commit 40420d900a1ca0fba4042883b25c39dcadefc596 Author: Ken Bowley Date: Fri Aug 17 05:46:24 2001 +0000 Initial revision diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..9cf718d8 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,31 @@ + MBSE BBS AUTHORS. + +All following people have contributed to the MBSE BBS project. I'm sure that +people are missing from this list. The list is not in any special order. + +Michiel Broek mbse@users.sourceforge.net 2:280/2802 +Joaquim Homrighausen joho@abs.lu +Andrew Milner andrew@fido.lu +Mats Wallin mw@fido.lu +Eugene G. Crosser crosser@average.org +Stanislav Voronyi stas@uanet.kharkov.ua +T. Tanaka +Martin Junius +Omen Technology Inc +Arjen G. Lentz +Cristof Meerwald +P. Saratxaga +Dima Maloff +Jan van de Werken +Sean Rima +Juergen Heisel +Jim Hansen +Ken Bowley +Redy Rodriguez 2:283/613.6 +Johannes Lundberg 2:206/149@fidonet, +Vincent Danen +Francois Thunus francois@telematique.org +Johan Lindh +William McBrine +Harald Wuensch +NERvOus nervous@nervous.it diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..e77696ae --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the 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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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/CRON.sh b/CRON.sh new file mode 100644 index 00000000..631538b7 --- /dev/null +++ b/CRON.sh @@ -0,0 +1,100 @@ +#!/bin/sh +# +# Crontab setup script for MBSE BBS +# +# (C) Michiel Broek, v0.06 06-Mar-2001 + +echo "MBSE BBS for Linux crontab setup. Checking your system..." + +# Basic checks. +if [ `whoami` != "mbse" ]; then +cat << EOF +*** Run $0 as "mbse" user only! *** + + Because the crontab for mbse must be changed, you must be mbse. + +*** SETUP aborted *** +EOF + exit 2 +fi + +if [ "$MBSE_ROOT" = "" ]; then + echo "*** The MBSE_ROOT variable doesn't exist ***" + echo "*** SETUP aborted ***" + exit 2 +fi + +if [ "`grep mbse: /etc/passwd`" = "" ]; then + echo "*** User 'mbse' does not exist on this system ***" + echo "*** SETUP aborted ***" + exit 2 +fi + +if [ "`crontab -l`" != "" ]; then + echo "*** User 'mbse' already has a crontab ***" + echo "*** SETUP aborted ***" + exit 2 +fi + +MHOME=$MBSE_ROOT + +clear +cat << EOF + Everything looks allright to install the default crontab now. + If you didn't install all bbs programs yet, you better hit + Control-C now and run this script when everything is installed. + If you insist on installing the crontab without the bbs is complete + you might get a lot of mail from cron complaining about errors. + + The default crontab will have entries for regular maintenance. + You need to add entries to start and stop polling fidonet uplinks. + There is a example at the bottom of the crontab which is commented + out of course. + + IMPORTANT: the first crontab entry is to set the Zone Mail Hour. + This entry is set for Holland, Amsterdam. ZMH is 02:30 - 03:30 UTC + for zone 2. CET is one hour plus in wintertime and two hours plus + in summertime. If you run "mbstat check" at each possible begin + and end of ZMH you must run it at 03:30, 04:30 and 05:30 local CET. + You must calculate and set the times for your own timezone and own + Fidonet Zone Mail Hour. + + On most systems you can edit the crontab by typing "crontab -e". + + Hit Return to continue or Control-C to abort. +EOF +read junk + +echo "Installing MBSE BBS crontab..." + +crontab - << EOF +#------------------------------------------------------------------------- +# +# Crontab for mbse bbs. +# +#------------------------------------------------------------------------- + +# User maintenance etc. Just do it sometime when it's quiet. +00 09 * * * $MHOME/etc/maint + +# Midnight event at 00:00. +00 00 * * * $MHOME/etc/midnight + +# Weekly event at Sunday 00:05. +05 00 * * 0 $MHOME/etc/weekly + +# Monthly event at the 1st day of the month at 00:10. +10 00 1 * * $MHOME/etc/monthly + +#----------------------------------------------------------------------------- +# +# From here you should enter your outgoing mailslots, when to send mail etc. + +# Mail slot example. +#00 02 * * * export MBSE_ROOT=$MHOME; \$MBSE_ROOT/bin/mbout poll f16.n2801.z2 -quiet +#00 03 * * * export MBSE_ROOT=$MHOME; \$MBSE_ROOT/bin/mbout stop f16.n2801.z2 -quiet + +EOF + +echo "Done." + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..c89e14f9 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,4062 @@ + MBSEBBS History. + + The good news is at the bottom :-) + +v0.00 Started work on the Rapidbbs sources to make new structures, + headerfiles and makefiles. + The whole thing will include Fidonet echomail and tic file processing. + +v0.01 Until v0.06 lots of sourcecode fixes, bugs removed which became + visible after writing the new header and makefiles. Included common + and jamapi libraries. The jamapi is not in use yet but will be the + final message base format. + + Rewritten the mbse deamon. This deamon monitors the bbs and all the + utilities. + + Written an import util to import textfiles from the databases exported + by a little Pascal program that exports the RA databases from the DOS + bbs. + + Started writing a new setup utility. While doing this the old config + program is being stripped down. + + Renamed the filelist program to allfiles. + +v0.06 In the internal mbsed server structure added information for user + online messages. Added ADIS:2,pid,flag; set users Do Not Disturb + flag, also changed the bbs to sent that flag. + + Added Status commands to the mbsed, test for BBS open, and Zone + Mail Hour. 2 new statements in etc/mbsed.conf. The mbsebbs now + tests at startup for ZMH and BBS open. If it is closed the user is + disconnected with the reason why. + +v0.07 The new structures are ready. The bbs can run with local mail only. + + Renamed the filepack program to mbfile, it will do a lot more later. + + Removed the whoson program, the functions are in the setup program now. + + Added in the setup program the oneliner editor, protocols editor, + language setup editor, limits editor. + The oneliner editor has an import facility to import plain textfiles + to add oneliners. + + Changed structures again, lastcaller and ttyinfo. + + Removed the usered program, the users editor is in setup now. + + Fixed the download (non batching) function DownloadB, it does work + more or less. Changed the calling program from execl() to system() + to fix the stack problems. Now need testing voor carrier loss and + timeouts. + + After testing with a DOS-PC (A real fast 286 10 MHz state of the art + of the eighties, directly connected to the tty port) the Good_Bye + function needed 5 seconds extra delay to be shure all data is + send to the user. Also the parent died too fast so the mbsed server + wasn't notified when the client was logged off. + + In the bbs chat.c added unlink the /tmp/.BusyChatting file so the + chat could be more than once in a session. + + In the internal mbsed server structure added information for user + online messages. Added ADIS:2,pid,flag; set users Do Not Disturb + flag, also changed the bbs to sent that flag. + + Added Status commands to the mbsed, test for BBS open, and Zone + Mail Hour. 2 new statements in etc/mbsed.conf. The mbsebbs now + tests at startup for ZMH and BBS open. If it is closed the user is + disconnected with the reason why. + +v0.08 Added the JAM c api. This is a modified version for Linux. + + Reading JAM messages and Quickscan JAM messages implemented. Removed + support for the old message base format. The function Msg_Post() does + not work anymore, must be rewritten to support JAM. + + In the msgpack program removed all code for the old message base + format. Inluded support for client/server. + + Removed all structures of the old message base format, the only + format left is JAM. + + +v0.09 22-Mar-1998. + In Language data compiler removed output to screen for each compiled + line. When finished compiling it reports the number of language lines. + + Changed the number of lines for the line editor in Post_Msg() and + Reply_Msg() in a #define statement. In the language source it still + allways says 60 lines. + + Bugfix in mbsetup: edit message area item 7 an 8 didn't work. + + Start writing of man pages. + + Start writing mbfido, the net- echomail tosser, scanner and packer. + Succeeded tossing echomail, no dupechecking, links checking or other + checks are done. No reply linking either. + + mbsetup: Added Fidonet aka setup. + + Moved JAM I/O functions to the common directory. + + Created the mbmon program out of mbsetup. Removed those items from + mbsetup. + + Start build of the dbase library, this library will contain functions + to access the configuration datafiles for all utilities except the + mbsetup program. + +v0.10 15-Apr-1998. + Allfiles changed to make use of the common and dbase libraries. Does + logging now of activities. Removed links to src/bbs/funcs4.c + + Added fileareas and filesdatabase import to the import program. + + Corrected file area mismatches in mbsebbs and fedit. + + Mbsetup: finished global setup. Fixed pull filegroup and messagegroup. + Added edit bbs file areas. Changed format of fareas.data. + + mbfido: Added first dupechecks, only logging. Fixed errors in dbase + search routines, caused mail to be tossed in the wrong directories. + Added tossing of bad (unknown areas) and dupe mail in the bad and + dupe boards. Checks for .PKT destination implemented. Ideas for + netmail tracking written. Dupe checking seems to work, but I can't + compare it with my other tosser yet. Note after more testing: + it's better than GEcho's 1.11+ dupechecking. + + allfiles: Opens header.txt now only before processing the areas. + Added footer.txt. Both files must be in the configfiles directory, + if they are not present, nothing will be inserted. Removed all code + that constantly opened and closed the output file. Added logging for + total processing time. Added new lines to the area headers. Areas + are only written if there are downloadable files in them. Download + counter now represents bbs downloads, ftp downloads and file requests. + The last two counters are not in use yet. + +v0.11 26-Apr-1998 + mbsebbs: In the mail reader swapped From and To language fields, the + names were in the right place. Added the nodenumber after the from + name. Must be set for messagearea type (Local/Net/Echo). + + mbfido: Corrected some loglevels. + + userpack: rewritten from scratch. Deletes unix accounts as well, uses + /usr/sbin/userdel to do this, so shadow support works just fine. + This program must be run as setuid root setgid root. + + structs.h: removed flags for Unixmode and all related flags. + + mbuseradd: written. This is a setuid root setgid root version of + adduser, this program is called by newuser to create the unix account + of a bbs user. It also creates the homedirectory, the .profile file + and expires the unix account password. When a new created unix user + logs in he will be prompted for a new password. + + newuser: lots of rewriting. Added inactivity timers. Now we have + always unix accounts and fido bbs accounts. It will also die + nicely when the user did hangup on us or waited for idle timeout. + + mbsebbs: Check for unix account, if it doesn't exist the user is + forced to create a unix account. If unix login we now have a pause() + at the same place the password prompt is so the user can see the + opening screen and read it. + Removed the code that there was a parent (guarding users logon time) + and a child process (running the user). There is only one process now. + Implemented keyboard input timers. The total onlinetime must be + guarded in another way now, ie. checking must be done at prompts. + In the mean time proper idletimeout, hangup and error conditions + will log the user off in a neat way and writing into the logs about + what happened is mostly solved. + + mbsebbs and newuser: New users can only be handled by the newuser + program. Listed users only by the mbsebbs program. You need 2 accounts + without a password for this. Maybe I'll chain these 2 programs later. + + misc: compiling is a mess again, more libraries are needed, time to + close this version. + +v0.12 07-May-1998. + mbsed: Rename the logfile from "mbsed" to "mbsed.log". The mbsed + logfile is opened and closed everytime now. Logfile cleanup utils + can now safely remove the logfile, make it smaller etc. + + mbsebbs: Splitted misc.c into bye.c, pinfo.c and misc.c + + dbase library: added userrecord search. Added netmailboard search. + + mbfido: removed segmentation fault caused by a too long kludge, added + a check for the stringlength (512 bytes). Removed bugs in netmail + destination tests. Implementation of ftn netmail import into JAM area. + Only the first netmail area is used, no need for several areas now. + + mbsebbs: Added aka display when reading netmail. Changed autowrap + to line 74. + Added test for users handle when scanning new mail. + Removed test tlcap() when comparing names. The tosser should correct + the names. + Changed the MsgSelectPrompt() to default return the lastread pointer + instead of message 1. + Changed Read_a_Message() so it will return TRUE if message read was ok, + FALSE otherwise. + CheckMail() now starts searching at the users lastread pointer. It + now also keeps track of messages to the user, and gives the option + to read them. Reply is not possible yet, but posting isn't working + also. + Added a check that the receivername must exist to prevent false new + mail. + Changed UserList() to skip the empty userbase records. + Place the users timecheck functions in a separate file, made it work + again. Inserted timecheck points at several prompts. + Changed the timebank to reflect new timecheck routine's. + Moved the exitinfo functions to a separate file, several other modules + now use new functions in this file instead of internal ones. + Changed FileArea_List() to work with options (F+ and F-) for direct + area change. + Improved the fatal menu error construction. The user now sees a message + and will logoff by SIGILL. + +v0.13 24-May-1998. + mbfido: + Added a debug line to show flagfield of the original packet. + Added code to fill the message header MsgIdCRC and ReplyCRC + fields. + Added version info in the logfile. + + mbsebbs: + Corrected unixmode login problem if there where more than one + field within the gecos field of the passwd file. + Added version info in the logfile. + Changed the setting of signal handlers, removed SIGINT, added + SIGILL. + Supress display goodby screen in case of a SIGHUP. + Display ttyinfo.comment instead if ttyname in connect info. + Added create/check for subdirectories wrk and tag in the users + homedirectory, wrk is for the users homedir fileoptions, tag + is where symlinks of tagged files area placed. + Corrected message diplayed to user when logging in during zone + mail hour. + Removed menu option GlobalDownload, see new feature below. + Implemented download file tagging in menus FileList and + NewFilesScan. + Implemented download tagged files, the old download function + is gone. + Moved Change_Protocol and Set_Protocol from file.c to change.c + where they belong. Change_Protocol is now Chg_Protocol as all + other functions in change.c use the same naming convention. + Made KeywordScan and FilenameScan working without coredumps, + implemented file tagging. + Made enum vars for WhosDoingWhat. + Changed the internal filearea record number, area 1 is now 1, + not 0. This should prevent a lot of bugs. + Now setting large timeouts on the client/server guard during + filetransfers to prevent server disconnection. Changed mbsed + and common.a for that. + Added logging info when user is kicked out if the BBS is + closed. + Split file.c into file.c and filesub.c + Added menu function 111, Copy file to home directory. + Download_Home, Delete_Home, List_Home, Upload_Home now all work + with the new directory structure. Upload and Download homedir + do not count uploaded/downloaded bytes, the user gets no ratio + bonus after upload, only the up/downloads are counted. + Quota check for users home directory. The value can be set + with the mbsetup program, value is MBytes. + Removed error message if user selected a menu option where he + has no access rights for. The user now sees nothing. If you + want to give a response, use the menu system! + Reset colors to lightgray on black after logoff. + Added menu function EditTaglist. + + mbsed: + Invented two new commands, ATIM:1,n; which set a new client/ + server timeout, and ADEF:0; which resets the client/server + timeout to 600 seconds. + + common.a: + Implemented the two new client/server commands: ATIM and ADEF. + + mbsetup: + In global BBS setup, added editing Users Quota. + + import: + In FDB import, changed the filenames to lowercase. + + allfiles: + Output list now contains CR/LF at the end of each line. + + mbuseradd: + Added the line "export TERM=pcansi" to the generated .profile + in the new users home directory. This seems to work quite well + for all kinds of clients. + + + +v0.14 02-Jun-1998. + msgpack: + Renamed to mbmsg, it will do more as just packing messages. + Implemented using the msgbase.a library: Purging (Days old + and Max msgs), Packing deleted messages and Reply linking. + During pack the messages are renumbered and lastread pointers + are adjusted. + + mbsetup: + Added edit messagebase storage type. + + msgbase.a: + New library, universal message base library, must support + JAMmb, Fido *.MSG, Passthru, Usenet news and E-Mail. + This came original from LoraBBS, written by Marco Maccaferri. + I changed the sources to normal C code without objects, that + was the fastest method to mix it with the existing sources. + I dropped support for Hudson and Squish. + Only JAM is supported for a start. + The JAM module renumbers the messages while packing. + Added support for lastread pointers. + Changed all msg handling so that the messagetext must contain + all the kludges to be compatible with several message bases. + This means that the JAM module now handles the kludges in the + text, storing and retrieving it between the *.jhr files and + text. This also means that the applications don't have to + worry about kludges. + + mbsebbs: + Changed mail.c to work with the new msgbase library, dropped + the old jamapi. Scanning new messages looks slower, maybe + the speed improvement must be made in the msbase library. + Applied all changes in the messagebase library to the bbs + program. + + mbfido: + Applied all changes in the messagbase library in the tosser + module. While doing that I saw some bugs but they don't + mather anymore. + + + +v0.15 13-Jun-1998. + msgbase.a: + Implemented msgbase locking for JAM messagebase. Dropped + future support for other messagebase formats, I stick to + JAM and only JAM, it can do all we need, including mailer + netmail directory. + Implemented all possible attributes in the interface. + + dbase.a: + Removed some bugs in dbmsgs.c + Added code to update the nodes and msgs data records if they + are changed. + During msgs record loading the group record will also be + loaded if it's defined. + Added support for .tic area lookup. + + mbmsg: + Implemented msgbase locking during msgbase updates. + Added colours. + + mbfido: + Implemented msgbase locking during msgbase updates. + Implemented simple echomail forwarding in the queue. + Splitted tosspkt.c into importmsg.c echoout.c and tosspkt.c + to make the source more readable. + Started collecting SEEN-BY and ^APATH information in memory. + Started appending SEEN-BY entries during echomail forward. + Added code which should append SEEN-BY and PATH lines in + outgoing echomail. + In the startup code changed the catching/ignoring of signals. + Activated mail send and received counters in the nodes + records. + Activated echomail received counters. + Started working on .tic file processing, using my own MBFIX + code (in Turbo Pascal) as a guide. + + mbsed: + Changed the server locking in a more portable and secure way. + Added sequencer counter for generating MSGID numbers and + message packet numbers. + Removed a bug in response strings when the BBS is closed. + The signal SIGTERM is now ignored, we wait for SIGKILL only + so we keep running as long as possible. + + mbmon: + Added support for sequence numbers display. + + mbsebbs: + Removed a bug in the syntax of BBS closed messages. + Added a toggle switch to display message kludges for the sysop. + Added hilite color for quoted message lines in message read. + + mbstat: + The BBS close command doesn't need a reason anymore. + Implemented the wait function. We only wait for users online + and utilities that we want to complete their actions. Depending + on the type of init program, if it uses shutdown scripts, you + can now wait for the system to become idle before the real + system shutdown starts. + + + common.a: + Added a flag "show_log" to the Syslog function to suppress + logging to the screen. + + mbsetup: + Added support to edit .tic areas. + Started working on the creation of a site document, this is + a complete overview of the whole setup. + + +v0.16 06-Jul-1998. + + General: + This version is the first version installed on the real BBS + server, line #2. While doing this I discovered lots of errors + in the Makefiles because I installed it from scratch. I also + found out that GEcho and or RA is screwing up some JAM bases + causing this program to dump core. Did some testing, download + and mail reading is ok. + + mbsebbs: + NewfilesScan and show files listings now work with the file + upload dates instead of the real filedates. + + mbfido: + It's possible to import .tic files into the bbs. + Unknown echomail areas now log with WriteError(). + Added functions to pack mail for downlinks and put it in + the mailer outbound. + Because of small diffrences between ifcico and DOS mailers + running 2 mailers together still doesn't work for attached + files and mail. + Fixed a bug in outbound mail packets, the packed messages + didn't start with 0x0002 so downlinks didn't process the + messages. Output of echomail works now! + When processing large amounts of .tic files, the processing + stopped after about 30 files. Added 2 forgotten fclose + statements. + Added sorting functions for filenames with date/time. All + inbound processing is now sorted by date and time, oldest + files first. + + common.a: + In mbfile.c changed file_cp() to copy file attributes as well. + + userpack: + Changed commandline syntax. + + mbmsg: + Changed commandline syntax. + + mbstat: + Changed commandline syntax. + Added colors. + Does timeout after one hour waiting for the BBS to become free. + + mbsetup: + Added setup for .tic magic records. + Improved logging reason when tossing messages not for us. + + dbase.a: + Remove a bug where reading downlinks from areas base gave + nothing. (Introduced in 0.15). + + mbmon: + Corrected the screen header. + + +v0.17 30-Jul-1998 + + mbfido: + When importing files to the BBS the destination directory + is checked and created if it doesn't exist. + Improved checks when to rearchive incoming files. + Forgot to chdir back to the inbound when rearc failed. + Switching virus check off when the inbound file isn't an + compressed archive. Should check incoming *.exe (selfextracting + archives). + Keep number of files now works. + TIC forwarding to downlinks implemented. There are 2 netmails + for each forwarded file, one for the file itself and one for + the .tic file. The subjectline is to short under Unix. The + second netmail is an empty one, lets see how this works. + Added cookies. + Packing ARCmail now checks for bundles older then 5 days and + creates new bundles if found. + Added netmail pack to ARCmail. + Improved errorlogging again when tossing bad echomail. + Scan for outgoing echomail from the bbs is working. It is a + complete messagebase scan for now. + TIC forwarding again with one netmail, I faked the subject + line, all files seem to come from C:\FILES\. This seems to + give no problems with the other end of the link. + + mbmsg: + Improved debug logging. + Processing in only one area didn't work anymore. + + mbsebbs: + Made post new message work. + Now unlocking and closeing the messagebase after a crash. + Moved the lineeditor to a seperate source module. + Reply to messages is working, also from scan for new mail. + Comment to sysop now works. + Removed the Voting door. + + +v0.18 10-Aug-1998. + + general: + New record structure for fidonet networks. This makes + it possible to use the same nodelist indexes as ifmail. + Note that de define -DHAS_NDBM_H may only be set if you + have done this also in the ifmail package! This is set + in ~/src/mbfido/Makefile + + run_inout: + A shell script run from the mbse crontab (every minute) to + see if there is something to do. It scan's the protected + inbound and scan's for the ~/sema/mailout semafore. + + mbsebbs: + Creates a ~/sema/mailout semafore if mail is entered. + Added extra debug logging during newmail scan. On the live + bbs mbsebbs keeps on dumping core probably due to RA or GEcho. + Most amusing is that after crashing mbsebbs, RA will see new + netmail again, as if only mbsebbs knows how to handle the + users lastread pointers and fixes them for RA; sigh. + + mbfido: + Start working on the netmail tracker/router. It works without + an external routing file, although hosts will need one. + It works on checking known nodes, then nodelists, and then + known nodes again. This is very experimental. + + mbsetup: + Changed to the new fidonet structures. + + import: + Changed to the new fidonet structures. + + general: + Installed at 13-Aug-1998 at the BBS for testing. + + +v0.19 14-Aug-1998 + + general: + Wrote some documentation about how to setup the ftp server + so that it works together with MBSE BBS. + + mbsebbs: + After download the message "updating download counters" now + will first send a to overwrite the zmodem init string + on the users screen. + Added structures for bluewave. + Now scans for new files at logon. + Removed global variable sUserName, gave some strange results. + Added logging which msg area was active when a segmentation + fault occurs. + + script: + A new subdirectory for /bin/sh scripts. Look out with this + one, if you modify the scripts in ~/etc or ~/bin directly + they will be overwritten with each new install. + + mbuseradd: + Add each new user to /etc/ftpusers to prevent them to login + under their own name in the ftp server. + + fbgen: + Setting umask to 002. + + fileedit: + Removed, was obsolete. + + import: + Setting umask to 007. + + common.a: + mkdirs now creates directories with permission 0775. + Added dos<->unix filenames translation. + Rewrote tu() and tl() functions. + + mbfile: + Setting umask to 002. + Now checks for files on disk, but missing in the fdb. Deletes + them when found (exept some). + Now when packing the fdb records marked for deletion, also + if the file is on disk, it is deleted. + Added some commands to the todo list. + With the check command it now reports the area number to the + mbsed server, so mbmon will display how far it is. This will + also avoid timeouts on large areas. + Now handles multiple commands in one run. Pack will run + automatic if there are files deleted. + + mbfido: + Set a semafore "msglink" when the message base is modified. + Added more debug logging for files descriptions. + Implemented dos<->unix filename translation for tic file + forward. + File attaches in .flo files now are DOS filenames and .flo + files are now DOS-compatible. + If there are no more then 2 Long Description lines we asume + that there is a better single (old style) Description line. + There are uplinks that make a mess of these lines. + Netmail forwarding should work now as long as the nodes via + we must route are in our setup. + + mbsed: + Added in wait for free the mbindex and mbuser programs. + + mbindex: + Written. Heavlily based on Eugene Crosser's ifindex. + + mbsetup: + Written the menu editor and removed the old mbconfig program. + Added some editor commands to the user editor. + + mbuser: + Now leaves the records alone with the NeverDelete flag set. + + mbmsg: + Added logging when a segmentation fault occurs which was the + last message area. + + +v0.20 24-Aug-1998 + + common.a: + Moved from mbfido the modules ftn, falists, nlindex and + nodelist to this library. More programs will need it. + + mbindex: + Changed some loglevels. Removed the -force switch, compile + is always forced now. + Removed a bug to the path of the index files. + + import: + Now using dos2unix pathname translation for fileareas and + mailareas import. + + mbfido: + Changed some logging. Removed ftn, falists, nlindex and + nodelist modules, they are now in the common library. + + +v0.21 25-Aug-1998 + + mbindex: + Trashed the index files when a new nodelist in the setup + was added. (ifindex did this also). Now it will allways + force to recreate the index files. + Now sends username who started mbindex to mbsed. + + mbfido: + Imported files into bbs areas now get filemode 0644 instead + of 0660 so the ftp/www clients will really see them. + Corrected the experimental replace test, could never work. + If after trigger the compile nodelist flag there came in + another file, the flag was reset. + Now sends username who started mbfido to mbsed. + + mbsebbs: + Created a language crossreference listing. Corrected some + language numbers. + After changing the language, it is now confirmed in the + new selected language. + When the language file is missing, the error message no longer + comes from the missing language file, now it is hardcoded. + Minimum location length is now adjustable with mbsetup, + changed language prompt 74. + Replaced hardcoded messages in chat with language prompts + 59 and 60. + Changed error logging in exitinfo.c + When reading messages the more prompt is now language prompt + 61 instead of hardcoded. + Posting messages is now blocked for Noreply boards. Language + prompt 438. + In message readpanel now language prompts 211 and 212 for + Next reply: and Reply to: threads. + In message area select now using prompt 207. + In newmailscan, added prompt 218 and the Quit option. + In message status, added prompt 226. + Readpanel, added prompt 227. + Delete specific message subfunction does work now. + In display file with more, changed prompt 72. + Changed prompts in file.c and filesub.c. + The info screen is 1 character smaller, 79 characters, some + terminal programs did extra line wrapping. + Added new language file format, the datafile now includes + the keys users can press. + Moved the loading of user's preffered language more to the + begin of the login procedure. + When the user is unknown (ordinary BBS account), the newuser + programm is started. If that runs successfull (depends on the + user on-line), mbsebbs will be run again. It's probably wise + to merge these 2 programs. + + mbsetup: + Minimum location length installed in menu 1.5 + + allfiles: + Now sends username who started allfiles to mbsed. + + mbfile: + Now sends username who started mbfile to mbsed. + + mbmsg: + Now sends username who started mbmsg to mbsed. + + mbstat: + Now sends username who started mbstat to mbsed. + + mbuser: + Now sends username who started mbuser to mbsed. + Did leave the users.data file owned by root. It is now + set to the owner and group of the "mbse" account. + Added screen output for non-quiet mode. + + lang: + Changed to compile new language datafile format, including + the keys a user can press. + + newuser: + Added new language file format, the datafile now includes + the keys users can press. + Now always asks Date of Birth, this is necessary for later + checks. + At the end now engages mbsebbs. + + mbuseradd: + Now uses the created gid and uid voor changing ownership + of files and directories. + + +v0.22 06-Sep-1998 + + mbsetup: + Changed logfile to one master logfile. + Added menus for offline reader. + + allfiles: + Changed logfile to one master logfile. + + mbsebbs: + Changed logfile to one master logfile. + Started offline reader. + + mbfile: + Changed logfile to one master logfile. + Corrected creating full path/filename in pack files. + Added creating and removing symlinks for file requests. + Now deletes files during "kill" instead of only marking. + Simplified log messages. + Added commandline switch "req", this will only check the + file request symlinks. + + mbmsg: + Changed logfile to one master logfile. + + fbgen: + Changed logfile to one master logfile. + + newuser: + Changed logfile to one master logfile. + + mbuser: + Changed logfile to one master logfile. + + mbstat: + Changed logfile to one master logfile. + + mbindex: + Changed logfile to one master logfile. + + mbfido: + Changed logfile to one master logfile. + Added creating and deleting of symlinks for file requests. + Files removed from the filedatabase when running "keep files" + are now also removed from disk. + Removed some debug logging for netmail forwarding. It seems + to work. + Replace files now works more or less. Moved the fdb packer. + + mbindex: + Only logs crash cause if errorlevel > 0. + Removed some invisible screen output in quiet mode. Cron did + notice this. + + lang: + Renamed to mblang, also the source directory is now mblang. + The directory lang will now be used for language sources. + + +v0.23 20-Sep-1998. + + global: + Added #pragma pack(1) to ~/src/include/libs.h so that all + datafiles are now compatible over several hard and software + platforms. I needed this to implement the BlueWave Offline + Reader into the bbs. Increased the QWK tagname field to 20 + characters. + + mbsebbs: + Made menu execution logging more readable. + If a user has no archiver set, set default to ZIP at logon. + Changed logging in the Download Direct command. + Implemented first raw version of BlueWave Offline Reader. + Needs some security improvements, file requesting, filters + but it works for now. + Checking for a Unix account was done before the password was + checked, so if the password was wrong the user was asked for + a new Unix account again. + + mbfido: + For netmail import now searches the netmail area on zone:net + match. + + import: + Removed bugs when converting DOS to Unix paths which resulted + in corrupted pathnames. + + mbsetup: + Corrected linefeed problem in language doc printing. + Horizontal line drawing now with low-ASCII instead of Alternate + Character Set. + + mbmon: + Horizontal line drawing now with low-ASCII instead of Alternate + Character Set. + Corrected a color problem in View BBS Information, and added + display BBS startdate. + + +v0.24 30-Sep-1998. + + structs.h: + New fields in config.data: OLR_MaxMsgs, OLR_NewFileLimit, + OLR_MaxFreq. + New fields in mareas.data: OLR_Default, OLR_Forced. + New fields in ttys.data: honor_zmh. + Added Areafilename field to group records. + + mbsebbs: + Combined some functions from offline.c and mail.c into + msgutil.c + Messages posted with a OLR are now counted in the users record. + Closeing the bbs during Zone Mail Hour can now be set for each + individual line. + Now counting and marking the date/time when posting messages + in mareas.data. + + mbsetup: + Corrected some sitedoc problems in global setup. + Added sitedoc printing for mail setup. + Added file and mailgroups setup to the nodes setup. + Added newfiles reports setup. + Added filefind areas setup. + + mbfile: + Corrected spelling error. + + mbaff: + New program. Announce new files and FileFind (Allfix). + + mbfido: + In .tic file processing if we were a pointaddress, the path + checking always gave an error. The check of our boss is + skipped now. + The correct .tic area and filedate is now set in the toberep + database. + + mbmsg: + Improved initialisation. + + +v0.25/a 12-Oct-1998. + + general: + From now on version numbering will get /a (Alpha), /b (Beta) + and /g (Gamma) release extensions. This is necessary for + live testing at my bbs. + + mbfido: + The Cost field in the toberep.data file was not set. + + msgbase.a: + Added extra screen output in certain error conditions. + Added a trick to generate a FromAddress from the Msgid + in case there is no FromAddress. This was left blank by + GEcho 1.11+ (DOS). + + mbaff: + Added some IsDoing information for the monitor. + Setting ReplyCRC to -1 instead of 0 if it's an original + message. + Minimum searchstring length is now 3 characters (hardcoded). + Added a check to see if there is a FromAddress and a Subject + before a message is added to the scanlist. + + mbsebbs: + Corrected spelling error in OLR download logging. + + mbsetup: + Changed some page layouts in the sitedocs, added some + forgotten formfeeds. + + +v0.25/b 14-Oct-1998. + + mbfido: + If the tic queue directory didn't exist, it is now created. + Netmail messages now have zone:net aka matching on the + destination and from addresses. + Started with the AreaMgr and FileMgr functions. It can respond + to %help. + Added the notify function. + + mbsetup: + When picking a mailgroup in messages setup or a filegroup + in ticsetup, the ftn aka is copied from the group setup as + a default aka for that area. + When setting the area tag and if the OLR tagname is empty, the + area tag is copied there as a default. + + +v0.26/a 17-Oct-1998. + + general: + In some databases in the header there is now a time_t field + added. This is to mark the last statistics counters rollover. + Programs that count statistics must perform an rollover when + it's run on a new day, week or month. + + warning: + To upgrade the databases, enter the setup for message areas, + tic areas, nodes, file groups and message groups and save + the databases. + + mbfido: + Implemented new statistic counters. + Implemented rollover of the statistic counters every week and + new month. + Changed program locking, now it locks the whole program in + stead of short moments. + + mbsebbs: + Implemented new statistic counters. + + mbaff: + It now counts the posted messages in the message area. + Corrected the announce message text. + + +v0.26/b 20-Oct-1998 + + mbsetup: + Wrote the hatch manager. All basic functions are present now. + All databases that can be packed after deleting records can + do this now. During update those databases area sorted. This + is not for the message areas, files areas and the userbase. + These files may not be packed. + + + +v0.27/a 29-Oct-1998 + + general: + Changed the database format for the files. Added support for + long filenames. The .tic file area is also stored in the + records to make the rescan function work later. + The files database must be rebuild for this release!!! + The BBS and the rest of the programs now use different + loglevels. + Changed the sourcefile distribution name to mbseN_NN.tgz. + + upgrade: + Delete all file databases! + mbsetup 1-5-20: set utils loglevel. + run mbfile check -debug to fix the files references. + + dbase.a: + Functions added to connect and disconnect nodes from echimail + and file areas. + Now marking the nodes record invalid after update. This should + prevent corrupting the nodes.data file from now on. + + common.a: + Added a function to convert ifcico addresses to internal fido + addresses. + Removed a pointer bug in the aka2str function. + + mbfido: + Added most AreaMgr and FileMgr functions. Needs a lot of + code cleanup but most things work for now. + Now imports the TIC area name in the filedatabase. This can + later be used for %resend requests. + The long filename field is filled with the dos filename for the + time being. + + +v0.27/b 04-Nov-1998 + + general: + Changed the top Makefile, it "forgot" the script directory. + This release adds nodelist diff processing and hatching of + new files, for example the nodelist you just created. + Switched to compiling with ndbm.h, this is now default + because the nodelist can now be opened by several programs + at the same time (for reading). Support for dbm.h will be + dropped, it gives trouble and cannot be used on a multiline + system. + Created the semafore.doc document for semafore handling. + + common.a: + Added the semafore functions. + + import: + Implemented long filenames on files database import. + + + mbfido: + Changed the way of counting FILE_ID.DIZ lines in archives. + Made macro's in tic processing case insensitive. + Implemeted automatic hatching of files. + Creates the "mbindex" semafore when new nodelists have been + put in place. + + mbuseradd: + Changed the contents of users .profile to: + . $MBSE_ROOT/etc/profile + The file $MBSE_ROOT/etc/profile contains the global startup + commands for normal bbs users. + + + mbsebbs: + Changed debug logging of DisplayFile function. + Logs the tty line comment after the username at login. + Linked with the new common/semafore functions. + + mbdiff: + New program. Nodelist diff processor. Creates the "mailin" + semafore when it created a zipped nodelist. + + mbsetup: + Added tic echo group pick in hatch and magic setup. + Removed setup of semafore path's, they are now hardcoded. + + mbcico: + A quick hack of Eugene G. Crosser's ifcico. At this time + only the logging functions using mbsed are implemented. + It needs ~/etc/mbcico.conf for configuration together with + the standard database configuration. In time, the mbcico.conf + file will not be needed anymore. For testing in this release + it does the job. + + mbaff: + Linked with the new common/semafore functions. + Creates also the msglink semafore when mail is written. + + mbindex: + Removes the "mbindex" semafore when the nodelists are + successfull compiled. During compiling it places the + "compiling" semafore. + + mbmsg: + Removes the "msglink" semafore when the messagebases are + linked. + + mbstat: + Now maintains the semafore's "bbsopen", "bbsclosed", "zmh" and + "scanout" according to semafore.doc. You must schedule + "mbstat check" in the crontan at the start op ZMH and end of + ZMH both on summer and wintertime. If you did configure the + ZMH right in UTC in $MBSE_ROOT/etc/mbsed.conf this will work + if you did setup your timezone correctly. + + + +v0.28/a 18-Nov-1998. + + general: + Modified the structs files to add a database for modems, + changed the tty database to link it with the modems, added + fields in the nodes database for the mailer, added fields + in the global config file to add setup for the mailer. + Dropped nodelist V21 flag, added V32T and VFC flags. The + U flags for modem capabilities must be implemented somehow. + + upgrade: + To upgrade, enter the global setup and leave it, say yes to + save changes. Enter the nodes setup, enter one of the nodes + record, exit and save changes. Setup the modems database. + Enter the tty ports setup, link the modems to the POTS and + ISDN lines and save it. + + common.a: + In crc added crc16ccitt functions. + In clcomm the function IsDoing(char *) now accepts formatted + parameters. + Added function SetTTY(char *). + Added debug logging of nodelist flags. + Changed the way the nodelist flags are parsed, sometimes + U flags became standard flags, and standard flags became U + flags. 'U' became a flag also. + Moved some common files from mbcico and mbfido into the + library. + + mbsetup: + Changed the lineeditor to accept the comma character. + Added modem setup, changed tty lines setup to pick a modem. + Changed nodes setup, finally added the statistics screen. + Changed fidonet setup, first zone is now called "primary zone" + + mbfido: + Added IsDoing info during date rollover. + Removed a bug causing a segmentation fault when a mail packet + had an error. + Removed check that incoming packets must come from a node in + our setup. All received mail packets are now processed. + Echomail must still come from nodes in our setup, the rest goes + to /dev/null + Moved some sources to the common library. + In forward() changed the uppercase functions for the subject + line. The original filename became uppercase also. + Corrected debug logging for packet date, the month was 0-11 in + stead of 1-12. + Added logging for ftsc product name and version. + + mbcico: + Added some EMSI extra logging. + Added more IsDoing info for mbmon. + Corrected the Makefile after testinstall on the live bbs. + Changed the order of the EMSI data to send to the remote + party to be more standard. McMail (maybe others too) didn't + recognize all options send too early. + Added EMSI logging for 'link', 'comp' and 'tranx'. + Moved some sources to the common library. + Completely rewritten the chat module. Everything received + from the modem is now logged. Because all modem responses + including echo from commands, are now logged, the aftercall + function (get modem aftercall or caller id), will go to the + logfile as well. (not tested, I have no CLIP capable modem). + Added patches from ifcico-3.0.cm.alpha-4.0 to filelist.c, + this should better handle files sent/notsent in failed + sessions. + Added counters for sent and received bytes. + Completely rewritten the scanout function. It now searches + only in the outbound directories defined in the setup. + In the fidonet networks of the setup the first defined zone + is the default zone for that domain. Other zones get a hex + extensions with zone number. + Scanning mail for the CallAll option now selects outside ZMH + only crash mail, during ZMH crash and normal mail. Logging + of selecting mail is improved. + When calling a node is failed for 30 attempts, the node will + not be called anymore. If the problem if corrected you now + must manually edit the .sts file or delete it to call that + node again. (Option for the future outbound manager). I think + that sessions errors do this after 3 attempts. + When calling a node, mbcico more ore less automatic selects + a tty with modem that matches the nodelist entries of the + node to call. ISDN is not yet supported. Also a best speed + test must set priority of ports to use. + + mbmsg: + Supressed error message if there was no semafore "msglink" + to remove. + + mbsed: + Added command SZMH, requesting Zone Mail Hour status. + Added command ATTY, setting a new tty port. + + mbdiff: + Removed some unnecessary debug log information. This program + seems to work fine now. (Wow, only needed 2 releases for + this one). + + +v0.28/b 09-Dec-1998 + + general: + Added structure for the mailer history file. + + mbaff: + Removed some debugging logmessages. + + mbsebbs: + Removed some debugging logmessages for newmail scan. + Removed some debugging logmessages from timer functions. + + mbmsg: + Added program info logline. + + mbcico: + Added monitor info during FTS-0001 sessions. + + mbout: + New program, the Outbound Manager, many ideas stolen from other + programs of the ifmail package. + + + +v0.29/a 11-Dec-1998 + + common.a: + Opening of nodelists is now logged at debug level. + Added .pol files to pktname.c + Moved attach.c from mbfido to common library. + Nodelock now tests for own locks, if so, no error is given. + + mbfido: + Worked on the uppercase bug again. It will only happen when + we must forward a file. + Moved attach.c to the common library. + + mbout: + Implemented file requests. + Implemented creating and removing of .pol files to make and + remove polls. + + mbcico: + Calls nodes when .pol file is present. + Made file requests working again, the .req files where not + added to the filelist to send. + When reading node options the NoEMSI and NoWazoo flags weren't + copied to the options. + Corrected a bug in yoohoo.c where it didn't initialize + remote->addr->name to NULL in checkhello(), this caused + a segmentation error and failing Yoohoo/2U2 sessions. Note + that this error is in ifcico as well. + Over TCP/IP with ifcico as other mailer EMSI, Yoohoo/2U2 and + FTS-0001 in- and outbound sessions are working. For other + mailers we will see if it will work in real live. + + +v0.29/b 17-Dec-1998. + + general: + Installed 0.29/alpha on the bbs. + Installed usleep() code in some utils. See usleep.doc for + details. + Changed the nodelist flag definitions to prevent conflicts + with system macro's. + + common.a: + Locking and unlocking nodes gives better error logging. It + now also checks our own pid if the lock was already made + instead of complaining. + + mbfido: + Removed some bugs in logging in magic.c + Changed FILE_ID.DIZ file checking for empty lines. + Now always marks a file announced when importing into the bbs. + Added code to prevent terminal output in quiet mode. + Added usleep() code in statistics rollover. + Added usleep() code in importmsg. (sleep each message). + Added usleep() code in LoadTic. (sleep each .tic file). + Added usleep() code in scan for mail. + Removed error message when "mailout" semafore didn't exist + in scan for mail. + + mbcico: + During outbound EMSI session we send the NRQ option flag, + requests on hold for us are not allowed when we callout. + When calling a node the first thing now is lock the node + to prevent further checking if the node is already locked. + Putstatus is logged for studying status updates. + Experimental status resetting of all nodes after successfull + session. + + mball: + Renamed from allfiles. + Now creates allfiles and newfiles reports. Honors maximum + security level to include in the lists (no flags yet). + Optional parameter -zip will create allfiles.zip and + newfiles.zip. + Installed usleep() code. + It is finished. + + mbout: + No more error message when a file attach in a .flo file is + nolonger on disk. This can happen if nodes don't poll often + enough. + + mbmsg: + Installed usleep() code. + Removed color code output when in quiet mode. + + mbaff: + Installed usleep() code. + Now marks the file announced after scanning the bbs for + uploads. + + mbfile: + Added the usleep() code. + Added some code to lower the disk i/o. + + mbstat: + Now logs status of ZMH with the "check" command. + + mbuseradd: + Added a check to see if the "shadow password suite" is + installed. It is absolutely necessary to have this. + If /etc/login.defs is present, the useradd program gets an + extra parameter "-M", to override the creating of the users + home directory. (Found on Redhat 5.1). + Added an extra check if reading the /etc/passwd file failed. + Added newline characters after some error messages. + + +v0.29/b2 24-Dec-1998 + + general: + Added modem.stripdash and ttyinfo.portspeed in structs.h + + common.a: + Changed logging functions in clcomm.c, repeated messages are + now counted and reported how many there were. A full filesystem + will hopefully not happen anymore. + Added the Nopper function, this one can be called often but + only once a minute a NOP is send to the server to prevent a + timeout disconnect. + + mbcico: + Removed some debugging logs. Added some return codes from the + tty drivers in zmodem send and receive. (removed later, it + didn't work). + Added Nopper code in file transfer protocols. + + mbout: + When creating a poll the node's status record is reset, so if + the node was undiable, it will start polling again. This will + not happen for sessions handshake errors and port errors. + + mbsetup: + In edit tty added edit portspeed. + In edit modem added edit stripdash. + + mbsed: + Corrected ZMH status response. + + mbstat: + Corrected ZMH status check. + + +v0.29/b3 28-Dec-1998. + + mbcico: + Inserted new ttyio code from the German version made by + P. Saratxaga and T. Tanaka. I hope the Zmodem problems will + now be solved. + Added Hydra filetransfer protocol. + Removed Janus, it wasn't implemented anyway. + Corrected modem init routine. + Implemented aftercall function. + + mbsetup: + Removed setup to disable Janus protocol. + + +v0.29/b4 29-Dec-1998. + + general: + Changed the Makefiles. Now only in ~/src/CONFIG you can place + extra defines. + Added compile switches -Wshadow -Wwrite-strings + -Wstrict-prototypes. This gave a lot of code cleanup, maybe some + strange errors are gone. + + common.a: + Corrected the repeative log counter. + Included in nlindex.c HAS_BSD_DB + + mbcico: + Improved ttyio logging, maybe we can better see what is going + wrong when transfering files. + EMSI compatibility protocol now gives Hydra first, then Direct + Zap. + Added file transfer counters to Hydra. Changed Hydra logging + a bit. + + mbindex: + Changed nodebld.c to inlcude HAS_BSD_DB + + mbuser: + Did some screen output when it was in quiet moded. + + +v0.30/a 01-Jan-1999. + + mbfido: + Removed a bug in the program lock that could cause a segfault. + In delete viruswork made rm now work in forced mode. + Hatch files now logs only hatched files. Added the + statistics update. + Changed completly the call module. There were some locking + problems and modem access attempts when the port was closed. + In Hydra the transfercounters are now updated after each + succesfull block. + Added more debugging log to the ttyio driver. + In answer mode we grep the environment variables CONNECT + and CALLER_ID created by mgetty and make log entries. + Swapped timer numbers in Hydra, in tty_write we now don't + test the read timer anymore, this gave unexpected timeouts + and is not according the Hydra specs. + Changed more debugging in ttyio, zmodem and zedzap are still + not working well. + Undiable nodes will not be added to the callist anymore. + + mbsed: + Added some logging in the ZMH status check to see what goes + wrong with asking ZMH status. + Changed the statusfile locking, now the lock tests are done + at 100 mSec intervals instead of 1 Second. + + mbsebbs: + Added CONNECT and CALLER_ID environment variables logging. + + newuser: + Added CONNECT and CALLER_ID environment variables logging. + + +v0.30/b1 10-Jan-1999. + + common.a: + Removed a bug in client.c that caused a segmentation fault + when the connected tty was /dev/console. It is now possible + to run clients from sysv init during system boot. + + mbsed: + Removed a bug in the ZMH status function. + Changed statusfile lock form 15 x 100 mSec to 10 x 250 mSec. + + +v0.30/b2 16-Jan-1999. + + general: + Defined bitmasks for logging. There are now maximum 26 debug + logflags. The logflags are changed from int to long. + All programs have been changed to use these flags now. + + upgrade: + In mbsetup set the new flags in menu 1.5.19 1.5.20 and 1.18.1 + + note: + This version still only compiles on Slackware 3.2 maybe + others, but not on RedHat 5.1 5.2 and RedHat 5.2 Sparc. + + +v0.31/a 23-Jan-1999. + + update: + Recompile the nodelists. Remove old index.dir and index.pag + files from the nodelist directory. + Set new value for dialdelay. + + general: + Removed mbsed from this source tree. From now on this will + be distributed as a seperate archive. + Finally found out why this package wouldn't work with glibc. + Complete rewrite of the nodelist indexes. I don't use any + dbm, ndbm anymore. I wanted username lookup included and + full support for ISDN and TCP/IP only nodes. + It now compiles on RedHat 5.2 Sparc and Intel. + + common.a: + Removed a serious memory leak causing the system to exhaust + all available memory during long filetransfer sessions. + Rewrote the nodelist lookup functions. Search is very fast + because the index file is sorted on nodenumber. + The nodelists will be closed after each lookup so that mbindex + may always compile new indexes. + + mbcico: + In call.c changed the port closing, it will now also close the + port after an unsuccessfull call so multiple calls in one + run will now hopefully work. + Removed a bug when calling a TCP/IP node it was trying to + dial with a modem. + Added random number generator to set the dialdelay before a + call is made. + + mbindex: + Total rewrite for the new nodelist indexes. In -quiet mode + it does the usleep(1) call every 80 lines (if set). Note + that in quiet mode it still runs faster then with screen + output. + The index file is sorted before it is written to disk. This + makes node lookup very fast (faster then with ndbm). + The old files stay on disk in case they are open, which can + only be for less then a second. + The semafore compile is not created anymore, instead the + mbindex program creates a lockfile to prevent that another + mbindex can run. Compiling the nodelists can now be done at + any moment. + Username indexes are not supported at this moment. + + mbstat: + Now only changes ZMH status if the status is really changed. + Will create the "scanout" semafore if ZMH status changes (I + did document it). + + mbmsg: + Changed the logging, killing messages now logs in columns, so + you can easy see how the mailflow and killing develops. + Removed some debug logging (finally). + When screen output is on, the last line is now erased after + processing. + + mbsetup: + Changed helptekst for mailer->dialdelay. + + mball: + Now creates semafore "mailin" when ready so the produced + allfiles and newfiles listings will be imported by mbfido tic. + + mbsed: + Changed the $MBSE_ROOT/sta directory to $MBSE_ROOT/var and + changed the names of the status and reginfo files. + +v0.31/b 06-Feb-1999 + + common.a: + Changed raw keyboard read to get cursor movement keys and other + gray keyboard keys. Only cursor movements is guaranteed to work + This is a limitation of PC-ANSI clients. + This change is needed to write the fullscreen editor. + Removed memory leaks from getheader.c and mbfile.c + Switched to one single .h file. + If loggin "message repeated n times" the first character is now + uppercase as in normal logmessages. + + mbsebbs: + Implemented raw keyboard read changes. + All actions in change.c are now logged. + Made change voice and data phone work. + Removed the (dangerous) gets function from funcs.c + + mbsetup: + Removed ncurses code. + In line editor the delete and insert key is finally working. + Modified help tekst for modem hangup string. + + mbmon: + Removed ncurses code. + In line editor the delete and insert key is finally working. + + mbcico: + If modem hangup string is empty only DTR-drop will be used + to hangup the modem line. + During ZMH mbcico will now only call nodes for which it has + non archived mail (netmail). + Changed ttyio debug logs, could block the session. + For magic file and execute requests now looks for both upper- + and lowercase matches. + Filerequests are searched in the internal database on both + long and short filenames, password protection is supported, + and the request counter in the FDB is updated. + + mbindex: + Doesn't complain anymore when the semafore "mbindex" didn't + exist when it tried to remove it. + Now tests for latest nodelist by filedate instead of file + extension number. + + mbfido: + Creates magic file names for magic filerequests. + + + +v0.32/a 16-Feb-1999 + + update: + Remove symlink directories. + + general: + Changed elapsed time logging, now ranges from seconds to + days with the same stringlength. + Moved signal names to common.a, also included the names + for i386 and Sparc systems. + Added PackNetmail flag to nodes record. + + msgbase.a: + Removed automatic adding of FMPT and TOPT kludges in netmail. + Applications are responsible for adding kludges. + + mbfile: + Removed code to work on symlinks for ifcico file requests. + + mbfido: + Added some code to prevent memory leaks. + The .pkt password check now always logs bad passwords, only + when mail password check is set, bad passwords are fatal. + Added code to keep dupe databases in maximum limits. + Now forcing chdir to inbound before processing each .tic file. + It will now export netmail from the message base. It also + supports packed und unpacked netmail. + Added TZUTC kludge (FSP-1001). + + mbcico: + Changed zmrecv debug logging for hanging session with one + of my links using InterMail 2.50 ML, rev B020. + If polling all lines of a multiline node and the first line + was successfull, mbcico would still poll the other lines. + The random dialdelay is now always 10 seconds or more to give + mgetty the chance to reset the modem and takeover the line + between multiple calls. + During dialdelay the IsDoing status is now sent every second + to the mbsed so you can watch it with mbmon. + + mbsetup: + Changed nodes setup so that password may be upper or lowercase + for remotes that are case sensitive (was always uppercase). + Added support for PackNetmail flags in nodes editor. + + scripts: + In run_inout added the news gateway (echomail => news). + + mbindex: + Now only tries to compile files with a numeric extension, + 2 or 3 digits length. + + mbsebbs: + Wrote a simple fullscreen message editor, more or less + Wordstar compatible. + Fixed a small problem in the line editor. + The maximum size of a message is now 500 lines. + When replying to a message, the original message is quoted + into the textbuffer including an introduction line. + When replying to a message, "Re: " is inserted in the + subject if there was none. + It is now possible to send and reply netmails. + Added TZUTC kludge (FSP-1001). + + mbout: + With poll and stop command you can enter multiple nodes. + With the request command you can enter multiple files. + The request command doesn't create a .flo file anymore, the + actual calling of the node must be done with the poll + command. + + mbaff: + Added TZUTC kludge (FSP-1001). + + mbsed: + Implemented CIPM and CSPM commands (online messages between + users). Updated the programnames list for check if the bbs + is idle. Changed the reginfo file lock to 30 x 150 mSec. + Fixed the Linux Sparc version. + + +v0.32/b 15-Mar-1999 + + upgrade: + Delete the newuser program and any accounts using it. + Move compiled language datafiles to ~/etc. + Move config.data from ~ to ~/etc. + Remove ~/lang directory + chown -R mbse.bbs ~/home/* + Upgrade mbsed to at least v0.32 Alpha. + + general: + The mbsebbs program now runs setuid "mbse" setgid "bbs". + All files are now owned by mbse.bbs, even the bbs users + private files. + All references to directories for the configuration are now + hardcoded to ~/etc, ~/fdb, ~/log, ~/tmp and ~/var. + The directory ~/lang is no longer needed. + The directory /tmp is no longer used, using ~/tmp instead. + Moved the language sources and installation into this source + tree. + + mbfido: + Forgot to append after the TZUTC kludge. + If we were a point, a route to our boss was not found. + Updated for hardcoded paths. + + mbsebbs: + Now runs setuid "mbse" and setgid "bbs". Changed the parameters + to the mbuseradd program. The newuser program is now part of + mbsebbs. + It is now possible to run mbsebbs as a shell, it is even wise + to do so! + Updated for hardcoded paths. + Sending and receiving online messages is now handled thru + mbsed. You need at least mbsed v0.32 Alpha. + Removed the last "gets" function. + + newuser: + No longer exists. + + mbuseradd: + Changed parameters to this program. + Finally worked around the problem of different passwd programs, + we will now let the user supply a new password instead of + creating an empty expired password. The shadow password suite + isn't necessary anymore but it may be wise to use it. + It will not install /bin/bash as user shell anymore, during + loading of the bbs users could get a shell prompt if they were + fast enough. The mbsebbs program is now installed as shell. + + mbsetup: + Updated for hardcoded paths. + Updated screen 1.3, global paths. There is only one screen now. + + mbmon: + Updated for hardcoded paths. + + mball: + Updated for hardcoded paths. + + fbgen: + Updated for hardcoded paths. + + mbfile: + Updated for hardcoded paths. + + mbmsg: + Updated for hardcoded paths. + + mbuser: + Updated for hardcoded paths. + + mbcico: + Updated for hardcoded paths. + If the tty port was locked by another process, mbcico tried + to close the port of that process (and luckily it failed). + Now it won't try to close that port and try to remove the + lockfile. Corrected the logmessages during this situation. + + mbaff: + Updated for hardcoded paths. + + mbsed: + Forgot to close the reginfo file after the CIPM command, + eventualy the bbs stopped logging because mbsed ran out of + file descriptors. + Added the GDST command, to get the status of all (but no + more then 10) mounted filesystems. + + +v0.33/a 25-Mar-1999 + + general: + Changed the users structure for IEMSI flags. + + update: + Open in mbsetup the users database, record 1, and close it. + This will upgrade the users database with new fields. + + mbcico: + Will dispatch mbsebbs when the EMSI string is EMSI_NAK instead + of EMSI_INQ. We then assume the client is an IEMSI client. + In the tty driver changed some error messages to debug log + messages. + + mbsebbs: + Didn't flush the screenbuffer when asking the user to read new + mail so the user couldn't see the prompt. + For OLR download the maxumimum number of file requests is now + taken from the main configuration. + Added IEMSI login support. Tested with FrontDoor 2.11/sw. + Flushed a prompt after file download. + The users filetaglist is removed from disk during logoff. + Deleted Toggle Expertmode, menu 307. + Added Toggle New Mail Check, menu 313, text code ^U1. + Added Toggle New Files Check, menu 315, text code ^U2. + Added Toggle Fullscreen Editor, menu 316, text code ^U3. + Added Toggle Bulltins Read, menu 307. + + mbfido: + Added more debugging messages for netmail processing. Netmail + between a boss and point are being bounced between each other. + At least they don't dissapear anymore. + When forwarding a netmail, all original characters were + lost and messages may have become undeliverable. + + mbsetup: + Added new menu choices that were added to mbsebbs. + + +v0.33/b1 29-Mar-1999 + + general: + Added support for "pktdate" from Tobias Ernst. This is a Y2K + .pkt analyzer and fixer. It is called before each .pkt file + is processed. Indeed, he did also made a Linux version. + Added support for ISDN and TCP/IP nodelist flags. They may + be in the Userflag field or in the authorized flags field. + + mbsetup: + Added .pkt preprocessor installation to global->mail for + the pktdate program. + + mbfido: + Inserted code to call the .pkt preprocessor. + Should insert ^aVia line in forwarded netmails and exported + netmails from the local msgbase. + Will now put netmail for direct links that are not in our + setup (by the stupidity of the Sysop, including me) still in + the outbound (normal status) instead of /dev/zero. + + mbcico: + Added support for ISDN and TCP/IP nodelist flags. + Will now call TCP/IP nodes. This is experimental! It uses the + proposal of Lothar Behet (2:2446/301) of 25 Oct 1998. The + defined flags may be in the User field or authorized fields. + At this moment only the IFC protocol is supported, the ITN + support on port 60177 is under construction. + + mbout: + Added support for ISDN and TCP/IP nodes. + + +v0.33/b2 02-Apr-1999 + + general: + 2 new configuration items, user levels to allow sending of + Crashmail and File Attaches. + + update: + Set Crashmail and File Attach levels in screen 1.4 + + common.a: + Updated nodelist flags and rendundency flags according to + errflags.zc2 dated 20 Mar 1999 (from 2:2/0). I should make + an external table for this. + If a semafore already existed (or was removed), nothing will + be done anymore. When a semafore is created, fsync is called + to make sure it is on disk. + Totally rewritten the .pkt header read function, it is now + more portable and does only one disk read to do that. + + mbfido: + Commented out some debugging logmessages in magic file test. + Corrected the ^aVia lines, in one case the Sysop name was + included, in all cases the year was only 2 digits. For + debugging the milliseconds fields are now different in all 3 + functions that create Via lines. + Now creates .pkt headers in a more portable way and only needs + one disk write to do that. + Now creates message headers in a more portable way. + When creating notify messages, the correct local time is now + entered. + Created a new fidonet date parser, removed the bison parser. + When messages are exported, the fidonet date is generated from + the internal structure, so incorrect received dates are + hopefully corrected on the fly. You should not need pktdate + anymore. + Now sets the local time when a message is imported. + + mbsetup: + When creating new message areas, the security fields will not + be preset anymore. + Removed the gid and start uid values. + Added setup for CrashMail and File Attaches. + + mbsebbs: + Remove an extra close menufile in the menu processing. The + Sparc version aborted with Segfault error on this. + When a message is created, the time is now the correct + local time. + Now sets the local time when a message is received by the user. + When a netmail address is entered, the user will now see the + nodelist bbs name and is asked to verify it. + Only above CrashMail level and if the destination node is CM, + the crash option is presented. + When creating a new user, the gid is now taken from the running + process instead of the setup. + + + +v0.33/b3 06-Apr-1999. + + general: + Due to hardware problems on my bbs, I was forced to takeover + the whole bbs on MBSE BBS, RA is now retired. This means that + lots of things must be solved in a hurry from now on, there's + no way back for me. The MOBO died, it is now replaced by an + old 386/DX33, so I have to fix the parts that slowing things + down. It must be able to run good enough on that board. This + also means that only necessary things are developed from now + on to create a stable and useable version. + + msgbase.a: + The message header read function doesn't seek the whole + messagebase anymore if it needs the next header. This will + roughly triple the speed of scan for new mail. + + mbfido: + Removed check for connected uplink if .tic file was a local + hatched file, there are no uplinks for local hatched files. + Finally found the bug where the TOPT and FMPT kludge info + dissapeared from the netmails causing mail for points to bounce + back to the boss. + Added commandline switch -full to force scan to scan the whole + messagebase for outgoing mail. + If ~/tmp/scan.mail exists the area and message numbers are used + to quick export messages. + It can now attach file attaches. File attaches are not routed. + If the imported file has a magic name, this magic is added to + the file description. + + mbcico: + Will stop calling a node after 3 attempts if there are no + matching ports, or if there is a port error. + + mbsebbs: + Abort on SIGHUP is not logged as error anymore but as normal + log message "Lost Carrier". + With netmails files can now be attached if the user has a high + enough security level. Files must be in translatable DOS range. + Fixed segfault when user tried to select an non existing + filearea. + Creates ~/tmp/scan.mail for posted messages to allow quickscan. + + mbaff: + Creates ~/tmp/scan.mail for posted messages to allow quickscan. + + mbsetup: + Finally added the pull uplink in file and mail group editors. + In the tic area and echomail area editors if the group is + selected and the uplink address is set in the group, the the + first default connection for that area is the uplink. + + +v0.33/b4 13-Apr-1999 + + upgrade: + The ticarea, hatch and magic datafiles are changed in format. + Order of update is important! + 1. Compile all sources, don't install. + 2. Make backup of all .data files in ~/etc. + 3. Announce new files. + 4. Remove *.*.*.*.bill files from the ~/tmp directory. + 5. Disconnect all modems, networks and stop the cron daemon. + 6. Run mbsetup from the source directory. ~/mbb0_33b/mbsetup + 7. Menu 10.2, leave and update the database. + 8. Menu 10.3, leave and update the database. + 9. Menu 10.4, leave and update the database. + 10. If all is well, install the binaries, check mbsetup. + 11. Start cron daemon, connect modems and networks. + + common.a: + Removed errormessage when created semafore succeeded when it + opened file descriptor 0. + + mbcico: + When searching for file requests it tried to use ~/fareas.data + instead of ~/etc/fareas.data. + + mbsetup: + Changed the tic areaname field from 12 to 20 characters. + Corrected screen numbers in hatch and magic pick areas. + Setting the magic "to area" now also uses the picklist. + Does normal logging again. + + mbfido: + Doesn't import the file area name anymore in the filesdatabase. + This needs a workaround because this field is now too small. + The check for quick scanned exported messages failed for + echomail if there was more then one downlink. This forced a + complete scan to be done while everything was really ok. + The .tic file dupecheck is moved to do a little later so that + if some checks fail, the file is not in the dupe database yet. + If the destination path is not available, the file and .ticfile + are moved to the bad directory. + Reads "Fullname" field from .tic file, logging only for now. + Will now process archived tic bundles with extension .c00 where + the numbers can be any digit. (Harald again :=). + More errorchecking in Magic file procesing. + Turned some debugging logging back on. + Corrected a bug that sometimes caused a segfault during tic + processing. + Corrected a routing problem if mail was to be sent to one of + my own points, in case there where more than one point. + + mbmon: + Does normal logging again. + + mbfile: + Calls the Nopper() function now to keep the connection with + the server alive. Good for slow systems and lots of files in + one area. + Removed a small memory leak in the check function. + + mball: + Creates "00index" files in each download directory that is in + range of anonymous ftp users. These files contain the file + names and file descriptions of that directory. A new command + "index" is added. + + mbaff: + Corrected for the .tic areaname size of 20 characters. + + mbsebbs: + Fixed segfault when user was trying to select a non existing + message area. + + +v0.33/b5 26-Apr-1999 + + general: + A new set of grouprecords is created. This is for the announce + of new files, so reports can be created by subject, ie. + Windows, Erotic pictures, Utilities etc. The groupnames are + part of the bbs file areas. + + upgrade: + Set in menu 1.15 the number of newfiles groups. + Create the several newfiles groups. + Install in all bbs file areas the right newfiles groups. + Install in all newfiles reports the right newfiles groups. + + mbsetup: + Will now ask if messagebase must be created if it doesn't + exist. + Implemented the setup of newfiles groups. + Will now show the TZUTC time instead of system generated + timezone (didn't work on RH systems). + + mbcico: + Changed some logging, removed some debug logging. + + mbfido: + Corrected a errormessage when the file import failed in a + non existing area. + If the file is imported in a bbs area, and that area has a + separate Newfiles groupname, that name will be stored in the + toberep.data file for announce. + If a fdb area doesn't exist during file import, it will be + created on the fly. + Doesn't send empty netmails anymore if node has tic messages + off. Only messages with text in it are send now. + Switched .tic description lines logging on again because there + are some strange descriptions coming in. + Fixed a problem when there was only a normal description line + in the incoming tic file, the downlinks got a shortened + description line. + Doesn't strip Hi-ASCII from FILE_ID.DIZ file anymore, only + control characters. Stripping of Hi-ASCII should only be done + by file announce programs (if the moderator wants that). + + mbdiff: + Removed a lot of debug logging. + Removed unarchive functions as they are already in the common + library. + + mbindex: + Removed some debug logging. + It now deletes old nodelists from the nodelist directory exept + the most recent two lists. + + mbsebbs: + Added logging of selected file and message areas by the users. + During mailscan and filescan inserted call to Nopper(). + Wrote a new Getstr function to create Unix accounts, this + one won't accept spaces. (Thanks to Henk de Graaf, a user + who failed to login). + The username won't be converted to lowercase anymore when + his Unix account is created. + The Unix name has to be at least 3 characters. + + mbaff: + In the announce function new uploads will get the area number + as fileecho name so they will be announced by area. + + + +v0.33/b6 30-Apr-1999 + + common.a: + Execute now only logs result messages if there was an error. + + mbaff: + Added High ANSI to Low ASCII translation for echomail areas + that need it. + + mbsetup: + Added High Ascii switch in filefind setup. + Corrected menu numbering. + + mbfido: + After tossing a .pkt the result is only logged if there was + an error. + Removed 2 debug messages during netmail import. + Made logging of "Keep files" final. + Allowed hi-ascii in .tic files for the descriptions. + Build in a check for multiple "Desc" lines in .tic file, + only one is allowed. Offenders are logged, See FSC-0087. + + mbsebbs: + Quick_Bye() is now logged (if possible). + + mbdiff: + The resulting new archived nodelist will now be a lowercase + name instead of a uppercase name. + The new nodelist will be default be archived with the same + archiver as the diff file came in, if it's not available + there is now a fallback to ZIP which is always available. + + +v0.33/b7 10-May-1999 + + upgrade: + ACRmail 0.60 file naming convention is default off for + existing nodes, check their setup. + + msgbase.a: + Added a counter which keeps track of the size of the message + being written. + + common.a: + Will now create unique arcmail names for out of zone mail if + it is turned on. This should prevent creation of duplicate + arcfile names to the same node. + Corrected logging of bestaka_s function. + Doesn't create 00000000.fr0 ARCfile names anymore if our + system is the point sending to the boss. + + mbaff: + In the announce function added logging of the size of the + written message. + Inserted a checkpoint log after each announced block. + Inserted code to split messages after 13000 bytes. + + mbfido: + Removed "Packing Mail" logmessage. + Imported netmail will now allways get the Private status. + Added code to replace the archive comment, currently this + works with .zip and .rar archivers, others don't support + this. + The ^aVia line was inserted at the begin of a forwarded + message instead of at the bottom, it also had the address + of the origin system instead of our own system. + Also moved the ^aVia line in the other 2 functions to the + bottom. + + mbfile: + If during the check for missing files in a download area there + is an extra file and it is not a regular file, it wil be + ignored. This allows the use of subdirectories. + + scripts: + Added support for binkd, if it is installed in ~/bin and the + binkd.cfg is in ~/etc it will be started and stopped as the + rest of the bbs. + + mbsetup: + Added in nodes setup ARCmail 0.60 naming convention switch. + + mbcico: + When there are session errors, the status counter is now + increased with 5, so maximum 6 calls are done. (was infinite). + + +v0.33/b8 23-May-1999 + + mbfido: + Corrected Connection time log messages. + + mbcico: + Restored the original filetime functions. + Removed 2 debugging log messages. + Made the filerequest processor 3 times faster. The remote + doesn't timeout anymore during the search for files. It + must still be made faster. + + mbsetup: + Added the (hidden) option to move echomail areas. + + mbout: + Will also clear the status record of a node with the poll + command if the reason was session errors. + + mbdiff: + Changed available archiver tests, and fallback to ZIP + archiving. It is finally working. + + mbsebbs: + Corrected the reply test for new users when they had entered + their name. + Updated language number 413. + New users won't see the "new files" when they logon the first + time. (They saw all the files on the bbs). + If IEMSI login is aborted or failed, IEMSI won't be used + anymore during login. + When the offline reader packs netmail, only personal mail is + now added to the dowload packet. + + +v0.33/b9 12-Jun-1999 + + update: + Change scripts that call mbuser. + + general: + Changed startup and finish logging of all programs to use + one style. + + mbaff: + New file reports that are splitted over several messages will + now report the right report totals. + Removed some development debugging logs for splitting messages. + + mbdiff: + Removed all extra debugging logs from version beta-8. + + mbuser: + Made command syntax and helpscreen as in all other programs. + This affects the scripts. + + mbsebbs: + For the "comment to sysop" function the .quote file in the + users homedirectory will now be truncated to 0 bytes to erase + its contents. + The "mailout" semafore is now only set at the end of the user + session. + Inserted the Nopper() call in the fullscreen editor to prevent + server timeout when writing a long message. + When writing a netmail to an unknown node, the user must verify + to send the mail anyway. New language prompt 241. + If a user is short with transfertime for a download, it will + be written to the logfile. + + mbfido: + The notify function will now only include areas that are + "Active" in the reports. + Changed the ASCII filtering of reading .tic and FILE_ID.DIZ + files, High-ASCII characters are not lost anymore. + The packet password is now only checked if the originating node + is in our setup. + Before processing AreaMgr and FileMgr messages the right + noderecord is loaded again in case it was replaced. + + +v0.33/b10 19-Jun-1999 + + general: + The man pages are removed. + + mbfido: + Removed logging of file descriptions. + Changed logging of replacing archive banner. + + mbaff: + Removed logging of splitting messages. + Removed several other debugging logmessages. + + mbsebbs: + Removed some debugging logging from download functions. + Corrected a logmessage for new users, language line 66 + is now obsolete. + + mbsetup: + Included (Spacebar = toggle) message in yes/no switches. + + mbuseradd: + Removed the creation of .profile in the users home directory, + this is not necessary because the users shell is mbsebbs. + + +v0.33/b11 29-Jun-1999 + + Most fixes in this release are from Jan van de Werken who is beta- + testing v0.33/b10. + + upgrade: + In mbsetup menu 1.14 set new fields 21 and 22. + In mbsetup, enter menu 8.5, set security levels for transfer + protocols and save the database. + + general: + Added 2 global setup integers for splitting newfiles reports. + + common.a: + Removed Getstr() function. + + mbfido: + Changed AreaMgr and FileMgr message body checks, lines with + more than 1 space or tab and empty lines are skipped. + Removed debug logging for import local netmail. + + mbsetup: + Added in menu 1.14 setup for newfiles reports message split + at a gently size (after a group of files) and a forced + message size. + In nodes setup, new records now default have Advanced tic off. + In nodes setup corrected several numbering errors. + New defaults for global configuration by Jan van de Werken. + To confuse all non-Unix users, all file attaches seem to + come from our A: drive. + Corrected a lot more wrong screen numbers. + + mbaff: + Implemented gently and hard splitting newfiles reports using + the global setup. + + mbsebbs: + Rewrote all user input functions. They should beep now if + the user does something wrong. + Changed the GetPhone functions, the format is not fixed + anymore and it accepts only 0..9 + - characters. This should + work in all countries now. Minimum length is 6 characters. + Changed the language prompts 45, 47 and 48. + Language prompt 46 is not in use anymore. + Removed the logdate2 function, it wasn't used. + Added GetstrP() function (instead of Getstr() in common.a). + Change transfer protocol now checks for the proper security + level. + + scripts: + Updated most scripts, added more comments, added tests to + see if MBSE_ROOT is already set, style fixes. + + +v0.33/b12 08-Jul-1999 + + general: + Removed creation of .VERSION file from the main Makefile. + + mbfido: + The echomail areatag is forced to uppercase. + Removes stale FILE_ID.DIZ files before processing a new one. + + mbsetup: + The new fields 1.14.21 and 1.14.22 where placed at the wrong + column on the screen. + Changed the default values for gently and forced message split + to 27 and 30 KBytes. + Corrected a missing linefeed in sitedoc protocols listing. + Corrected a menu error in menu 8. + Corrected placement of menu item 1.4.11 + Some cosmetic changes in the sources. + Corrected help message in screen 7.x.23, caused mbsetup to + crash. + + mbsebbs: + The info screen now displays compile date and time. + The Area listings for file areas and message areas now break + lines at column 79 and send cr/lf at the end of the line. + Also, area numbers increased to 5 digits (was 3). + Added cr/lf to language prompt 220 in mail.c + + lang: + Shortened prompt 220 with 1 character. + + +v0.33/b13 28-Jul-1999 + + general: + Added structure for file request index. + + update: + Run "mbfile index" once. + Include "mbfile index" in the maint script. + Modify "run_inout" script to start "mbfile index -quiet" if + the semafore "reqindex" is present. + Modify "run_inout" script to replace the fixed .pkt filenames + with stdin from the mbseq program, ie: 12345678.pkt will + become `mbseq`.pkt + Set the filerequest limits in menu 1.17.22 and 1.17.23 + You may specify portspeeds above 57600 in the tty's setup. + + common.a: + Corrected a comment in pktname.c + Changed error logging in execute.c + Moved execsh() from mbcico into common library. + + mbcico: + Removed some debugging logmessages from yoohoo.c + Changed some debugging logging from 'Session' to 'EMSI'. + File request response messages now contain MSGID, PID and TZUTC + lines and request limits. + Filerequest limits implemented. + Filerequest search now uses the index file created by mbfile, + should be fast enough now. + Moved execsh() to common library. + Magic execute request result is now send by mail instead of + an ASCII textfile. + Made some changes in zmmisc.c according to ifmail-2.13, sessions + with D'Bridge 1.58 seems to work now. + Logging of "chat: read return -1" suppressed, this is most of + the time caused by modem hangup during dial and is not a real + error. + During outbound scan missing directories will be created. + A major error in callall.c prevented crash arcmail to be sent. + Rewrote all functions that created mail, less disk I/O. Also + made the .pkt headers the same as the mbfido program did. + Will now handle serial port speeds upto 4000000 baud if your + hardware can handle that. + + mbsebbs: + Finally implemented user access flags. + Removed some debug logging. + Changed "Terminated on SIGALRM" error logging to normal log + with "User inactivity timeout" message. + + mbsetup: + In edit users toggle of flagbits is now correct, no "notflags" + anymore. + Added setting of filerequest limits in menu 1.17 + Changed fieldlength for integers to 7 digits. Now you can + enter all available portspeeds in the tty setup. + + mbfile: + New command: index. This will create ~/etc/request.index + which contains a sorted index of all requestable files on + your bbs. This index is used by the mbcico request processor + to speed up the filerequest search. The "reqindex" semafore + is removed when it is finished. + + mbfido: + Creates "reqindex" semafore if there were files imported. + The check for stale FILE_ID.DIZ files was at the wrong point. + Will pack the mailqueue if the temporary .pkt file is bigger + then the maximum size of that .pkt and creates a fresh one. + + mbseq: + New program. Write a 8 character hexadecimal unique sequence + number to stdout. This can be used in shellscripts to create + unique filenames. The sequence numbers are fetched from mbsed. + + +v0.33/b14 16-Aug-1999 + + general: + This is the first public release. + + mbcico: + Revised zmodem protocol, changed timers etc. Used latest + information (Aug 1999) found at Omen Technology's ftp site. + In the openfile function added support to skip files already + present in the inbound. + Hydra and TCP protocol transmitters now send the filetime + rounded up to even seconds just like zmodem already did, so + the filetime is always the same on DOS (Fat) as on Unix + systems. + Zmodem will now skip files already present in the inbound. + Hydra will now skip files already present in the inbound. + TCPproto will now skip files already present in the inbound. + Changed EMSI debug logging, should be more clear now. + Does finish zmodem session with D'Bridge [1a] 1.58 now. + + scripts: + Added support for UPS. The UPS software should set the + semafore "upsalarm" when it's running on battery power. Most + utilities will the not run anymore to prevent data-loss. + The semafore "upsdown" should be set just before the UPS + starts the real shutdown. This will force the mbstat program + to timout after 30 seconds. + + mbstat: + The wait command will only wait for 30 seconds instead of + one hour if the semafore "upsdown" exists. + + +v0.33/g1 01-Sep-1999 + + general: + Many brave souls have downloaded and tested the previous + version. Most changes in this release are bugs found by all + these people. + Added checks in the Makefile to test the MBSE_ROOT variable, + written by Jan van.de.Werken. + Added checks in some Makefiles for root privileges for + make install. + + upgrade: + Enter mbsetup 1.1.10 and set the name to "bbs". + Check UnSecure switch in echomail areas. Should be off unless + you need it. + Remove the line LOGDEBUG from $MBSE_ROOT/etc/client.conf + + common.a: + Added the original copyright in for the 32 bits crc code. + Checking .pkt header now checks valid system aka's. + Removed reading LOGDEBUG from ~/etc/client.conf, wasn't used. + Added SigName for Alpha CPU (not tested). + + mbfido: + Removed debug message in addpkt. + Added 2 extra DeleteVirusWork() calls in tic processing at + points where processing is aborted and left the temp directory + with unwanted files. This also happened when a virus was + detected. + Will now import echomail from points who are connected to + the normal nodenumber instead of the hub/host number. + Will now try to import bad netmail into a netmail directory + instead of losing it. + Changed the check for received echomail, the sending node + must be in the export list, unless the msg area UnSecure flag + is set. + Implemented the connected systems Excluded flag for echomail + connections in import/export echomail. + Implemented the connected systems Excluded flag in the AreaMgr. + The Notify function now also sends statistic reports to the + node. + Fixed a routing problem (I hope) for out of zone routed + netmail. + When scanning outbound netmail the domain field is zeroed in + the destination address to prevent garbage in the domain field. + Patches by Jan van.de.Werken, files import now set the name to + FileMgr instead of sysop's name. + AreaMgr and FileMgr generated messages now have AreaMgr or + FileMgr as "From" name instead of the sysop's name. + + mbcico: + Restored some zmodem code that was changed in beta-14. + Added some other code for error handling (Carrier lost). + Zmodem file transfers are streaming again. + Added a tty flush in the TCP/IP transmitter. + Solved the EMSI handshake problem with T-Mail mailers. + + mbsetup: + Added menu 1.1.10 to setup the name of the bbs startup + account. The default is "bbs". + Changed ImpSeenby switch in UnSecure switch in message areas + setup. + In message areas the Excluded flag is added to the systems, + you can now disable a node from an area if a moderator wants + that. + In edit users added a switch to toggle OLR Extended Message + Info in OLR download. + + mbsebbs: + Now reads the bbs startup name from the configuration instead + of using the hardcoded name "bbs" + Writes a door.sys dropfile in users homedir. The first line is + fixed to COM0 forcing doors to run in local mode. The second + line is 0, meaning 0 baud is local mode. Let's see how this + works. + Added some logging for the OLR upload function. + Now tests lowercase filenames also for reply packets created + by MultiMail. + Now includes the ^aMSGID string in BlueWave download messages. + Optional includes all other kludges in BluwWave download. + + +v0.33/g2 02-Oct-1999 + + general: + Moved the mbsed back into this archive. Included the new + installation procedure. + Moved the example files into this archive. + + upgrade: + Remove $MBSE_ROOT/bin/fbgen. + If you want to switch off CFG.dospath, be sure your outbound + is empty or mail and files will get lost!!! Thus: type + "mbout stat" and see if nothing is there before you do that. + + common.a: + Patches by JvdW, if CFG.dospath is empty then fileattaches + will contain Unix style filenames, otherwise the ataches + are translated to DOS style. + + dbase.a: + If SearchTic and SearchMsg function the area must be active + in order to be found. + + mbaff: + Removed a bug in scanning uploads function that created empty + lines in the toberep.data file. Also forced the long + description strings to be no longer then 48 characters. + + fbgen: + Finally fixed this one. Can now read multiple description + lines from files.bbs. Renamed to mbfbgen. + The dangerous gets function is replaced. + + mbsetup: + The edit path function now checks if the directory has read + access instead of write access, it might be on CD-rom. + + mbfile: + Skips the kill and pack functions on CD-rom areas. + Skips the check of files on disk against the database on + CD-rom areas. + + mball: + Doesn't create 00index files on CD-rom areas anymore. + + mbcico: + More bugfixes in TCP protocol. Better error handling for + disconnected sessions. + Creates inbound tmp directories when they don't exist. + Now presents the EMSI info from the tty records if + possible. + + script: + Corrected a syntax error in the maint script. + + mbfido: + The areamgr and filemgr names are not hardcoded anymore, + the names presented are the first names defined in the + setup. + Outbound processing now also works if CFG.dospath is empty, + then Unix style fileattaches will be created. + Rewrite of file import function by JvdW to fix some bugs. + FileMgr and AreaMgr global connect and disconnect now + check if the area is set to Active. + Rewrote ARCmail naming, zero length archives older then + 6 days are deleted. If a zero length archive then still + exists, the extension number is bumped. This should + prevent using the same archive name on the same day to + nodes with more then one mailsession each day. + + +v0.33/g3 18-Oct-1999 + + general: + Ideas for generating ARCmail names by Sean Rima and JvdW + implemented. + Lot's of cosmetic stuff to make commandlines, help screens, + more clear and the same for each program by JvdW. + + update: + In mbsetup 1.14.15 check that this is zero or the number of + old days you want echomail rejected. + Check in mbsetup nodes->mail that "ARCmail a..z" is off + for nodes that can't handle that. + + mbcico: + File attaches that are no longer on disk are now correctly + removed from the flo files. Changed logging for this. + The scanout function now removes truncated ARCmail files + that are not of the current day or are older then 6 days. + Corrected a bug that the inbound directory wasn't created + when it didn't exist. + + mbsebbs: + Now allows netmail crash replies. + Can now reply netmail that came in via the UUCP gateway, + when the reply is saved the message is readdressed to the + gateway. + Disabled the download transfertime check before starting a + download. It gave unpredicteble results if the users previous + download cps was bad for some reason, the user couldn't + download. + + mbsetup: + New menu item in 1.14, "Reject old", to reject incoming + echomail older then this number of days, or zero to not + check the age. + In nodes->mail setup added a switch to allow a..z + ARCmail archives extensions. + Made editing log (debug) switches more clear. + Some editing keys now beep if you do something wrong. + + mbfido: + The pack function now supports 'a..z' ARCmail extensions + if this is on for that node. + It's possible to reject too old echomail. + Short commands and options now displayed in the help. + The fileforward netmail now set's the filemgs name first + character to uppercase. + The uploader name with file import now only has one + name anymore, the first character is capitalized. This + line should not be too long, this gives ugly listings. + System aka's in the same zone other then the aka of echomail + area are added to the seen-by lines. + Added experimental zonegate support for echomail. + Removed some debug logging in tic processing. + + mbaff: + Short commands and options are now possible, like other + programs already did. + + mbout: + Short commands and options are now possible, like other + programs already did. + The scanout function now removes truncated ARCmail files + that are not of the current day or are older then 6 days. + Suppressed the help message for file attach, it is not + yet implemented. + + mbfile: + Short commands and options now displayed in the help. + + mbmsg: + Short commands and options are now possible, like other + programs already did. + + mball: + Short commands and options now displayed in the help. + + mbstat: + Short commands and options are now possible, like other + programs already did. + + mbfbgen: + Handles files.bbs lines of 255 characters instead of 80. + + +v0.33/g4 05-Nov-1999. + + mbfido: + The final seenby lines are deduped and sorted before writing + them to the in and exported echomails. + Areamgr and Filemgr messages now have a capitalized first + "From" name character. + Areamgr new function: flow reports. Can be requested by + %flow and is automatic generated with notify reports. + Areamgr, increased the area tag from 20 to 25 characters + in the notify reports and %list, %query, %unlinked response + messages. + Corrected a bug creating garbage at the end of the magic + execute commandline. + + mbsebbs: + Reply to UUCP gateway didn't work in real live, it seemed + that the official UUCP gate had no ':' character after the + REPLYADDR and REPLYTO kludges, while my testsystem running + ifmail 2.12 for the gate does. I now test both cases. + + mbcico: + Implemented remove ARCmail older then n days. + + mbout: + Implemented remove ARCmail older then n days. + + mbsetup: + Added integrity check for edit message groups. + Added integrity check for edit fileecho groups. + + +v0.33/g5 13-Nov-1999. + + upgrade: + Edit /etc/inetd.conf to add "-t ifc" for standard ifcico + protocol, "-t itn" for telnet protocol. + If you don't use the original binkp mailer, you may want to + add entries for the binkp protocol, this will show the + remote that you don't support the binkp protocol. + The installation scripts are updated. See the file SETUP.sh + on how the files /etc/services and /etc/inetd.conf should + look like. + + mbcico: + Implemented "not supported" binkp protocol. + Revised commandline parameters, in TCP/IP slave mode the + mode must be given on the commandline, -t ifc for standard + ifcico protocol, -t itn for telnet protocol, -t ibn for + binkp protocol. + Starting mbcico without arguments will show the help screen. + Now all programs do that exept the mbsebbs binary. + + mbsebbs: + Changed language prompts 214 and 215. + Added language prompt 46. + Added message export to file function. The file will be saved + in the users private homedirectory, the filename is created + as _.msg in MS-DOS format. + Corrected display header of users home directory file list. + Added import file in message function, the file must be in the + users private homedirectory. This only works in the fullscreen + editor. + + mbfido: + Inserted 2 sync() calls during mailtoss. I hope this prevents + temporary missing archives and .pkt files. + New command, "tag", writes areas tagfiles for each mail and + tic file group to the ~/doc directory. Filenames are automatic + created. + + mbsetup: + In edit tic area and edit message area editing of connected + systems now uses the excisting node setup. + Made a new menu selector for areas with Global and Move + options. + Implemented new menu selector in message and tic areas select. + If you jump directly to a message or tic area with select, the + offset is recalculated to that area range. + Added global editing functions in message areas setup. Functions + are add, delete, change connected systems, aka to use and some + other settings. + Edit a nodes aka's is checked if these aka's are used in tic + and message areas. + Delete a node is checked against aka's used in tic and message + areas. + +v0.33/g6 22-Nov-1999 + + mbsetup: + Removed a bug where you could not add new aka's to nodes due to + the aka's checking. + With database intergrity checks the cause of blocked actions + is now logged in mbsetup.log + If you change the number of connected systems or maximum groups + in global setup, the databases affected will be automatic + updated. + + mbfido: + When writing a notify message to selected nodes all other nodes + received status messages. + Corrected uploader name, removed "BBS" string. + Installed patches from JvdW in file forward to correct some + segfaults with the subject variable. + The local hatched files are now moved to the inbound so that + the unarchiver programs can find these files. + + mbcico: + Added very experimental binkp protocol. Handle with care and + at your own risk. This isn't finished yet. + + SETUP.sh: + Fixed the script, there was one "fi" missing so the script + crashed and didn't do all changes. + + +v0.33/g7 05-Dec-1999 + + mbcico: + Fixed some logging in binkp protocol. It works for normal + mail and files transport. + + mbsebbs: + Export message to users work directory did not put the + message in the work directory but in the home directory. + + mbfido: + Netmail to unknown bbs users are now readdressed to the + sysop. Should be a bounce message. + Added a experimental test for empty imported netmails. + The netmail area Private flag is checked to see if we keep the + original Private flag or force imported netmail to Private. + + +v0.33/g8 12-Dec-1999 + + general: + Changed the Makefile, make zip now puts FILE_ID.DIZ in the + root of the directory tree so that file processors will + find it now. This is a version of this file. + + common.a: + Removed and changed nodelist lookup debug logging. + + mbuseradd: + Now check the excistance of the users home directory, if it + is found then it is removed before the home directory is + created again. This fixes problems with RedHat 6.1. + + mbfido: + Global AreaMgr commands cannot disconnect message areas anymore + that are mandatory. + Removed some routing tracking debug messages. + Added check to see why not connected echomail is imported to + the netmail of the last user in the userbase. + Changed check to "Sysop of z:n/n@network" to readdress to + the sysop's real name. + After readdress a netmail to the sysop, the usersearch is now + done again. + If locking the message base during import fails, import is + aborted. + + +v0.33/g9 18-Dec-1999 + + upgrade: + If you ever used DOSEMU then do a rm -Rf .dosemu in each users + home directory. The ownership of these files are changed so + they are created again when the user runs a door for the + first time. + If you have created ttyinfo records with just digits in it + for the /dev/pty/0 type tty entries, you need to change them + to pty/0 type entries. The example etc files are now containing + these entries. + + general: + All sources recompiled with memwatch. I will not name all + places where I found memory leaks, it was a lot. Still busy + finding them, but most programs are allright now. + You can turn memwatch on and off in the file CONFIG. If you + change it, do a "make clean" before recompiling the sources. + Changed my Fidonet address, the testsystem is listed now and + removed my old e-mail address which was not valid anymore. + Changed the installation script. + For RedHat 6.1 and newer a different /etc/rc.d/init.d/mbsed + file is created then before because the su command behaves + different. The install script will try to detect this. + Thanks to Juergen Heisel for finding this problem. + Changed more startup and shutdown scripts. + Changed language prompts 306, 311 and 324 to reflect + GigaBytes storage instead of MegaBytes. + Changed language prompt 327, it had a space too many at the + end. + + common.a: + In the attach function implemented the global leavecase + switch to be able to turn off the forced uppercase for + file attaches when dos translation is on. + + mbfido: + Found a bug where mbfido ran out of file descriptors during + toss, only about 1012 messages were tossed and then the whole + thing started tossing everything to bad. Jim Hansen who + reported the problem, reported that tossing 37500 messages + now works fine. + Added the commandline switch -unsecure to be able to run an + unsecure toss, ie. no originating checks are performed. + Handle with care. + Forwarded netmail packets got the wrong from address in the + .pkt header. + Added fsync calls after every write to a message packet. + When writing .tic files to other nodes now the real aka of + the tic area is used in the From address instead of bestaka + match of the destination. + All system aka's in the same zone are now added to the .tic + Seenby lines. + Will now gently stop processing if the upsdown semafore is + detected. + Added a check with file import that there are no more then + 25 description lines. + + mbsebbs: + Added new controlcode, ^KM displays the users lastread pointer + in the current message area. + When reading new mail at logon, the users lastread pointers + are not updated anymore in echomail/news areas to prevent that + the users skips unread messages. + Only if a message area is Public/Private and a reply is given + the user gets the question Private y/N. On other cases the + flag is automatic set. + With netmail reply if enough security level a file may be + attached. + The door.sys dropfile date formats are now fixed. Depending + on the menu settings it can be original (pre 2000) format or + have four digit year numbers, the new style. Writing the + dropfile can also be suppressed. + Removed the setuid calls before and after running a door, + mbsebbs now always runs as user "mbse". + The $HOME environment variable is now forced to the users + real home directory, even if mbsebbs is started as user bbs. + When the user logs in, the existance of the subdirecties + .dosemu/run and .dosemu/tmp are created in the users home + directory if they don't exist. DOSEMU is happy with that. + Because of this, all files in the users directories are now + only owned by user mbse. + Moved the setup of last message and file area to a later + startup point in userlogin. + Autoexecuted menus are now also checked for user security + and user age. + Fixed the screen output of several bbs list menus. + Now handles the /dev/pty/0 device names found on newer + Linux distributions. + It will now also create the necesary subdirectories for the + /dev/pty/n devices. + + mbaff: + The written messages statistics counters always counted at + sunday in januari. + + mbmsg: + Added message post from a file function. + + mbsetup: + With the filebase editor I got segmentation faults on a Sun + Sparc machine, changed the filedate calls. They show up the + local time now also. + Added the global editor for the tic areas. + Added in menu 1.3 a switch to leave to case for .flo files + original, ie. not forcing it to uppercase. + Added menu creation in menus setup. + Added setup to suppress the creation of a door.sys dropfile, + and the ability to write the years in four digit format in + the door.sys file. Newer doors seem to understand this. + Added delete menu item in menu setup, finally. + Added menu item move. + The menu editor now shows the autoexec menus with the + lightred lowercase "a" at the selection key position. + When a new config.data is created, the default loglevels + are now set to normal values. + + mbcico: + Forgot to implement the NoTCP global and per node flag. + If you are not permanent connected to the net, use these + to prevent the use of internet protocols. + + mbmon: + Screen 5 now calls Nopper() to keep the server alive. + Corrected screen display numbers 5 and 6. + + +v0.33.10 24-Jan-2000 + + general: + Changed version numbering. From now on, minor odd numbers + are testversions, even are stable. Same as with the + Linux kernel. + Changed the setup script, it should now detect SuSE systems. + This is not tested. + + update: + Remove (as root) all bbs users from /etc/ftpusers. They are + not needed (and never were). + Compile and install this release. + Kill mbsed (killall -9 mbsed). + Edit $MBSE_ROOT/etc/mbsed.conf, remove the line with logdebug + and the commentlines above. + Start mbsed again (/opt/mbse/bin/mbsed). + Then start mbsetup, open the global menu 1, and exit. Answer + yes to update. + If you have any echomail passthru areas, give them a + message base path. Passthru doesn't exist anymore. + + common.a: + The file_crc function now supports the usleep(1) code + for background processing. + The logfunctions now replace and with spaces. + + msgbase.a: + Corrected a bug in the Pack function when the headerfile + was corrupt. If the header is corrupt, the index file is + used to find the right recordposition again. Errors are + logged. + + mbsed: + Removed the logdebug loglevels. Logging is fixed now. + Changed the answers for the SBBS command. + + mbsetup: + Added a global setup screen for the ftp server. + Added a switch in the menus setup for doors to set a flag + to create door.sys files for dosemu/Vmodem use. + Revised the message area setup screen. + Changed text's in global mailer setup to indicate that the + mailer flags are for TCP/IP connections. + + mbuseradd: + Doesn't add usernames anymore to /etc/ftpusers. This is not + needed for standard ftp security. + + mbcico: + Added send filerequest to the binkp protocol. In single + batch mode, you need to connect a second time to get the + request response. This is normal single batch behaviour. + Nodelist flag for Binkp mode is XX. (For POTS/ISDN XA). + Added received filerequest to the binkp protocol. In single + batch mode this will put the files on hold. Multiple batch + mode works now but is only tested against another mbcico + mailer. + Calling internet nodes could not use a forced hostname or + IP address. Fixed. Added search in nodes setup phone + fields for hostname/IP address, search in nodelist location + entry (2 nodes on the world do that, I needed one of them), + and the IP notation in the nodelist phone field (000-...). + Hostnames after the flags are not resolved, hostnames + should be in the system name field. + In the binkp protocol the flags from the global mailer + setup are sent as our flags. + + mbsebbs: + The next two pathes are from Ken Bowley. + Changed the fullscreen editor with patches from Ken Bowley. + Improved behaviour for inserting and deleting text. + Changed the door.sys creation, if the COM port option in + the menu files is on, the door.sys file writes COM1 in + it with a portspeed of 115200. This is for running doors + under dosemu and a patched Vmodem. + Made newmail scan and other checks for personal mail case + insensitive. + The fullscreen editor source now has an extra define FSEDIT + to enable heavy debugging logs. + It didn't respect the BBS closed status on lines that did + not honor ZMH status. + Removed "Re:" debug logging from mail.c + + mbfido: + Corrected the queue path for tic passthru areas, the + destination path missed a /. + Delete file from the inbound with passthru areas is now at a + later point. + Removed the message passthru switch, you needed and area + anyway. + + mbstat: + Corrected screen output when it was waiting for the bbs to + close. + + mbftpd: + New! Special ftp server for MBSE BBS. Should use BBS users + access restrictions etc. Doesn't work yet so don't use it. + It is included in the distribution, but not compiled or + installed. + + +v0.33.11 07-Mar-2000 + + upgrade: + Change the CLIENT line in ~/etc/mbsed.conf, the authcode must + now come behind the hostname. Remove the AUTHCODE line. + Kill the old mbsed, start the version from this version. + The same changes must be made to ~/etc/client.conf + Run mbsetup, goto 1.17 and 1.18 and set it up for your system. + Check the QWK area names in the message areas: if there are + areanames longer then 13 characters edit them so that they + fit in the 13 characters limit. In previous versions this field + was 20 characters. + + general: + Added global config to create www pages for downloads. + Included the mbftpd directory in the main Makefile. Don't use + the mbftpd program yet! + Updated the documentation, some parts were 2 versions behind. + + common.a: + Execute external programs now lowers process priority to 15, + and restores to 0 after execution. This should make running + (de)compressors and other utilities "nicer". + If a client fails server authorization, it will now proper + close the server connection. + + mbsed: + The syntax of the client lines in mbsed.conf is changed, + multiple lines are now allowed, hostnames and authcodes must + be on one line now. + It is now possible to close the connection when not authorized. + Minimized the number of response codes. Updated the + documentation. + + mbsetup: + Added global setup menu for the html pages creation. + The length of the QWK area names in the message areas setup + is changed from 20 to 13 characters for the QWK specifications. + Removed selection of menu number 216 from the menu editor. + + mball: + The index command now also creates index.html files for web + clients. The index files are stored in the download directories. + If a download directory contains .gif or .jpg files then + thumbnails will be created and the thumbnails will be used in + in the index.html files. + You need "convert" of the ImageMagick package to use that + future. + + mbfile: + Added 'index*' to the list of filenames that isn't checked + with the mbfile check option. + Pack and Move file functions will now also delete or move the + thumbnail files. + + mbcico: + Changed the binkp receiver timeout code to prevent a hanging + receiver. This only happens sometimes on a Sun Sparc (and + still does). + Changed the modem chat logging. It is now visible what is + really send and received from to the modem. + + mbsebbs: + Added wordwrap in the fullscreen texteditor. Patches by + Ken Bowley. + Replaced hardcoded prompts in offline.c with language prompts. + New prompts are 66, 228, 229, 256, 260, 277, 297, 338, 374, + 377, 391..397, 411, 425, 439..460. Replaced a language prompt + in the Language load function with a hardcoded message. + Removed menu option 216, download pointmail. + Added QWK download and upload. Not fully tested yet!! + Added ASCII download. + File descriptions with color info will now be displayed in + color. + + mball: + File descriptions with color info suppresses the color info + in the all/newfiles listings and 00index files. + + +v0.33.12 24-Apr-2000 + + upgrade: + After compiling and installing set the amount of free + diskspace in mbsetup menu 1.4.22 to your choice. + Kill and reload mbsed. + If you use the web interface for the file areas create + the directory css in your webserver document root and copy + files.css from the distribution archive in it. Then run + mball index. Customize files.css to your taste. + + general: + Changed the ~/tmp/scan.mail file to ~/tmp/echomail.jam and + ~/tmp/netmail.jam in the standard JAM format. + Added file README.GoldED + + common.a: + Added function to check for free diskspace on ext2, msdos and + vfat filesystems, except floppies. + + mbsetup: + New nodes now have "Notify" default off. + Renamed menu 1.4. + Added minimum diskspace setting to menu 1.4. + Added force FNC switch to the nodes setup. + + mbfido: + Exported netmail are checked until any tearline, not MBSE's + tearline alone. + If exported echomail doesn't have a ^aPID kludge, the ^aTID + kludge will be inserted anyway. + Removed some debugging info from the ARCmail pack function. + When netmail to points is written with GoldED there was no + ^aTOPT kludge. Any missing ^aTOPT, ^aFMPT and ^aINTL kludges + are now added if they were not found during mailscan. + The unarc/viruscheck directory is now completly removed after + use and created again. Sometimes files with strange names + were left behind with a normal recursive remove. + Now checks at regualar points the free diskspace. Execution + aborts if it is too low. + + mbsebbs: + Inserted ^aINTL: kludge instead of ^aINTL without colon. + Corrected the users age calculation, the users age increased + one month after his birthday. + + mbsed: + Added some fsync() calls to ensure disk writes. + Now starts logging reginfo locking after the fifth attempt. + + mbcico: + Made some small changes to the binkp batch function. + Added free diskspace check during outbound calls. + Added BSY command support for binkp during file transfer stage. + Changed binkp timer reset points during file transfer stage. + The binkp receiver now checks diskspace before accepting a + new file, it sends BSY if too low to the remote. + If in nodes setup the FNC flag is set, the binkp protocol + will now send old 8.3 uppercase filenames to the remote. + + mball: + The WWW pages now include a stylesheet so it is more easy + to create a personal look and feel for the pages. The + stylesheet goes into htdocsroot/css/files.css An example + is included in this distribution. + + mbaff: + Added free diskspace check. + + mbindex: + Added free diskspace check. + + mbdiff: + Added free diskspace check. + + mbmsg: + Added free diskspace check. + + mbuser: + Added free diskspace check. + + +v0.33.13 12-Jun-2000 + + upgrade: + Make all files and install them as root. + If you use GoldED or other mail utilities as another user + change $MBSE_ROOT/sema and $MBSE_ROOT/tmp to mode 777. + Kill mbsed with signal 9. + Now start mbsed again (/opt/mbse/bin/mbsed). + + general: + The install script now sets the $MBSE_ROOT/sema and tmp + directories to mode 777. + Updated the internet news gate documentation. + + msgbase.a: + Now creates all JAM files with mode 0666. + + mbcico: + The binkp driver skipped aka's when the node number + was zero. + Changed on hold logmessage. + + mbfido: + When forwarding a netmail, a temp file was closed twice, + this caused a segfault on glibc-2 systems. + In the logfile areamgr notify messages had the same orgin + and destination address. + + mbsed: + Changed the signal handlers. It will now allways try to + cleanup lost clients. It will also not hang anymore when a + client aborts for 10 minutes and use 100% cpu time. + + mbsebbs: + Changed logging in filearea select. + Permanent removed download checktime function, this was + already off. + Added error logging for setting filearea 0 during logoff. + Only netmail replies via an internet gate are now readressed + to a UUCP address. + + +v0.33.14 03-Jul-2000 + + upgrade: + Read this section carefully!!! This is a large update. + Backup the whole BBS configuration. + Compile and install all programs. + Kill -9 pid of mbsed. Restart mbsed. + Delete file ~/var/mailer.hist + Delete in all outbounds the *.sts files. + Start mbsetup, set item 1.5.14 if you want new users to + get an email box, you should do this. + Set 1.13.4, 1.13.5 and 1.13.6 to the node where the pop3, + smpt and nntp servers are, normally this is "localhost". + Set 1.13.10 to the Fidonet aka you will use for incoming + and outgoing email via the Fidonet UUCP gate. + Set 1.13.11 to the node address of the Fidonet UUCP gate. + Set 1.13.12: use "No ISP" if you dont't have internet + access, you will then use the default Fidonet UUCP gate. + Set it to "Dial ISP" if you connect sometimes to the internet + of have a cable modem without a DNS entry. Set it to + "Perm ISP" if you have a permanent connection to the internet + and you system has a valid DNS name. + With mbsetup open the userbase, close it and answer yes to + the save question. If you want existing users to have + private email, set 15.36 for each user to yes. You should + do this to accept email from the UUCP gate. + Open the message areas setup (9.2), exit and answer yes to + the save question, this will update this database. + Remove any existing email areas in the normal mail setup, + menu 9.2 (you should not have had any yet). + With mbsetup open menu 16, this will add the default services + database. Add entries as needed. + With mbsetup open menu 17, this will add the default domain + translate database. Insert entries as needed. Move the new + entries so that the .fidonet .ftn translation is the last + entry. + Go back to the start of this section and check! + + general: + Introduced users private email. Each user has (if set) three + email boxes: mailbox, archive and trash. + New system settings GiveEmail, POP3 host, SMTP host, Email Aka, + UUCP gate aka and Email mode. + New menus for email: 216 Read email, 217 Post email, 218 Trash + email, 219 Choose mailbox, 220 Quickscan email. + New user settings Email and plain password. + All users can now have private email boxes. + In normal mail areas you can't create email boards anymore. + Some documentation is updated for new features and some + changes are made to explain some things better. + Added a services database. These are mail accounts that can + perform certain actions. + Added domain translation database, this will translate fido + domains to internet domains and back. + Changed the message areas to contain newsgroups information. + + common.a: + The nodelist lookup function didn't recognize the internet + protocol flags followed by a colon and portnumber. + Move some functions from mbfido and mbmsg in here. + Added characterset convertor from ifmail. It uses the same + maptabs. + Moved some other functions into this library. + + mbinet.a: + New library, internet protocol interfaces. Has interfaces + to SMTP, NNTP and POP3 protocols. + + msgbase.a: + The MsgIdCRC and ReplyIdCRC values were not set in the message + headers. + Added protection for too long subfield strings. + Made some stringlengths longer, following JAM specs. + + clcomm.a: + When closing the server connection the autorisation table will + now be freed before the program ends. + + mbcico: + During binkp calls the mailer history wasn't filled with + session information. + Some system names were too long for the history info. + Will now properly initialize the mailer history file when it + doesn't exist. + With incoming calls the "Node not in setup..." debug log + message at startup is supressed. + Will send netmail with Immediate flag set allways. + Will now also poll non-CM systems outside ZMH. You should + know what you are doing! + The format of the outbound .sts files is changed to prevent + problems on Sparc systems. + Made the FTS-0001 sessions work again. + With outbound sessions the RH1 link option is set. + If a file is received and there is alread an empty file with + the same name, that one is removed to prevent filename extension + bumping. This may be a leftover from a previous failed session. + + mbout: + Won't create polls for nodes not in the nodelist, nodes that + are Down or Hold. Removing polls is always possible. + When multiple polls on the commandline are given, if one of + these nodes is down/hold, then all other polls are still + created. + When creating a poll for a non-CM node outside ZMH, a warning + is given and written in the log. + Added the fileattach command. + The format of the outbound .sts files is changed to prevent + problems on Sparc systems. + + mbfido: + In the rollover function the mailer history is truncated each + month. The current and previous month records stay. + When forwarding .tic files, the files are now attached to the + routevia address if this is set for a node. + Processes scanning of netmail with the immediate flag set. + Added more debugging info for the scan function. + Uses the services database to decide incoming netmail to handle + by AreaMgr, FileMgr or Email. + Moved some functions to common.a + Configuration errors found during mailscan are now logged. + Removed a small memory leak from the magic manager. + Added experimental email import from a FTN UUCP gateway. + The AreaMgr now refuses to disconnect a node who is cutoff from + an mail area to prevent reconnection. + If from a received tic file the accompaning file is missing in + the inbound the errormessage will now say that instead of the + wrong message "Permission denied". + + mbsetup: + In edit fido aka's when you remove a secondary nodelist the aka + is now automatic erased. + The line editor now checks if a line only contains spaces, if + so, the line is returned erased. Trailing spaces are still + possible! + Added global settings and user settings for the new options. + Added 5 new menu choices, Post Email, Read Email, Trash Email, + Choose Mailbox and Quickscan Email. + Added setup for the services database. + Added setup for the domain translation database. + Corrected some sitedocs chapters numberings. + Added setup parameters for news in the message areas editor. + For new installations there will now be a default system + location filled in. This will prevent "mbstat open" to hang + for sysops that didn't do proper system setup. + + mbmsg: + The post function created the semafore scanout instead of + mailout. + Moved some functions to common.a + Messages written with GoldED were deleted by age because some + GoldED versions don't set the Processed date. + + mbsebbs: + Added DoNop() to message read function to prevent losing the + connection with mbsed with long messages. + Added netmail Immediate option for non CM nodes. + Replaced some hardcoded prompts by language prompts. + Duplicate phonenumbers check is finally working. + Added better check for personal mail. + The messagearea overview now also counts messages written by + the user as personal messages. + Changed the newuser function to set system and bbs password + in one function so the user creates the password only once. + During normal login (via user bbs) the plain user password is + stored in the userbase. This will not work with Unix login. + New textcontrolcode: Control-K + N, current e-mail mailbox name. + Updated the change password menu command to use the new + mbpasswd wrapper. + If a user decided to Quit check for newmail, the bbs crashed + with a segfault. + Will not insert Re: in the subject of the subject contained a + Re^2: produced by GoldED. + Patched the fullscreen editor with code from Johannes Lundberg + to correct the "invalid screencoordinates" problem. + Adds the ^aCHRS kludge with CP437. + Will now free the server authorisation tables on exit. + The users plain password is now written to door.sys + + mbsed: + Removed the fsync calls in the logfile write functions, + it never did any harm and the fsync calls do really slowdown + the system. + The locking functions only waited for 2,5 second instead of 15. + + mbpasswd: + New wrapper, sets a new password for a user from the + commandline. + + mbuseradd: + Doesn't ask the user for a new Unix password anymore, mbpasswd + is used instead to set the password. + + lang: + Added 10 new language prompts, 461 upto 470. + Changed language prompts 39, 40 and 388. + + mblang: + Corrected a bug reported by Johannes Lundberg (2:206/149). + + mbuser: + Will now remove blank records at the end of the database. + + mball: + The index function now translates the characterset from CP437 + to ISO-8859-1. + + mbdiff: + Removed a small memory leak. + + mbindex: + Writes an error in the logfile when no nodelist is defined for + a network that is defined in the network setup. Processing of + all other lists will be completed. + + mbmon: + Will now free the server autorisation table at exit. + + mbmail: + New program, use this to replace ifmail from the ifmail package + for the email gateway if you had that installed. If it is then + it's probably configured in /etc/sendmail.cf or whatever other + MTA you are using. + + +v0.33.15 08-Oct-2000 + + upgrade: + After installing the new binaries kill mbsed. Start mbsed. + Start mbsetup, open global menu 1, exit and save. This will + set the default value for newsarticles dupe database size. + Set the real news areas to the type News instead of Echomail. + Copy mbsebbs-0.33.15/script/run_inout to $MBSE_ROOT/etc + Compile the nodelists again with mbindex. + + general: + All version information for the sources now comes from the + generated file config.h + Tested on Slackware 7.1 (i386) and Debian 2.2 potato (Sparc). + Changed the SS() macro to MBSE_SS() to prevent conflicts + with system libraries. + Changed the way debug logging is, see the file DEBUG for + details. + Updated the ftscprod list with version 006 of 22 jan 2000. + I dared to ask for a product code with the FTSC commitee. + Removed the McMail.bug file from the distribution because + later releases (after 1.0) don't have problems anymore with + EMSI handshake. + Added nodelist capability flag IFT for future extension. + Added forgotten nodelist capability flag Z19. + Changed the analogue modems priority. + + lib: + When there was more then 6 Gig diskspace free, several programs + complained about negative diskspace available. + The logger now registers the /dev/pts/n devices correct. + Changed the logger for the new debug way of logging. + The logger is now protected for stringlength overflow. + + mbfido: + When exporting echomail all system aka's in the same zone are + now added to the SEEN-BY lines. + Experimentail newsgroup postings from local posted echomail + and received echomail. + Now closes active SMTP and NNTP servers only once if they have + been used instead of opening and closing for each message. + The filemover now creates destination directories if they don't + excist. + Added patches from Redy Rodriguez of 2:283/613.6: + . Added %RESCAN and %MSGS to the Areamgr. + . It also fixes two bugs in %QUERY: it incorrectly listed the + linked areas (I have added the great totals at the end of + answers to %QUERY and %LIST); and it also corrects its not + recognizing the area tag if you ask for it in lower case + letters (should always be in upper case). + . The AREA: kludge in echomail is now only tested if it is the + first line of the message. + . Added the message area autocreate function. See the manual + for details how to set it up. + mbfido now creates MBSE-FIDO ^aPID and ^aTID kludges. + Crashmail to points will be sent to their boss node. + Sending email now uses the mkrfcmsg function. + Incoming .pkt files not ending with a zero word are now + processed as if they were ok. The will not end up in the bad + directory anymore. + In magic unpackfile for test there is now an calloc for the + cwd buffer to see if that removes a NULL pointer free'd error. + + SETUP.sh + Added extra check for Slackware systems. Since 7.0 there is + an extra check needed to prevent detecting a Mandrake system. + Corrected a minor typo for Debian startup script. + + mbsetup: + The PickAka function loaded the global setup again when + editing the global setup so you did loose all recent changes. + Added a menu entry in menu 1.13 to set the size of the news + articles dupes database. + In screen 9.2 changed the order of fields 19, 20, 21 and 22 + because item 8. got partly overwritten by linewrapping. + + mbsed: + Corrected the data given for disk statistics for large disks. + The log function now prints all characters to the logfile. + + mbsebbs: + New users have now default the fullscreen message editor. + Added patches from Redy Rodriguez of 2:283/613.6: + . Changed language prompts 136...141 and added 471. Changed + the timestatistics output in funcs4.c for the changed + language prompts. It is now full international. + mbsebbs now creates MBSE-BBS ^aPID kludges. + It is now possible to reply crash to points by testing the + status of the bossnode. Also crash posting to points is + now possible. + Changed some debugging code of the fullscreen editor. + Message reading on Sparc systems works again. + The offline reader functions Tag areas, Untag areas and View + tags will now display the more/y/= prompt when the listings are + longer then the screenlength. Patches by Redy. + When posting a news article the To: field is automatic filled + with "All". + Postings to email and newsgroups now add some RFC headers for + mbfido to process. The style of GoldED is used. + + mbcico: + mbcico now creates MBSE-CICO ^aPID kludges. + The binkp transmitter now sends a zero length dataframe after + the transmitted file to all mailers except mbcico. + Removed a small bug in EMSI handshake routine. + Revised modem7 timeouts. Corrected checksum error for first + time receive of filename. + Did final testing for FTS-0001 sessions, a lot of bugs are + repaired. Note that most of them may be present in ifcico. + In a FTS-0001 session wazoo filerequests are also honored. + Sometimes received wazoo requests were renamed to temp + filenames and not responded to. + Corrected the helpscreen for the TCP/IP modes. + Improved the random dial delay time generation. + + mbmon: + The logger now registers the /dev/pts/n devices correct. + + mbchat: + Patches for new device pty names by Redy Rodriguez. + + fbutil: + New utility written and maintained by Johannes Lundberg, + 2:206/149@fidonet, . + + run_inout: + Changed this script to check for the inbound/bad directory, + if it doesn't excist it is created. + Removed all old news/email gateway stuff. + The goldnode compiler is called if it is in $MBSE_ROOT/bin. + + +v0.33.16 07-Jan-2001 + + upgrade: + Edit the crontab to comment out the lines with run_inout, + mailer and mbstat check. + Compile the sources. + Stop the bbs, kill mbsed. + Install the new binaries. + Start the bbs as root with the new init script. It will be + in some init.d subdirectory depending on your distribution. + If you can't find it, reboot. + If you want to start using the newsgate, run mbfido news -learn + the first time to learn which articles there are. + Edit menu item 1.14.3 and check that it's empty if you don't + use it. + + CRON.sh: + Removed the lines that ware replaced by the mbtask program. + + SETUP.sh + Changed binkd into binkp because binkp is the official protocol + name. + Corrected a problem installing on a system without shadow + passwords. + Removed the part where the init scripts are installed. They + are now in a new script in the script directory. + + clcomm.a: + New function Syslogp, to log unformatted strings, the normal + formatted string logfunction did hang sometimes when logging + strings containing the % character. + Improved some error messages in the NNTP and SMTP connections. + + common.a: + Protected uniq_list and sort_list against NULL pointers. + Handles the error strings now if there is a $ at the start + of an logstring. This was only in the daemon but that didn't + give the right errorstrings. Nobody noticed this error has + been here from the beginning. + Protected the chkftnmsgid function from NULL input. + + libdbase.a: + Dupe checking databases are now loaded in memory when needed + and written to disk only once when ready. + + general: + Two new global switches, don't regate and allow control + messages. + Changed the maptab cp437__iso-8859-1 to translate 8bits dos + graphics to 7bits characters to make all fancy dos like + textboxes more readable on Unix systems. + New setup parameters for UUCP newsfeeds. + Added support for the PPC cpu. + + mbtask: + New daemon. Takes over the functions of the run_inout and + mailer scripts. This program launches every program needed + to run the bbs. It will also check Zone Mail Hour. + + mbsed: + Corrected a spelling error in the program header. + Made the userlog full transparant. + Fixed a memory leak in the userlog function. + Changed file locking of mbsed status files to use fcntl() + instead of placing lockfiles. + + mbfido: + Protected the rfcmsgid function against NULL input. + Build some protection against too long lines in ftn messages + that were gated from rfc and regated to news. + Removed a lot of #ifdef statements for gating behaviour and + made a lot of code permamenent. + Original code for #ifdef ALLOW_CONTROL and DONT_REGATE is now + under control of configuration settings. + Forwarded files had an old copyright message in the tic files. + When sending messages to the SNMP or NNTP servers a line with + only a dot in it will be sent as a space and a dot to prevent + that the server thinks it's the end of the message. + When sending or forwarding messages to a destination with a + routevia address, the arcmail will be packed with the flavor + of the new destination node. + Magic execute uses the exec call now instead of the system + call, the programs to execute must now be in MBSE_ROOT/bin or + it will fail. + If a MSGID is missing the dupecheck includes the message text + in the dupecheck. (Redy). + Local posted echomail gated to news has now the right From: + address format and the right UTC time. + Imported news messages had an AREA: line in the message text. + Gating news to echomail doesn't crash anymore. Fixed several + bugs to make this finally work. + During gating news to echomail the mbmon program now displays + what is going on. + Added usleep code during news scanning. + The program is now installed setuid mbse and setgid bbs. This + allows it to be called by other users as mbse. + New commandline, uucp. This allows mbfido to process incoming + uucp newsbatches. Call it from uucp by: + cat newsbatch | /opt/mbse/bin/mbfido uucp -quiet or + cat newsbatch | /opt/mbse/bin/mbnews + It will handle compressed and uncompressed newsbatches. + If a scanned netmail should be send via your own UUCP gate, the + message will be handled further by the ExportEmail function. + All other UUCP destinations will be send via the remote UUCP + systems. + News articles that need to be send via NNTP are now first stored + in a temporary file. At the end of the mbfido run it will try + to post these articles. If it fails (newsserver down), the temp + file stays for a later try. + Added newsserver options for submitting articles via rnews and + to an UUCP remote host. + Added alias database again that was in the original ifmail. + Made a universal email post function. + Removed sourcefiles addos.*, they were not used. + If in configuration the root for the html pages is blank, then + no html pages will be created. + Netmail send to "ping" are bounced back to the sender if your + system is the final destination. If such a netmail is passing + thrue, the receiver is notified (trace). All ^aVia lines are + added to the replies. Systems running MBSE 0.33.16 and up may + now add the PING flag to the nodelist. + + mbmail: + If there is no Organization header, the BBS default origin + line will be used. + Removed a lot of #ifdef statements for gating behaviour and + made a lot of code permamenent. + Original code for #ifdef ALLOW_CONTROL and DONT_REGATE is + now under control of configuration settings. + The packet routing is now determined using the mail tracker. + The point of splitting large messages is now set at the point + from the setup instead of hardcoded at 12 Kbytes. + The program is now installed setuid mbse and setgid bbs so that + braindead MTA's can still deliver mail to the Fidonet. + Mail for users at your own bbs is now imported into the netmail + board. + Added REPLYTO: REPLYADDR: and MSGID: kludges if these where + not yet present in the message. + Added alias database again that was in the original ifmail. + + mbsetup: + In menu 1.13 added allow control and don't regate setup. + In all menus the default prompt selection is now "-" instead + of "0", so just pressing enter will leave from a menu. + When editing a new message area the area is automatic made + active when you assign a group to the area. + Most databases now create default records the first time. + The sitedoc pages for the tty lines were to big for each + printed page. + Splitted menu 1.13 in a Fidonet and Internet part, added setup + parameters for UUCP newsfeeds. + In the services setup the UUCP/Email entry is now added for + first time installations. + + mbmon: + In all menus the default prompt selection is now "-" instead + of "0", so just pressing enter will leave from a menu. + + mbout: + Fixed the helpscreen. + + mbstat: + Removed the check command, this is now done by the mbtask + daemon. + + mbcico: + Doesn't use tmpnam anymore during execute magic request. + The openfile function doesn't use tempnam anymore if a filename + is created after 62 name bumps. + When searching for a matching aka and your first aka is + disabled the first active aka is used as default. + The closefile function doesn't use the tempnam function anymore. + + mbsebbs: + When posting news articles when not permament connected to the + internet, the From address will be Fido style. + Messages for offline packets are now packed using the + following tests: + - If area is netmail then only personal messages are + included (unchanged). + - If area is not netmail, and msg-kinds are private then + only personal messages are included. + - If area is not netmail, and msg-kinds are both (pvt/pub) + then personal messages and messages without pvt flag are + included. + - Otherwhise all messages are included in the packet. + Removed debug messages for the POP3 protocol. + + mbpasswd: + Fixed a compile problem on systems without shadow passwords. + Thanks to Mario Mure. + Corrected a missing library in salt.c + Corrected a missing conditional header file in encrypt.c + + mbmsg: + Wrote wrong CHRS kludge in the post function. + + mbfile: + Warns about empty file areas during kill files. + + +v0.33.17 21-May-2001 + + upgrade: + Compile the sources. + Stop the bbs using the init script mbsed as root: + Slackware 7.0 and older: /opt/mbse/etc/rc.shutdown + Slackware 7.1 and newer: /etc/rc.d/init.d/mbsed stop + RedHat and Mandrake: /etc/rc.d/init.d/mbsed stop + SuSE: /sbin/init.d/mbsed stop + Debian: /etc/init.d/mbsebbs stop + Install the new programs. + Start the bbs using the examples above and use the word start. + Use mbsetup menu 1.18 to change the Zone Mail Hour if you are + not in Fidonet zone 2. + + general: + The daemon mbsed is now obsolete, all these functions are now + in the mbtask daemon. For client/server communications Unix + Datagram sockets are used instead of TCP stream sockets. + Italian language added, translated by nervous@nervous.it + Spanish language added, translated by Redy Rodriguez. + JAM messagebase locking is now according to the JAM specs. + + docs: + Added fsc-0088, fts-4001 and a page to describe the use of a + UPS with MBSE BBS. + Updated documentation to show all changes. + Added in file area setup and message area setup the description + of the global commands. + + SETUP.sh: + Removed installing mbse as port in /etc/services + + common.a: + The diskfree check now ignores a mounted filesystem at /boot + because that filesystem is usually small and not needed by + mbse. + The diskfree check should support reiserfs now (not tested). + Code and logging cleanup in packet.c + + dbase.a: + Removed debug logging from the dupes databases. + + mbinet.a: + When an NNRP server asked for authentication after the first + command instead of after connect, the user authentication + wasn't started. + + mbsed: + Obsolete and removed. + + mbtask: + Does all things mbsed used to do, it uses Unix Datagram sockets + to communicate with the clients. + If IP addresses to test are entered in the setup it will check + if the internet connection is available with ICMP ping. + Added Internet connection status, system running status and + system load average to the GSTA command for mbmon. + Create's the file ~/etc/config.data if it doesn't excist and + fills it with default parameters. + Note: the internet connection status is for future use. + + mbfido: + The pktdate logresult is now only displayed if there was + something wrong. + The Checkdupe fallback logmessage is removed. + Corrected a small bug in the news to echomail gate to get the + correct replyto and replyaddr kludges in the messages. + Changed the tosspkt messages read functions back to the way it + was so the namefield may be exactly 36 characters long excluding + the null terminator. + The PING function didn't work if the message came from a node + not in the setup. + The PING reply now has a Re: prepended. + The scannews function now acts better on nntp error conditions. + Local posted echomail dropped the subject when it was gated to + news. + If imported netmail doesn't have a FMPT kludge and there is + pointinfo in the MSGID line, the pointinfo is taken from the + MSGID line. + Improved the TRACE message of the PING function to make it + more clear that it is a TRACE message. + The PING reply now uses the aka from address that was original + the destination address instead of the matched aka in the + reply message. + Added a hack to try to process .tic files that are not lowercase + filenames. + Added support for a system alias file to convert fidonet + addresses to RFC addresses. + In the mbnews function the tests for the headers Newsgroups: + and Message-ID: are now case insensitive. + File attaches with the leave case option set did not get the + TFS or KFS flags set in the attachement. + + mbdiff: + Removed some debugging logmessages. + + mbfile: + Removed some unnecessary logmessages. + + mbmon: + When viewing the bbs lastcaller list the clock wasn't updated. + The commandline option doesn't work anymore because we + now use Unix Datagram sockets to communicate with the server, + so we must be on the same system. + Added Internet status, running status and system load average + to the Server Statistics screen. + Minor adjustments to the screen layout of the Filesystem Usage + screen. + + mbindex: + Sends the correct IsDoing information to mbtask during sort and + write. + + mbsetup: + Added setup screen for the task manager. + Some menus didn't have the default "-" character in the prompt. + The language setup now adds Italian and Spanish on new + installations. + In main system aka's shortened the domain names from 12 to 11 + characters length to prevent SIGSEGV in mbsetup. + Improved help messages when editing aka's. + Corrected chapter numbering in sitedoc. + Changed page layout sitedoc 8.1 + Removed initialisation of ~/etc/config.data, this is now in + mbtask. + In golded.inc AKAMATCHECHO is no YES. + In golded.inc writing the AKAMATCH aka's other then fidonet + didn't really match the aka's, the main aka was written instead. + + mball: + Removed two redundant log messages. + + mbmail: + The program wrote mbfido instead of mbmail in the logfile. + + mbsebbs: + During login with two names the second name now also checks + for empty responses from the user. + Removed some IEMSI debugging messages. + Removed the timeleft debug message. + Removed logmessage if no newfiles were found. + Removed rendunant log message abount start newfiles scan. + Removed logmessage if no newmail was found. + Removed debug email setarea message. + The list of languages to select is now divided in two columns. + The message to sysop function now doesn't quote and doesn't + write "Sysop wrote to ..." anymore. Thanks to Harald Wuensch. + The program now uses umask(007) instead of umask(000) + In the displayfile function the ^B syntax (show text above + sec. level) is now: ^B^B^B without + the < and > characters. Thanks to Harald Wuensch. + Removed (press enter to Quit) from language prompt 379 since + there is no default choice. + Adjusted a lot of strings for filenames and paths to PATH_MAX + in stead of 80 characters length. + Moved the Nopper call in the fullscreen editor to a place were + it always should work. + + mbcico: + The session debug logmessages are set to the special loglevel. + Implemented EMSI-II, FSC-0088. + When calling a TCP/IP node with hostname in nodelist system + name and a valid phonenumber, and if the hostname could not + be resolved, mbcico would dialout and try to establish a + TCP/IP session over the modem connection. Now the TCP/IP + flags are cleared and mbcico will fallback to valid old style + phone sessions. + In binkp added the M_NUL PHN and M_NUL OPM to log if they are + received from the remote. We also send these flags. + In binkp we now always send and empty dataframe after a file + is sent, most binkp implementations need this to detect EOF. + We don't log received empty frames anymore, we just drop them. + + mbpasswd: + Added check that username and password may not be longer then + 16 characters. + Fixed the error message on some systems about USERGROUPS_ENAB. + + mbuseradd: + Error messages now go to stderr. + Increased stringslength of some internal variables to PATH_MAX. + Check all arguments that they are no longer then 80 characters. + The user is now the owner of his homedir. In this homedir a + directory Maildir with subdirs cur, new and tmp are created, + also owned by the user. Some MTA's need this (Qmail). + Doesn't create the .hushlogin file anymore, not needed. + + mbmsg: + Now runs umask(007) + + mbuser: + If users at the end of the userbase are deleted and the database + should be truncated, these users were not removed from the Unix + system and their homedirectories weren't removed also. + Added a check to see if the sysop defined in the main config + also exists in the user database because these two must match. + + mbstat: + Added the semafore command to set internal mbtask semafore's. + + script/installinit: + Corrected a bug for Slackware 7.0.0 were the wrong initscripts + were installed. + + examples: + Replaced the internet menu and txtfiles with versions that work + with the current menu structure. + diff --git a/DEBUG b/DEBUG new file mode 100644 index 00000000..154ab8f5 --- /dev/null +++ b/DEBUG @@ -0,0 +1,31 @@ + Debugging with MBSE BBS. + +From version 0.33.15 I changed the way debug logging goes. There are no more +#ifdef .. #endif directives in the code that change the loging behaviour. +Lines that could be logged in the code for debug are now written in two +possible ways: + +Syslog('b', "This is always logged for debug"); +Syslog('B', "This is logged if most_debug flag is true"); + +The difference is the uppercase or lowercase logclass. Uppercase is only logged +if the global flag most_debug is set to true. If you want to use it in one of +the sources declare that flag like this: + +extern int most_debug; + +Then, from the moment you need the extra debugging, insert + +most_debug = TRUE; + +in the code, and set it to FALSE when you are done. + +I did this because the extra debug is good for developers but not for regualar +users that need some extra logging. The log output with the most_debug flag +set to TRUE can be huge and does affect system performance. + +For those who are developing code for MBSE BBS, use two kinds on debug logging. + + + Michiel Broek. + diff --git a/FILE_ID.DIZ.in b/FILE_ID.DIZ.in new file mode 100644 index 00000000..f0842fc0 --- /dev/null +++ b/FILE_ID.DIZ.in @@ -0,0 +1,23 @@ +-= MBSE BBS System v@VERSION@ for Linux =- +MBSE BBS is a full Fidonet capable ANSI bbs +package including a mailer (ifcico clone), +tosser, ticfile processor, filefind and other +utilities. +The bbs supports full configurable ANSI +menus, multiple languages, IEMSI, standard +file transfer protocols, native Linux doors +and BlueWave and QWK offline readers. +The mailer supports FTS-0001, YooHoo/2U2, +EMSI protocols over modem, TCP/IP IFC and +Binkd protocol. Zedzap, Zmodem, Telink and +Hydra file transfer protocols. Full FTN mail +support, including automatic routing for hub +and host systems. +Internal mail format is JAM (c) messagebase. +Full tic file support, including extended +tic files. Costsharing will be added later. +Originating sites 2:280/2802@fidonet and +http://mbse.sourceforge.net/ +Copyright by Michiel Broek. +Released under the terms of the GNU Public +License. diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..66812a54 --- /dev/null +++ b/INSTALL @@ -0,0 +1,251 @@ + New installation procedure. + --------------------------- + +The old initial system setup was a little tricky and didn't work on some +systems. This procedure is tested on Slackware, RedHat, Mandrake, SuSE and Debian. +I have not tested on other distributions. Installation is now done by a +script which will do the dirty work. This script can be executed once only, +unless you undo all changes the script has done. Basicly, if you already +have installed MBSE BBS, or there are parts left of an old installation, the +script will abort and inform you why. I hope this will give a better and more +universal setup on most distributions. + + + + Installing MBSE BBS for the first time. + --------------------------------------- + +Login as root and type the following commands to do the basic install: + +cd /tmp +tar xfvz /pathtopackage/mbsebbs-0.33.17.tar.gz +cd mbsebbs-0.33.17 +sh ./SETUP.sh + +This will setup a new directory structure /opt/mbse and create's some +necessary users. If this in successfull, logout and login as user "mbse". +To build and install mbse bbs type the following commands: + +cd +tar xfvz /pathtopackage/mbsebbs-0.33.17.tar.gz +cd mbsebbs-0.33.17 +./configure +make +su +[type rootpassword] +make install +exit +/opt/mbse/bin/mbtask + +The next step is to read the documentation in /opt/mbse/html with a browser. +After your system is configured and tested type "sh ./CRON.sh" to install +a default crontab for the bbs. + + + Upgrading MBSE BBS on a running system. + --------------------------------------- + +Login as user "mbse", backup your bbs configuration, and then type the +following commands: + +cd +tar xfvz /pathtopackage/mbsebbs-0.33.17.tar.gz +cd mbsebbs-0.33.17 +./configure +make +su +[type rootpassword] +make install +exit + +Read the ChangeLog file for update instructions from the version +you were running and the version you have just installed over the old +version. Perform the upgrades step by step, version by version. + + +Next the instructions for the standard GNU installation programs: + + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/opt/mbse/bin', `/opt/mbse/etc', etc. You can specify an +installation prefix other than `/opt/mbse' by giving `configure' the +option `--prefix=PATH'. This is NOT ADVISED for MBSE BBS!!! + + 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.in b/INSTALL.in new file mode 100644 index 00000000..b3b5ff30 --- /dev/null +++ b/INSTALL.in @@ -0,0 +1,251 @@ + New installation procedure. + --------------------------- + +The old initial system setup was a little tricky and didn't work on some +systems. This procedure is tested on Slackware, RedHat, Mandrake, SuSE and Debian. +I have not tested on other distributions. Installation is now done by a +script which will do the dirty work. This script can be executed once only, +unless you undo all changes the script has done. Basicly, if you already +have installed MBSE BBS, or there are parts left of an old installation, the +script will abort and inform you why. I hope this will give a better and more +universal setup on most distributions. + + + + Installing MBSE BBS for the first time. + --------------------------------------- + +Login as root and type the following commands to do the basic install: + +cd /tmp +tar xfvz /pathtopackage/@PACKAGE@-@VERSION@.tar.gz +cd @PACKAGE@-@VERSION@ +sh ./SETUP.sh + +This will setup a new directory structure /opt/mbse and create's some +necessary users. If this in successfull, logout and login as user "mbse". +To build and install mbse bbs type the following commands: + +cd +tar xfvz /pathtopackage/@PACKAGE@-@VERSION@.tar.gz +cd @PACKAGE@-@VERSION@ +./configure +make +su +[type rootpassword] +make install +exit +/opt/mbse/bin/mbtask + +The next step is to read the documentation in /opt/mbse/html with a browser. +After your system is configured and tested type "sh ./CRON.sh" to install +a default crontab for the bbs. + + + Upgrading MBSE BBS on a running system. + --------------------------------------- + +Login as user "mbse", backup your bbs configuration, and then type the +following commands: + +cd +tar xfvz /pathtopackage/@PACKAGE@-@VERSION@.tar.gz +cd @PACKAGE@-@VERSION@ +./configure +make +su +[type rootpassword] +make install +exit + +Read the ChangeLog file for update instructions from the version +you were running and the version you have just installed over the old +version. Perform the upgrades step by step, version by version. + + +Next the instructions for the standard GNU installation programs: + + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/opt/mbse/bin', `/opt/mbse/etc', etc. You can specify an +installation prefix other than `/opt/mbse' by giving `configure' the +option `--prefix=PATH'. This is NOT ADVISED for MBSE BBS!!! + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..f8e838f5 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = foreign dist-zip no-installinfo no-installman +EXTRA_DIST = COPYING DEBUG CRON.sh FILE_ID.DIZ.in README \ +README.GoldED SETUP.sh TODO UPGRADE files.css checkbasic + +SUBDIRS = @SUBDIRS@ + + +install-exec-local: + @./checkbasic + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(mkinstalldirs) $(prefix)/{bin,etc,etc/maptabs,doc,fdb,home,log,magic,sema,var,tmp} + $(mkinstalldirs) $(prefix)/{dutch,dutch/txtfiles,dutch/menus,dutch/macro} + $(mkinstalldirs) $(prefix)/{english,english/txtfiles,english/menus,english/macro} + $(mkinstalldirs) $(prefix)/{italian,italian/txtfiles,italian/menus,italian/macro} + $(mkinstalldirs) $(prefix)/{spanish,spanish/txtfiles,spanish/menus,spanish/macro} + chown @OWNER@.@GROUP@ $(prefix)/{bin,etc,etc/maptabs,doc,fdb,home,log,magic,sema,var,tmp} + chown @OWNER@.@GROUP@ $(prefix)/{dutch,dutch/txtfiles,dutch/menus,dutch/macro} + chown @OWNER@.@GROUP@ $(prefix)/{english,english/txtfiles,english/menus,english/macro} + chown @OWNER@.@GROUP@ $(prefix)/{italian,italian/txtfiles,italian/menus,italian/macro} + chown @OWNER@.@GROUP@ $(prefix)/{spanish,spanish/txtfiles,spanish/menus,spanish/macro} + chmod 777 $(prefix)/{sema,tmp} + $(mkinstalldirs) /var/spool/mbse + $(mkinstalldirs) /var/spool/mbse/{nodelist,unknown,inbound,outbound,badtic,ticqueue,ftp,mail} + chown -R @OWNER@.@GROUP@ /var/spool/mbse + chmod -R 755 /var/spool/mbse + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..30d9e12f --- /dev/null +++ b/Makefile.in @@ -0,0 +1,395 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +AUTOMAKE_OPTIONS = foreign dist-zip no-installinfo no-installman +EXTRA_DIST = COPYING DEBUG CRON.sh FILE_ID.DIZ.in README README.GoldED SETUP.sh TODO UPGRADE files.css checkbasic + + +SUBDIRS = @SUBDIRS@ +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = INSTALL FILE_ID.DIZ +DIST_COMMON = README ./stamp-h.in AUTHORS COPYING ChangeLog \ +FILE_ID.DIZ.in INSTALL INSTALL.in Makefile.am Makefile.in NEWS TODO \ +acconfig.h acinclude.m4 aclocal.m4 config.guess config.h.in configure \ +configure.in install-sh missing mkinstalldirs + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(ACLOCAL_M4): configure.in acinclude.m4 + cd $(srcdir) && $(ACLOCAL) + +config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +config.h: stamp-h + @if test ! -f $@; then \ + rm -f stamp-h; \ + $(MAKE) stamp-h; \ + else :; fi +stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=config.h \ + $(SHELL) ./config.status + @echo timestamp > stamp-h 2> /dev/null +$(srcdir)/config.h.in: $(srcdir)/stamp-h.in + @if test ! -f $@; then \ + rm -f $(srcdir)/stamp-h.in; \ + $(MAKE) $(srcdir)/stamp-h.in; \ + else :; fi +$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f config.h + +maintainer-clean-hdr: +INSTALL: $(top_builddir)/config.status INSTALL.in + cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status +FILE_ID.DIZ: $(top_builddir)/config.status FILE_ID.DIZ.in + cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive install-info-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + -rm -rf $(distdir) + GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) dist + -rm -rf $(distdir) + @banner="$(distdir).tar.gz is ready for distribution"; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +dist-zip: distdir + -chmod -R a+r $(distdir) + zip -rq $(distdir).zip $(distdir) + -rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + zip -rq $(distdir).zip $(distdir) + -rm -rf $(distdir) +distdir: $(DISTFILES) + -rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-info-am: +install-info: install-info-recursive +all-recursive-am: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile config.h +all-redirect: all-recursive-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-hdr clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-hdr distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + -rm -f config.status + +maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + -rm -f config.status + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +install-data-recursive uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-info-am \ +install-info all-recursive-am install-exec-local install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs-am \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +install-exec-local: + @./checkbasic + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(mkinstalldirs) $(prefix)/{bin,etc,etc/maptabs,doc,fdb,home,log,magic,sema,var,tmp} + $(mkinstalldirs) $(prefix)/{dutch,dutch/txtfiles,dutch/menus,dutch/macro} + $(mkinstalldirs) $(prefix)/{english,english/txtfiles,english/menus,english/macro} + $(mkinstalldirs) $(prefix)/{italian,italian/txtfiles,italian/menus,italian/macro} + $(mkinstalldirs) $(prefix)/{spanish,spanish/txtfiles,spanish/menus,spanish/macro} + chown @OWNER@.@GROUP@ $(prefix)/{bin,etc,etc/maptabs,doc,fdb,home,log,magic,sema,var,tmp} + chown @OWNER@.@GROUP@ $(prefix)/{dutch,dutch/txtfiles,dutch/menus,dutch/macro} + chown @OWNER@.@GROUP@ $(prefix)/{english,english/txtfiles,english/menus,english/macro} + chown @OWNER@.@GROUP@ $(prefix)/{italian,italian/txtfiles,italian/menus,italian/macro} + chown @OWNER@.@GROUP@ $(prefix)/{spanish,spanish/txtfiles,spanish/menus,spanish/macro} + chmod 777 $(prefix)/{sema,tmp} + $(mkinstalldirs) /var/spool/mbse + $(mkinstalldirs) /var/spool/mbse/{nodelist,unknown,inbound,outbound,badtic,ticqueue,ftp,mail} + chown -R @OWNER@.@GROUP@ /var/spool/mbse + chmod -R 755 /var/spool/mbse + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..e69de29b diff --git a/README b/README new file mode 100644 index 00000000..193a4492 --- /dev/null +++ b/README @@ -0,0 +1,24 @@ + MBSE BBS Packages. + + +Distribution naming scheme: + +mbd0_30a.tgz +^^^^ ^^^ + ||| || + ||| |+---- Alpha, Beta, Gamma or none for stable version. + ||| +----- Minor version number (2 digits). + ||+-------- Major version number. + |+--------- Package type, see next section. + +---------- Always mb (2 alpha characters). + +Package types: + + b - The complete MBSE BBS package, including mailer and utilities. + i - Internet <> Fidonet gateway software. + p - Pointlist processing software. + + +Note that for distribution via Fidonet Technology networks the naming scheme +is restricted to dos 8.3 conventions, while longer names would be nicer. + diff --git a/README.GoldED b/README.GoldED new file mode 100644 index 00000000..86c25345 --- /dev/null +++ b/README.GoldED @@ -0,0 +1,90 @@ + README for GoldED users. + + +Since MBSE BBS version 0.33.12 GoldED and MBSE BBS can be used together +without problems as long as you use it to read the sysop mail. The +mbsetup program can export a file called /opt/mbse/etc/golded.inc which +will contain your main Aka's, Aka matching, sysop name and all your mail +areas. This file is only (re)created if you change the global settings or +one of the mail areas. The first time you must force this by making a change +somewhere. + +Now create /opt/mbse/etc/golded.cfg, here is what I wrote: + +; GoldED.cfg +; +; Internet Addressing +; +INTERNETADDRESS Michiel_Broek@f2802.n280.z2.fidonet.org +INTERNETGATE UUCP 2:292/875 +; +; +OUTBOUNDPATH /SYS/usr/mail/out +REPLYLINK chain +STYLECODES yes +; +; +; MESSAGE READER +; +DISPMSGSIZE KBYTES +DISPATTACHSIZE KBYTES +DISPLOCALHIGH YES +DISPPAGEBAR YES +VIEWHIDDEN YES +VIEWKLUDGE NO +VIEWQUOTE YES +; +INCLUDE /opt/mbse/etc/golded.inc +; +; The end. + +Put in /opt/mbse/.profile the following line: +export GOLDED=$HOME/etc + +When you now start GoldED you use it as the sysop. Make sure that the sysop's +userrecord is the first user in the MBSE BBS userbase. If not, the lastread +pointers are not right. + + +Compile instructions for GoldED 3.0.1 written by Johannes Beekhuizen, 2:280/1018 + +* Unpack the sources in some directory (/tmp): + cd /tmp + tar -zxvf ???/ged_301.tgz + This will create a directory golded-3.0.1, so if you did this in /tmp then + there is now a directory called /tmp/golded-3.0.1 which will be called + from now on. +* Set the environment variables GSRC, GOBJ and GLIB to basedir. In a bash + shell this is: + export GSRC=/tmp/golded-3.0.1 + export GOBJ=/tmp/golded-3.0.1 + export GLIB=/tmp/golded-3.0.1 +* Build the program 'gbuild': + cd /gbuild + make lnx + cp gbldnx /opt/mbse/bin + The location of gbldlnx is not important, as long as it is in your PATH. +* Create the directories needed for compilation and installation: + cd /goldlib + make install +* Next build GoldED: + cd /goldlib/gall + make lnx + cd /goldlib/gcfg + make lnx + cd /goldlib/gmb3 + make lnx + cd /golded3 + cp mygolded.__h mygolded.h + Edit the file mygolded.h to suit your own taste. + make lnx + strip gedlnx + cp gedlnx /opt/mbse/bin +* Now build goldnode: + cd /goldnode + make lnx + strip gnlnx + cp gnlnx /opt/mbse/bin +* Example configurations and documentation are in /golded3/cfgs + and /golded3/docs. + diff --git a/SETUP.sh b/SETUP.sh new file mode 100644 index 00000000..a8eadb62 --- /dev/null +++ b/SETUP.sh @@ -0,0 +1,365 @@ +#!/bin/sh +# +# Basic setup script for MBSE BBS +# +# (C) Michiel Broek, v0.17 26-May-2001 +# +# Customisation section, change the next variables to your need. +# However, all docs refer to the setup below. +# +# Basic bbs root directory. +clear +MHOME=/opt/mbse +PATH=/bin:/sbin:/usr/bin:/usr/sbin: +DISTNAME= +DISTVERS= + +#------------------------------------------------------------------------ +# +# Logging procedure, needs two parameters. +# +log() { + /bin/echo `date +%d-%b-%y\ %X ` $1 $2 >> SETUP.log +} + + +#------------------------------------------------------------------------ +# +cat << EOF +MBSE BBS for Linux first time setup. Checking your system..." + +If anything goes wrong with this script, look at the output of +the file SETUP.log that is created by this script in this +directory. If you can't get this script to run on your system, +mail this logfile to Michiel Broek at 2:280/2802 or email it +to mbroek@users.sourceforge.net + +EOF + +echo -n "Press ENTER to start the basic checks " +read junk + +log "+" "MBSE BBS $0 started by `whoami`" +log "+" "Current directory is `pwd`" + + +# +# First do various tests to see which Linux distribution this is. +# +if [ -f /etc/slackware-version ]; then + # Slackware 7.0 and later + DISTNAME="Slackware" + DISTVERS=`cat /etc/slackware-version` +else + if [ -f /etc/debian_version ]; then + # Debian, at least since version 2.2 + DISTNAME="Debian" + DISTVERS=`cat /etc/debian_version` + else + if [ -f /etc/SuSE-release ]; then + DISTNAME="SuSE" + DISTVERS=`cat /etc/SuSE-release | grep VERSION | awk '{ print $3 }'` + else + if [ -f /etc/redhat-release ]; then + DISTNAME="RedHat" + DISTVERS=`cat /etc/redhat-release | awk '{ print $5 }'` + else + if [ -f /etc/mandrake-release ]; then + DISTNAME="Mandrake" + # Format: Linux Mandrake release 8.0 (Cooker) for i586 + DISTVERS=`cat /etc/mandrake-release | awk '{ print $4 }'` + else + if [ -f /etc/rc.d/rc.0 ] && [ -f /etc/rc.d/rc.local ]; then + # If Slackware wasn't detected yet it is version 4.0 or older. + DISTNAME="Slackware" + DISTVERS="Old" + else + DISTNAME="Unknown" + fi + fi + fi + fi + fi +fi + + +log "+" "Detected \"${DISTNAME}\" version \"${DISTVERS}\"" + +# Basic checks. +if [ `whoami` != "root" ]; then +cat << EOF +*** Run $0 as root only! *** + + Because some of the system files must be changed, you must be root + to use this script. + +*** SETUP aborted *** +EOF + log "!" "Aborted, not root" + exit 2 +fi + +if [ "$MBSE_ROOT" != "" ]; then + echo "*** The MBSE_ROOT variable exists: $MBSE_ROOT ***" + echo "*** SETUP aborted ***" + log "!" "Aborted, MBSE_ROOT variable exists: ${MBSE_ROOT}" + exit 2 +fi + +if [ "`grep mbse: /etc/passwd`" != "" ]; then + echo "*** User 'mbse' already exists on this system ***" + echo "*** SETUP aborted ***" + log "!" "Aborted, user 'mbse' already exists on this system" + exit 2 +fi + +if [ "`grep bbs: /etc/group`" != "" ]; then + echo "*** Group 'bbs' already exists on this system ***" + echo "*** SETUP aborted ***" + log "!" "Aborted, group 'bbs' already exists on this system" + exit 2 +fi + +if [ -f /etc/passwd.lock ]; then + echo "*** The password file is locked, make sure that nobody" + echo " is using any password utilities. ***" + echo "*** SETUP aborted ***" + log "!" "Aborted, password file is locked" + exit 2 +fi +clear + +if [ -d /opt ]; then + log "+" "Directory /opt already present" +else + mkdir /opt + echo "Directory /opt created." + log "+" "Directory /opt created" +fi + + +cat << EOF + Basic checks done. + + The detected Linux distribution is $DISTNAME $DISTVERS + + Everything looks allright to start the installation now. + Next the script will install a new group 'bbs' and two new + users, 'mbse' which is the bbs system account, and 'bbs' which + is the login account for bbs users. This account will have no + password! The shell for this account is the main bbs program. + + One final important note: This script will make changes to some + of your system files. Because I don't have access to all kinds of + distributions and configurations there is no garantee that this + script is perfect. Please make sure you have a recent system backup. + Also make sure you have resque boot disks and know how to repair + your system. It might also be wise to login as root on another + virtual console incase something goes wrong with system login. + + If you are not sure, or forgot something, hit Control-C now or +EOF + +echo -n " press Enter to start the installation " +read junk +clear + + +#------------------------------------------------------------------------ +# +# The real work starts here +# +log "+" "Starting installation" +echo "Installing MBSE BBS for the first time..." +echo "" +echo -n "Adding group 'bbs'" +groupadd bbs +log "+" "[$?] Added group bbs" +echo -n ", user 'mbse'" +useradd -c "MBSE BBS Admin" -d $MHOME -g bbs -G uucp -m -s /bin/bash mbse +log "+" "[$?] Added user mbse" +chmod 770 $MHOME +log "+" "[$?] chmod 770 $MHOME" + +echo -n " writing '$MHOME/.profile'" +cat << EOF >$MHOME/.profile +# profile for mbse +# +export PATH=\$HOME/bin:\$PATH +export MBSE_ROOT=\$HOME +export GOLDED=\$HOME/etc +# For xterm on the Gnome desktop: +cd \$HOME +EOF +echo "" +log "+" "Created $MHOME/.profile" + +# On some systems there is a .bashrc file in the users homedir. +# It must be removed. +if [ -f $MHOME/.bashrc ] || [ -f $MHOME/.bash_profile ]; then + echo "Removing '$MHOME/.bash*'" + rm -f $MHOME/.bash* + log "+" "Removed $MHOME/.bash* files" +fi + +echo "" +echo "Now set the login password for user 'mbse'" +passwd mbse +log "+" "[$?] Password is set for user mbse" + +echo -n "Adding user 'bbs'" +mkdir $MHOME/home +log "+" "[$?] Created directory $MHOME/home" +chown mbse.bbs $MHOME/home +log "+" "[$?] chown mbse.bbs $MHOME/home +chmod 775 $MHOME/home +log "+" "[$?] chmod 775 $MHOME/home +useradd -c "MBSE BBS Login" -d $MHOME/home/bbs -g bbs -s $MHOME/bin/mbsebbs bbs +log "+" "[$?] Added user bbs" +# Some systems (RedHat and Mandrake) insist on creating a users homedir. +# These are full of garbage we don't need. Kill it first. +if [ -d $MHOME/home/bbs ]; then + rm -Rf $MHOME/home/bbs + log "+" "[$?] Removed $MHOME/home/bbs" +fi +mkdir $MHOME/home/bbs +log "+" "[$?] mkdir $MHOME/home/bbs" +chmod 770 $MHOME/home/bbs +log "+" "[$?] chmod 770 $MHOME/home/bbs" +chown mbse.bbs $MHOME/home/bbs +log "+" "[$?] chown mbse.bbs $MHOME/home/bbs" +touch $MHOME/home/bbs/.hushlogin +log "+" "[$?] touch $MHOME/home/bbs/.hushlogin" + +echo ", removing password:" +echo -n "$$" >/etc/passwd.lock +if [ -f /etc/shadow ]; then + log "+" "Shadow password system" + # Not all systems are the same... + if [ "`grep bbs:\!\!: /etc/shadow`" != "" ]; then + sed /bbs:\!\!:/s/bbs:\!\!:/bbs::/ /etc/shadow >/etc/shadow.bbs + else + sed /bbs:\!:/s/bbs:\!:/bbs::/ /etc/shadow >/etc/shadow.bbs + fi + log "+" "[$?] removed password from user bbs" + mv /etc/shadow /etc/shadow.mbse + log "+" "[$?] made backup of /etc/shadow" + mv /etc/shadow.bbs /etc/shadow + log "+" "[$?] moved new /etc/shadow in place" + if [ "$DISTNAME" = "Debian" ] || [ "$DISTNAME" = "SuSE" ]; then + # Debian and SuSE use other ownership of /etc/shadow + chmod 640 /etc/shadow + chgrp shadow /etc/shadow + log "+" "[$?] Debian/SuSE style owner of /etc/shadow (0640 root.shadow)" + else + chmod 600 /etc/shadow + log "+" "[$?] Default style owner of /etc/shadow (0600 root.root)" + fi + echo " File /etc/shadow.mbse is your backup of /etc/shadow" +else + log "+" "Not a shadow password system" + if [ "`grep bbs:\!\!: /etc/passwd`" != "" ]; then + sed /bbs:\!\!:/s/bbs:\!\!:/bbs::/ /etc/passwd >/etc/passwd.bbs + else + sed /bbs:\!:/s/bbs:\!:/bbs::/ /etc/passwd >/etc/passwd.bbs + fi + log "+" "[$?] Removed password of user bbs" + mv /etc/passwd /etc/passwd.mbse + log "+" "[$?] Made backup of /etc/passwd" + mv /etc/passwd.bbs /etc/passwd + log "+" "[$?] Moved new /etc/passwd in place" + chmod 644 /etc/passwd + log "+" "[$?] Changed owner of /etc/passwd" + echo " File /etc/passwd.mbse is your backup of /etc/passwd" +fi +rm /etc/passwd.lock +echo "" + +if [ "`grep binkp /etc/services`" = "" ]; then + BINKD=TRUE +else + BINKD=FALSE +fi +if [ "`grep fido /etc/services`" = "" ]; then + FIDO=TRUE +else + FIDO=FALSE +fi + +log "+" "Services: binkp=$BINKD fido=$FIDO" + +if [ "$FIDO" = "TRUE" ] || [ "$BINKD" = "TRUE" ]; then + echo -n "Modifying /etc/services" + log "+" "Modifying /etc/services" + mv /etc/services /etc/services.mbse + cat /etc/services.mbse >/etc/services + echo "#" >>/etc/services + echo "# Unofficial for MBSE BBS" >>/etc/services + echo "#" >>/etc/services + if [ "$BINKD" = "TRUE" ]; then + echo -n ", binkp at port 24554" + echo "binkp 24554/tcp # mbcico IBN mode">>/etc/services + fi + if [ "$FIDO" = "TRUE" ]; then + echo -n ", fido at port 60179" + echo "tfido 60177/tcp # mbcico ITN mode">>/etc/services + echo "fido 60179/tcp # mbcico IFC mode">>/etc/services + fi + chmod 644 /etc/services + echo ", done." +fi + + +if [ "`grep mbcico /etc/inetd.conf`" = "" ]; then + echo -n "Modifying /etc/inetd.conf" + log "+" "Modifying /etc/inetd.conf" + mv /etc/inetd.conf /etc/inetd.conf.mbse + cat /etc/inetd.conf.mbse >/etc/inetd.conf +cat << EOF >>/etc/inetd.conf + +#:MBSE-BBS: bbs service +binkp stream tcp nowait mbse $MHOME/bin/mbcico mbcico -t ibn +tfido stream tcp nowait mbse $MHOME/bin/mbcico mbcico -t itn +fido stream tcp nowait mbse $MHOME/bin/mbcico mbcico -t ifc + +EOF + chmod 644 /etc/inetd.conf + if [ -f /var/run/inetd.pid ]; then + echo -n ", restarting inetd" + kill -HUP `cat /var/run/inetd.pid` + log "+" "[$?] restarted inetd" + else + log "!" "Warning: no inetd.pid file found" + fi + echo ", done." +fi + + +echo "" +echo -n "Press Enter to continue" +read junk +clear + +cat << EOF + The script made it to the end, that looks good. Before you logout do some + sanity checks; + + 1. Can you still login as a normal user. + + 2. Login on another virtual console, network or whatever as user 'mbse'. + Then type 'echo \$MBSE_ROOT'. Does this show the path to + '$MHOME' or nothing. + + 3. Login on another virtual console as user 'bbs'. It should not ask for + a password, but should direct try to start the bbs. This is not + installed yet but you should see error messages and then be logged out. + + If these three tests weren't successfull, restore /etc/passwd and + or /etc/shadow, the backup copies have the extension '.mbse'. + Then issue (as root of course) the following commands: + + userdel bbs + userdel -r mbse + groupdel bbs +EOF + diff --git a/TODO b/TODO new file mode 100644 index 00000000..19d00855 --- /dev/null +++ b/TODO @@ -0,0 +1,123 @@ + MBSE BBS V0.33.17 TODO list. + ---------------------------- + + These are a list of things that must be implemented one way or + another. Some things are urgent and necessary to operate the bbs + without human intervention, others are just for comfort, or nice. + I think this list will always contain items, I only hope the urgent + matters will be removed. + Note that most goodies are still in my mind instead of in this file. + Classes: U = Urgent. + N = Normal, second priority. + L = Cosmetic or nice to have. + + +mbsebbs: + L: Reading of function keys over modem lines, or worse PPP connections, + must be fixed. Timing problems together with modem buffering? + It works with direct serial connections. Note, this also happens + on busy LAN's between Linux boxes with normal xterm's. + Note: this problem almost dissapeared after kernel upgrade to + 2.2.16. + + L: Must include SEEN-BY and other hidden lines into BlueWave and QWK + mail, must be user selectable. see remarks of William McBrine. + The default is oke now. + + N: Rewrite chat to use "mbtask". Write chat functions into "mbmon" + + N: Implement session and time/day limits. + + N: Display textfiles and archives. + + N: Check for tagged files before logoff + + N: If a message doesn't end with a newline in the FS-editor, the last + line will dissapear when reading the message. + + N: Can't post messages to users handle. + + L: Implement telnet door. + + N: Deleting a line in the FS editor with the BS key gives a SEGFAULT. + +mbfido: + U: Code cleanup and make a structure in this program. Remove duplicate + or similar functions. + + N: Remove memory leak during toss. (It's ok for less 5000 messages for + each run). + + N: Make a workaround for the fileecho name in the filesdatabase. + + N: Implement long filename support from .tic files. + + N: When a news article is received from a mailinglist there is a valid + To: address in the message, the gate doesn't see that and uses the + name to "All". + +mbcico: + L: Implement modem connect response translation for ISDN lines, i.e. + make the CAUSE responses human readable. see McMail for this + option. + + N: Implement MD5 crypt in binkp protocol driver. + + N: Remove code to make automatic calls after mbtask does this. + +mbfile: + N: Add a check to see if the magic filenames are valid. + + N: Adopt files with check for FILE_ID.DIZ + + N: Export to files.bbs + + N: Add + + N: Update <-touch> + + N: Rearc + +mbaff: + L: Add setup parameters for minimum length of keywords. + +mbindex: + N: Add usernames index. + +mbmon: + L: Logfile tail functions. + + L: Chat with bbs users. + +mbtask: + L: Add chat protocol. + + N: Let mbtask control the mailer and mailer calls. + + N: Implement nodelist Txx flags. + + N: Add events. + +mbsetup: + U: PickAka function lets mbsetup crash if domain is 12 characters + + L: Generate crossreference document: + File Areas <=> BBS groups + File Areas <=> Newfiles groups + Filefind flags <=> TIC Areas + Echomail <=> Mail groups + Echomail <=> Nodes + Fileechos <=> Groups + Fileechos <=> Nodes + Fileechos <=> BBS Areas + Fileechos <=> Magic processing + Fileechos <=> Hatch + Newfiles <=> BBS Areas + Newfiles <=> File groups + Echomail groups <=> Nodes + Echomail groups <=> Areas + Fileecho groups <=> Nodes + Fileecho groups <=> File echos + Fileecho groups <=> Newfile reports + Fileecho groups <=> BBS Areas + diff --git a/UPGRADE b/UPGRADE new file mode 100644 index 00000000..a8d9facc --- /dev/null +++ b/UPGRADE @@ -0,0 +1,18 @@ + UPGRADE INSTRUCTIONS. + + +Read the file ChangeLog from the version you are currently running +until you reach the current version. With every version that needs +upgrade you will find the instructions there. Read them carefully +and perform all necessary steps. + +Read the file ChangeLog from the version you are currently running +until you reach the current version. With every version that needs +upgrade you will find the instructions there. Read them carefully +and perform all necessary steps. + +Yes, I wrote this twice, please do the same with the update +instructions. + + Michiel. + diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 00000000..1af3260c --- /dev/null +++ b/acconfig.h @@ -0,0 +1,72 @@ +/* acconfig.h for the MBSE BBS package */ + +#define AUTHOR @COPYRIGHT@ + +/* Memory debugging */ +#undef MEMWATCH + +/* Has strcasestr function */ +#undef HAVE_STRCASESTR + +/* Has mkstemp function */ +#undef HAVE_MKSTEMP + +/* If you have gettimeofday function */ +#undef HAVE_GETTIMEOFDAY +#undef HAVE_DECLARED_TIMEZONE +#undef HAVE_TM_GMTOFF +#undef HAVE_TM_ZONE + +/* If you don't have pid_t */ +#undef DONT_HAVE_PID_T + +/* Believe ZFIN */ +#undef BELEIVE_ZFIN + +/* Add pid to mbmail */ +#undef ADD_PID + +/* FSC-0070 */ +#undef FSC_0070 + +/* NOPROTO in lhash.h ??? */ +#undef NOPROTO + +/* No Hash Comp function */ +#undef NO_HASH_COMP + +/* News postings */ +#undef RESTAMP_FUTURE_POSTINGS +#undef RESTAMP_OLD_POSTINGS + +/* From mbftpd: */ +#undef FNM_PATHNAME +#undef IP_TOS +#undef M_UNIX +#undef NBBY +#undef REGEX +#undef REGEXEC +#undef SHADOW_PASSWORD +#undef SO_OOBINLINE + +/* mbuseradd */ +#undef AGING +#undef ATT_AGE +#undef ATT_COMMENTS +#undef AUTH_METHODS +#undef CKDEFS +#undef DOUBLESIZE +#undef HAVE_A64L +#undef HAVE_FCHMOD +#undef HAVE_FCHOWN +#undef HAVE_FSYNC +#undef HAVE_LCKPWDF +#undef HAVE_LIBCRACK +#undef HAVE_LIBCRACK_HIST +#undef KEEP_NIS_AT_END +#undef MD5_CRYPT +#undef PAM +#undef SW_CRYPT + + +/* That's it */ diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 00000000..102dc3e3 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,136 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +dnl AM_PROG_LEX +dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT +AC_DEFUN(AM_PROG_LEX, +[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1) +AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex") +AC_PROG_LEX +AC_DECL_YYTEXT]) + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 00000000..6b6e035a --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,149 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +dnl AM_PROG_LEX +dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT +AC_DEFUN(AM_PROG_LEX, +[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1) +AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex") +AC_PROG_LEX +AC_DECL_YYTEXT]) + + diff --git a/checkbasic b/checkbasic new file mode 100755 index 00000000..2dac4920 --- /dev/null +++ b/checkbasic @@ -0,0 +1,40 @@ +#!/bin/sh +# +# checkbasic - A script for mbse bbs that checks if your +# installation is correct. If it is then +# normal installation is allowed. If it is +# pristine, basic installation must be done. +# If it bad or incomplete installed it will +# give an errormessage. +# +# v1.00 08-Oct-2000 (c) Michiel Broek. + +if [ "`grep mbse: /etc/passwd`" != "" ]; then + if [ "`grep bbs: /etc/group`" != "" ]; then + if [ -n "$MBSE_ROOT" ]; then + if [ "$LOGNAME" = "mbse" ]; then + # + # Looks good, normal mbse user and environment is set. + # Exit with errorcode 0 + echo "Hm, looks good..." + exit 0 + else + echo "*** You are not logged in as user 'mbse' ***" + exit 1 + fi + else + echo "*** MBSE_ROOT environment is not set or you are not 'mbse' ***" + exit 1 + fi + else + echo "*** Group 'bbs' is missing on your system ***" + exit 1 + fi +else + echo "*** User 'mbse' is missing on your system ***" + echo " It looks like you need to do a basic install." + echo " Make sure you are root and type ./SETUP.sh and" + echo " read the file INSTALL for instructions." +fi + + diff --git a/config.guess b/config.guess new file mode 100755 index 00000000..4e5345fa --- /dev/null +++ b/config.guess @@ -0,0 +1,973 @@ +#! /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 + +dummy=dummy-$$ +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*T3E:*:*:*) + echo t3e-cray-unicosmk${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:*:* | i?86:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-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 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + 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`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%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/config.h.in b/config.h.in new file mode 100644 index 00000000..01df6d68 --- /dev/null +++ b/config.h.in @@ -0,0 +1,239 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if your system has a working fnmatch function. */ +#undef HAVE_FNMATCH + +/* Define if your struct stat has st_blksize. */ +#undef HAVE_ST_BLKSIZE + +/* Define if you have the strftime function. */ +#undef HAVE_STRFTIME + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if your struct tm has tm_zone. */ +#undef HAVE_TM_ZONE + +/* Define if you don't have tm_zone but do have the external array + tzname. */ +#undef HAVE_TZNAME + +/* Define if utime(file, NULL) sets file's timestamp to the present. */ +#undef HAVE_UTIME_NULL + +/* Define if you have . */ +#undef HAVE_VFORK_H + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define to `long' if doesn't define. */ +#undef off_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 `setpgrp' function takes no argument. */ +#undef SETPGRP_VOID + +/* 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 + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define vfork as fork if vfork does not work. */ +#undef vfork + +/* Define if lex declares yytext as a char * by default, not a char[]. */ +#undef YYTEXT_POINTER + +/* Memory debugging */ +#undef MEMWATCH + +/* If you have gettimeofday function */ +#undef HAVE_GETTIMEOFDAY +#undef HAVE_DECLARED_TIMEZONE +#undef HAVE_TM_GMTOFF +#undef HAVE_TM_ZONE + +/* If you don't have pid_t */ +#undef DONT_HAVE_PID_T + +/* Add pid to mbmail */ +#undef ADD_PID + +/* FSC-0070 */ +#undef FSC_0070 + +/* News postings */ +#undef RESTAMP_FUTURE_POSTINGS +#undef RESTAMP_OLD_POSTINGS + +/* From mbftpd: */ +#undef FNM_PATHNAME +#undef IP_TOS +#undef M_UNIX +#undef NBBY +#undef REGEX +#undef REGEXEC +#undef SHADOW_PASSWORD +#undef SO_OOBINLINE + +/* Define if you have the a64l function. */ +#undef HAVE_A64L + +/* Define if you have the c64i function. */ +#undef HAVE_C64I + +/* Define if you have the fchmod function. */ +#undef HAVE_FCHMOD + +/* Define if you have the fchown function. */ +#undef HAVE_FCHOWN + +/* Define if you have the fsync function. */ +#undef HAVE_FSYNC + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the gethostname function. */ +#undef HAVE_GETHOSTNAME + +/* Define if you have the gettimeofday function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define if you have the getwd function. */ +#undef HAVE_GETWD + +/* Define if you have the lckpwdf function. */ +#undef HAVE_LCKPWDF + +/* Define if you have the mkdir function. */ +#undef HAVE_MKDIR + +/* Define if you have the mkstemp function. */ +#undef HAVE_MKSTEMP + +/* Define if you have the mktime function. */ +#undef HAVE_MKTIME + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the re_comp function. */ +#undef HAVE_RE_COMP + +/* Define if you have the regcmp function. */ +#undef HAVE_REGCMP + +/* Define if you have the regcomp function. */ +#undef HAVE_REGCOMP + +/* Define if you have the rmdir function. */ +#undef HAVE_RMDIR + +/* Define if you have the select function. */ +#undef HAVE_SELECT + +/* Define if you have the socket function. */ +#undef HAVE_SOCKET + +/* Define if you have the strcasestr function. */ +#undef HAVE_STRCASESTR + +/* Define if you have the strcspn function. */ +#undef HAVE_STRCSPN + +/* Define if you have the strdup function. */ +#undef HAVE_STRDUP + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strspn function. */ +#undef HAVE_STRSPN + +/* Define if you have the strstr function. */ +#undef HAVE_STRSTR + +/* Define if you have the strtol function. */ +#undef HAVE_STRTOL + +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + +/* Define if you have the uname function. */ +#undef HAVE_UNAME + +/* Define if you have the header file. */ +#undef HAVE_CRYPT_H + +/* 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_MALLOC_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_NETINET_IN_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_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + diff --git a/configure b/configure new file mode 100755 index 00000000..e24a5388 --- /dev/null +++ b/configure @@ -0,0 +1,3881 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_default_prefix=/opt/mbse +ac_help="$ac_help + --enable-memwatch MEMWATCH debugging" +ac_help="$ac_help + --enable-fsc-0070 Enable FSC 0070" +ac_help="$ac_help + --enable-add-pid Enable add PID" +ac_help="$ac_help + --with-log-compress=METHOD Log compression method (default gzip)" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=lib/libs.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + + +SUBDIRS=". lib mbcico mbfido mbftpd mbmon mbsebbs mbtask mbsetup fbutil import lang examples html script" + + +MBSE_PACKAGE=mbsebbs +MBSE_VERSION=0.33.17 + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:575: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:628: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:685: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=$MBSE_PACKAGE + +VERSION=$MBSE_VERSION + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:731: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:744: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:757: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:770: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:783: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + + +GROUP="bbs" +OWNER="mbse" + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:805: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:835: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:886: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:918: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 929 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:934: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:960: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:965: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:993: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +# Extract the first word of "gawk", so it can be a program name with args. +set dummy gawk; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1027: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="gawk" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "nawk", so it can be a program name with args. +set dummy nawk; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1056: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="nawk" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "awk", so it can be a program name with args. +set dummy awk; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1085: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="awk" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1123: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:1176: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1205: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +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 $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1237: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_YACC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +YACC="$ac_cv_prog_YACC" +if test -n "$YACC"; then + echo "$ac_t""$YACC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1268: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1289: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1306: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1323: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +missing_dir=`cd $ac_aux_dir && pwd` +for ac_prog in flex lex +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1353: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LEX" && break +done +test -n "$LEX" || LEX=""$missing_dir/missing flex"" + +# Extract the first word of "flex", so it can be a program name with args. +set dummy flex; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1386: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="flex" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$LEXLIB" +then + case "$LEX" in + flex*) ac_lib=fl ;; + *) ac_lib=l ;; + esac + echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6 +echo "configure:1420: checking for yywrap in -l$ac_lib" >&5 +ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-l$ac_lib $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LEXLIB="-l$ac_lib" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking lex output file root""... $ac_c" 1>&6 +echo "configure:1462: checking lex output file root" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_root'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # The minimal lex program is just a single line: %%. But some broken lexes +# (Solaris, I think it was) want two %% lines, so accommodate them. +echo '%% +%%' | $LEX +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + { echo "configure: error: cannot find output from $LEX; giving up" 1>&2; exit 1; } +fi +fi + +echo "$ac_t""$ac_cv_prog_lex_root" 1>&6 +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +echo $ac_n "checking whether yytext is a pointer""... $ac_c" 1>&6 +echo "configure:1483: checking whether yytext is a pointer" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_yytext_pointer'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c +ac_save_LIBS="$LIBS" +LIBS="$LIBS $LEXLIB" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_prog_lex_yytext_pointer=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +LIBS="$ac_save_LIBS" +rm -f "${LEX_OUTPUT_ROOT}.c" + +fi + +echo "$ac_t""$ac_cv_prog_lex_yytext_pointer" 1>&6 +if test $ac_cv_prog_lex_yytext_pointer = yes; then + cat >> confdefs.h <<\EOF +#define YYTEXT_POINTER 1 +EOF + +fi + +CFLAGS="$CFLAGS -Wall -Wshadow -Wwrite-strings -Wstrict-prototypes -pipe" + +# Check whether --enable-memwatch or --disable-memwatch was given. +if test "${enable_memwatch+set}" = set; then + enableval="$enable_memwatch" + memwatch=$enableval +else + memwatch=no +fi + +# Check whether --enable-fsc0070 or --disable-fsc0070 was given. +if test "${enable_fsc0070+set}" = set; then + enableval="$enable_fsc0070" + fsc0070=$enableval +else + fsc0070=no +fi + +# Check whether --enable-addpid or --disable-addpid was given. +if test "${enable_addpid+set}" = set; then + enableval="$enable_addpid" + addpid=$enableval +else + addpid=no +fi + + +if test "$memwatch" = "yes"; then + cat >> confdefs.h <<\EOF +#define MEMWATCH 1 +EOF + +fi +if test "$fsc0070" = "yes"; then + cat >> confdefs.h <<\EOF +#define FSC_0070 1 +EOF + +fi +if test "$addpid" = "yes"; then + cat >> confdefs.h <<\EOF +#define ADD_PID 1 +EOF + +fi + +cat >> confdefs.h <> confdefs.h <<\EOF +#define RESTAMP_FUTURE_POSTINGS 1 +EOF + + +echo $ac_n "checking for setspent in -lshadow""... $ac_c" 1>&6 +echo "configure:1579: checking for setspent in -lshadow" >&5 +ac_lib_var=`echo shadow'_'setspent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lshadow $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + +if test "$result" = "yes"; then + LIBS="$LIBS -lshadow" + SHADOW_PASSWORD=1 + LIBSHADOW=1 +else + echo $ac_n "checking for getspnam in -lshadow""... $ac_c" 1>&6 +echo "configure:1625: checking for getspnam in -lshadow" >&5 +ac_lib_var=`echo shadow'_'getspnam | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lshadow $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + + if test "$result" = "yes"; then + LIBS="$LIBS -lshadow" + SHADOW_PASSWORD=1 + LIBSHADOW=1 + else + echo $ac_n "checking for setspent in -lc""... $ac_c" 1>&6 +echo "configure:1671: checking for setspent in -lc" >&5 +ac_lib_var=`echo c'_'setspent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lc $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + + if test "$result" = "yes"; then + if test -f /etc/shadow; then + SHADOW_PASSWORD=1 + fi + fi + fi +fi +if test "$SHADOW_PASSWORD" = "1"; then + if test "$ac_cv_func_fgetspent" != "yes"; then + echo $ac_n "checking for fgetspent in -lshadow""... $ac_c" 1>&6 +echo "configure:1721: checking for fgetspent in -lshadow" >&5 +ac_lib_var=`echo shadow'_'fgetspent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lshadow $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + + if test "$result" = "yes"; then + if test "$LIBSHADOW" != "1"; then + LIBS="$LIBS -lshadow" + fi + fi + fi + cat >> confdefs.h <<\EOF +#define SHADOW_PASSWORD 1 +EOF + +fi +echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6 +echo "configure:1773: checking for crypt in -lcrypt" >&5 +ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lcrypt $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + +if test "$result" = "yes"; then + LIBS="$LIBS -lcrypt" + for ac_hdr in crypt.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1819: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1829: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +fi + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:1862: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:1875: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:1900: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:1941: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1983: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1996: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:2063: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 +echo "configure:2087: checking for sys/wait.h that is POSIX.1 compatible" >&5 +if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#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; } +EOF +if { (eval echo configure:2108: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_sys_wait_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_sys_wait_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 +if test $ac_cv_header_sys_wait_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_WAIT_H 1 +EOF + +fi + +for ac_hdr in fcntl.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h termio.h unistd.h netinet/in.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2132: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2142: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 +echo "configure:2169: checking whether struct tm is in sys/time.h or time.h" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct tm *tp; tp->tm_sec; +; return 0; } +EOF +if { (eval echo configure:2182: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm=time.h +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm=sys/time.h +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm" 1>&6 +if test $ac_cv_struct_tm = sys/time.h; then + cat >> confdefs.h <<\EOF +#define TM_IN_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&6 +echo "configure:2203: checking for tm_zone in struct tm" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_cv_struct_tm> +int main() { +struct tm tm; tm.tm_zone; +; return 0; } +EOF +if { (eval echo configure:2216: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm_zone=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm_zone=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm_zone" 1>&6 +if test "$ac_cv_struct_tm_zone" = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_TM_ZONE 1 +EOF + +else + echo $ac_n "checking for tzname""... $ac_c" 1>&6 +echo "configure:2236: checking for tzname" >&5 +if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#ifndef tzname /* For SGI. */ +extern char *tzname[]; /* RS6000 and others reject char **tzname. */ +#endif +int main() { +atoi(*tzname); +; return 0; } +EOF +if { (eval echo configure:2251: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_var_tzname=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_var_tzname=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_var_tzname" 1>&6 + if test $ac_cv_var_tzname = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_TZNAME 1 +EOF + + fi +fi + + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2274: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2328: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:2349: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:2383: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for pid_t""... $ac_c" 1>&6 +echo "configure:2416: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:2449: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking for st_blksize in struct stat""... $ac_c" 1>&6 +echo "configure:2482: checking for st_blksize in struct stat" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct stat s; s.st_blksize; +; return 0; } +EOF +if { (eval echo configure:2495: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_st_blksize=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_st_blksize=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_st_blksize" 1>&6 +if test $ac_cv_struct_st_blksize = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ST_BLKSIZE 1 +EOF + +fi + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:2516: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:2530: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 +echo "configure:2551: checking whether struct tm is in sys/time.h or time.h" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct tm *tp; tp->tm_sec; +; return 0; } +EOF +if { (eval echo configure:2564: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm=time.h +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm=sys/time.h +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm" 1>&6 +if test $ac_cv_struct_tm = sys/time.h; then + cat >> confdefs.h <<\EOF +#define TM_IN_SYS_TIME 1 +EOF + +fi + + +for ac_func in c64i a64l fchmod fchown fsync lckpwdf strcasestr mkstemp +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2588: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2616: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking for working fnmatch""... $ac_c" 1>&6 +echo "configure:2641: checking for working fnmatch" >&5 +if eval "test \"`echo '$''{'ac_cv_func_fnmatch_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # Some versions of Solaris or SCO have a broken fnmatch function. +# So we run a test program. If we are cross-compiling, take no chance. +# Thanks to John Oleynick and Franc,ois Pinard for this test. +if test "$cross_compiling" = yes; then + ac_cv_func_fnmatch_works=no +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_fnmatch_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_fnmatch_works=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_fnmatch_works" 1>&6 +if test $ac_cv_func_fnmatch_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_FNMATCH 1 +EOF + +fi + +if test $ac_cv_prog_gcc = yes; then + echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 +echo "configure:2680: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext < +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext < +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 +echo "configure:2726: checking for 8-bit clean memcmp" >&5 +if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_clean=no +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_memcmp_clean=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_memcmp_clean=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 +test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" + +echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6 +echo "configure:2762: checking whether setpgrp takes no argument" >&5 +if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#endif + +/* + * If this system has a BSD-style setpgrp, which takes arguments, exit + * successfully. + */ +main() +{ + if (setpgrp(1,1) == -1) + exit(0); + else + exit(1); +} + +EOF +if { (eval echo configure:2790: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_setpgrp_void=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_setpgrp_void=yes +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6 +if test $ac_cv_func_setpgrp_void = yes; then + cat >> confdefs.h <<\EOF +#define SETPGRP_VOID 1 +EOF + +fi + +echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 +echo "configure:2814: checking return type of signal handlers" >&5 +if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#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; } +EOF +if { (eval echo configure:2836: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_signal=void +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_signal=int +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_type_signal" 1>&6 +cat >> confdefs.h <&6 +echo "configure:2855: checking for strftime" >&5 +if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char strftime(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_strftime) || defined (__stub___strftime) +choke me +#else +strftime(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2883: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_strftime=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_strftime=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_STRFTIME 1 +EOF + +else + echo "$ac_t""no" 1>&6 +# strftime is in -lintl on SCO UNIX. +echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6 +echo "configure:2905: checking for strftime in -lintl" >&5 +ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lintl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_STRFTIME 1 +EOF + +LIBS="-lintl $LIBS" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking whether utime accepts a null argument""... $ac_c" 1>&6 +echo "configure:2951: checking whether utime accepts a null argument" >&5 +if eval "test \"`echo '$''{'ac_cv_func_utime_null'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata; > conftestdata +# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong. +if test "$cross_compiling" = yes; then + ac_cv_func_utime_null=no +else + cat > conftest.$ac_ext < +#include +main() { +struct stat s, t; +exit(!(stat ("conftestdata", &s) == 0 && utime("conftestdata", (long *)0) == 0 +&& stat("conftestdata", &t) == 0 && t.st_mtime >= s.st_mtime +&& t.st_mtime - s.st_mtime < 120)); +} +EOF +if { (eval echo configure:2972: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_utime_null=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_utime_null=no +fi +rm -fr conftest* +fi + +rm -f core core.* *.core +fi + +echo "$ac_t""$ac_cv_func_utime_null" 1>&6 +if test $ac_cv_func_utime_null = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_UTIME_NULL 1 +EOF + +fi + +ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for vfork.h""... $ac_c" 1>&6 +echo "configure:2997: checking for vfork.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3007: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VFORK_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for working vfork""... $ac_c" 1>&6 +echo "configure:3032: checking for working vfork" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + echo $ac_n "checking for vfork""... $ac_c" 1>&6 +echo "configure:3038: checking for vfork" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vfork(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vfork) || defined (__stub___vfork) +choke me +#else +vfork(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3066: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_vfork=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vfork=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vfork`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + +ac_cv_func_vfork_works=$ac_cv_func_vfork +else + cat > conftest.$ac_ext < +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_VFORK_H +#include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. + The compiler is told about this with #include , + but some compilers (e.g. gcc -O) don't grok . + Test for this by using a static variable whose address + is put into a register that is clobbered by the vfork. */ +static +#ifdef __cplusplus +sparc_address_test (int arg) +#else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} +main() { + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. + This test uses lots of local variables, at least + as many local variables as main has allocated so far + including compiler temporaries. 4 locals are enough for + gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. + A buggy compiler should reuse the register of parent + for one of the local variables, since it will think that + parent can't possibly be used any more in this routine. + Assigning to the local variable will thus munge parent + in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), + vfork doesn't separate parent from child file descriptors. + If the child closes a descriptor before it execs or exits, + this munges the parent's descriptor as well. + Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + exit( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +EOF +if { (eval echo configure:3183: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_vfork_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_vfork_works=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_vfork_works" 1>&6 +if test $ac_cv_func_vfork_works = no; then + cat >> confdefs.h <<\EOF +#define vfork fork +EOF + +fi + +echo $ac_n "checking for vprintf""... $ac_c" 1>&6 +echo "configure:3206: checking for vprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vprintf(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vprintf) || defined (__stub___vprintf) +choke me +#else +vprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_vprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_func_vprintf" != yes; then +echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 +echo "configure:3258: checking for _doprnt" >&5 +if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +_doprnt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3286: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func__doprnt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func__doprnt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DOPRNT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +fi + +for ac_func in getcwd gethostname gettimeofday getwd mkdir mktime putenv re_comp regcmp regcomp rmdir select socket strcspn strdup strerror strspn strstr strtol strtoul uname +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3313: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3341: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +# Extract the first word of "compress", so it can be a program name with args. +set dummy compress; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3369: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_COMPRESS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$COMPRESS" in + /*) + ac_cv_path_COMPRESS="$COMPRESS" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_COMPRESS="$COMPRESS" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_COMPRESS="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_COMPRESS" && ac_cv_path_COMPRESS="no-compress-found-during-configure" + ;; +esac +fi +COMPRESS="$ac_cv_path_COMPRESS" +if test -n "$COMPRESS"; then + echo "$ac_t""$COMPRESS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +for ac_prog in gzip +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3407: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_GZIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$GZIP" in + /*) + ac_cv_path_GZIP="$GZIP" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_GZIP="$GZIP" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_GZIP="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +GZIP="$ac_cv_path_GZIP" +if test -n "$GZIP"; then + echo "$ac_t""$GZIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$GZIP" && break +done +test -n "$GZIP" || GZIP="no-gzip-found-during-configure" + +# Check whether --with-log-compress or --without-log-compress was given. +if test "${with_log_compress+set}" = set; then + withval="$with_log_compress" + LOG_COMPRESS=$with_log_compress +else + LOG_COMPRESS=gzip +fi + +case "$LOG_COMPRESS" in +gzip) + LOG_COMPRESS=$GZIP + LOG_COMPRESSEXT=".gz" ;; +compress) + LOG_COMPRESS=$COMPRESS + LOG_COMPRESSEXT=".Z" ;; +*) + LOG_COMPRESS=$LOG_COMPRESS + LOG_COMPRESSEXT=".unknown" ;; +esac + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile + lib/Makefile + mbcico/Makefile + mbfido/Makefile + mbfido/paths.h + mbftpd/Makefile + mbmon/Makefile + mbsebbs/Makefile + mbtask/Makefile + mbsetup/Makefile + fbutil/Makefile + script/Makefile + import/Makefile + lang/Makefile + examples/Makefile + html/Makefile + INSTALL + FILE_ID.DIZ + config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@SUBDIRS@%$SUBDIRS%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@GROUP@%$GROUP%g +s%@OWNER@%$OWNER%g +s%@CC@%$CC%g +s%@AWK@%$AWK%g +s%@RANLIB@%$RANLIB%g +s%@YACC@%$YACC%g +s%@LEX@%$LEX%g +s%@LEXLIB@%$LEXLIB%g +s%@CPP@%$CPP%g +s%@LEX_OUTPUT_ROOT@%$LEX_OUTPUT_ROOT%g +s%@LIBOBJS@%$LIBOBJS%g +s%@COMPRESS@%$COMPRESS%g +s%@GZIP@%$GZIP%g +s%@LOG_COMPRESS@%$LOG_COMPRESS%g +s%@LOG_COMPRESSEXT@%$LOG_COMPRESSEXT%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + + diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..c73f639f --- /dev/null +++ b/configure.in @@ -0,0 +1,160 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(lib/libs.h) +AM_CONFIG_HEADER(config.h) +SUBDIRS=". lib mbcico mbfido mbftpd mbmon mbsebbs mbtask mbsetup fbutil import lang examples html script" +AC_SUBST(SUBDIRS) + +dnl General settings for MBSE BBS +MBSE_PACKAGE=mbsebbs +MBSE_VERSION=0.33.17 +AC_SUBST(PACKAGE, $MBSE_PACKAGE) +AC_SUBST(VERSION, $MBSE_VERSION) +AM_INIT_AUTOMAKE($MBSE_PACKAGE, $MBSE_VERSION) +AC_PREFIX_DEFAULT(/opt/mbse) +GROUP="bbs" +OWNER="mbse" +AC_SUBST(GROUP) +AC_SUBST(OWNER) + +dnl Checks for programs. +AC_PROG_CC +dnl ALternate awk check, I skip mawk because it doesn't work for MBSE. +AC_CHECK_PROG(AWK, gawk, gawk) +AC_CHECK_PROG(AWK, nawk, nawk) +AC_CHECK_PROG(AWK, awk, awk) +AC_PROG_INSTALL +AC_PROG_MAKE_SET +AC_PROG_RANLIB +AC_PROG_YACC +AM_PROG_LEX +CFLAGS="$CFLAGS -Wall -Wshadow -Wwrite-strings -Wstrict-prototypes -pipe" + +dnl Additional commandline switches +AC_ARG_ENABLE(memwatch, [ --enable-memwatch MEMWATCH debugging], [ memwatch=$enableval ], [ memwatch=no ]) +AC_ARG_ENABLE(fsc0070, [ --enable-fsc-0070 Enable FSC 0070], [ fsc0070=$enableval ], [ fsc0070=no ]) +AC_ARG_ENABLE(addpid, [ --enable-add-pid Enable add PID], [ addpid=$enableval ], [ addpid=no ]) + +if test "$memwatch" = "yes"; then + AC_DEFINE(MEMWATCH) +fi +if test "$fsc0070" = "yes"; then + AC_DEFINE(FSC_0070) +fi +if test "$addpid" = "yes"; then + AC_DEFINE(ADD_PID) +fi + +dnl Defines for MBSE BBS (must use tests or --enable-stuff later) +AC_DEFINE_UNQUOTED(RESTAMP_OLD_POSTINGS, 21) +AC_DEFINE(RESTAMP_FUTURE_POSTINGS) + +dnl Checks for libraries. +AC_CHECK_LIB(shadow,setspent,result=yes,result=no) +if test "$result" = "yes"; then + LIBS="$LIBS -lshadow" + SHADOW_PASSWORD=1 + LIBSHADOW=1 +else + AC_CHECK_LIB(shadow,getspnam,result=yes,result=no) + if test "$result" = "yes"; then + LIBS="$LIBS -lshadow" + SHADOW_PASSWORD=1 + LIBSHADOW=1 + else + dnl some libc's (glibc 2.x) keep shadow functions in -lc + AC_CHECK_LIB(c,setspent,result=yes,result=no) + if test "$result" = "yes"; then + if test -f /etc/shadow; then + SHADOW_PASSWORD=1 + fi + fi + fi +fi +if test "$SHADOW_PASSWORD" = "1"; then + if test "$ac_cv_func_fgetspent" != "yes"; then + AC_CHECK_LIB(shadow,fgetspent,result=yes,result=no) + if test "$result" = "yes"; then + if test "$LIBSHADOW" != "1"; then + LIBS="$LIBS -lshadow" + fi + fi + fi + AC_DEFINE(SHADOW_PASSWORD) +fi +AC_CHECK_LIB(crypt,crypt,result=yes,result=no) +if test "$result" = "yes"; then + LIBS="$LIBS -lcrypt" + AC_CHECK_HEADERS(crypt.h) +fi + +dnl Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h termio.h unistd.h netinet/in.h) +AC_STRUCT_TIMEZONE + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_STRUCT_ST_BLKSIZE +AC_HEADER_TIME +AC_STRUCT_TM + +dnl Checks for library functions. +AC_CHECK_FUNCS(c64i a64l fchmod fchown fsync lckpwdf strcasestr mkstemp) +AC_FUNC_FNMATCH +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MEMCMP +AC_FUNC_SETPGRP +AC_TYPE_SIGNAL +AC_FUNC_STRFTIME +AC_FUNC_UTIME_NULL +AC_FUNC_VFORK +AC_FUNC_VPRINTF +AC_CHECK_FUNCS(getcwd gethostname gettimeofday getwd mkdir mktime putenv re_comp regcmp regcomp rmdir select socket strcspn strdup strerror strspn strstr strtol strtoul uname) + +dnl Check for external programs +AC_PATH_PROG(COMPRESS,compress,no-compress-found-during-configure) +AC_PATH_PROGS(GZIP,gzip,no-gzip-found-during-configure) +dnl +AC_ARG_WITH(log-compress,[ --with-log-compress=METHOD Log compression method (default gzip)], LOG_COMPRESS=$with_log_compress, LOG_COMPRESS=gzip) +case "$LOG_COMPRESS" in +gzip) + LOG_COMPRESS=$GZIP + LOG_COMPRESSEXT=".gz" ;; +compress) + LOG_COMPRESS=$COMPRESS + LOG_COMPRESSEXT=".Z" ;; +*) + LOG_COMPRESS=$LOG_COMPRESS + LOG_COMPRESSEXT=".unknown" ;; +esac +AC_SUBST(LOG_COMPRESS) +AC_SUBST(LOG_COMPRESSEXT) +dnl + +AC_OUTPUT( + Makefile + lib/Makefile + mbcico/Makefile + mbfido/Makefile + mbfido/paths.h + mbftpd/Makefile + mbmon/Makefile + mbsebbs/Makefile + mbtask/Makefile + mbsetup/Makefile + fbutil/Makefile + script/Makefile + import/Makefile + lang/Makefile + examples/Makefile + html/Makefile + INSTALL + FILE_ID.DIZ +) + diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 00000000..1897e136 --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,20 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +EXTRA_DIST = etc.tar menus.tar txtfiles.tar + +install-exec-local: + @if [ ! -f $(sysconfdir)/mareas.data ]; then \ + tar xfC etc.tar $(sysconfdir) ; \ + echo "Installing default databases" ; \ + fi + @if [ ! -f $(prefix)/english/menus/main.mnu ]; then \ + tar xfC menus.tar $(prefix)/english/menus ; \ + echo "Installing default english menus" ; \ + fi + @if [ ! -f $(prefix)/english/txtfiles/main.ans ]; then \ + tar xfC txtfiles.tar $(prefix)/english/txtfiles ; \ + echo "Installing default english txtfiles" ; \ + fi + diff --git a/examples/Makefile.in b/examples/Makefile.in new file mode 100644 index 00000000..301fa5c2 --- /dev/null +++ b/examples/Makefile.in @@ -0,0 +1,298 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = etc.tar menus.tar txtfiles.tar +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps examples/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = examples + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + @if [ ! -f $(sysconfdir)/mareas.data ]; then \ + tar xfC etc.tar $(sysconfdir) ; \ + echo "Installing default databases" ; \ + fi + @if [ ! -f $(prefix)/english/menus/main.mnu ]; then \ + tar xfC menus.tar $(prefix)/english/menus ; \ + echo "Installing default english menus" ; \ + fi + @if [ ! -f $(prefix)/english/txtfiles/main.ans ]; then \ + tar xfC txtfiles.tar $(prefix)/english/txtfiles ; \ + echo "Installing default english txtfiles" ; \ + fi + +# 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/examples/etc.tar b/examples/etc.tar new file mode 100644 index 00000000..e8f29f64 Binary files /dev/null and b/examples/etc.tar differ diff --git a/examples/menus.tar b/examples/menus.tar new file mode 100644 index 00000000..13decbaf Binary files /dev/null and b/examples/menus.tar differ diff --git a/examples/txtfiles.tar b/examples/txtfiles.tar new file mode 100644 index 00000000..0accd217 Binary files /dev/null and b/examples/txtfiles.tar differ diff --git a/files.css b/files.css new file mode 100644 index 00000000..deb1987c --- /dev/null +++ b/files.css @@ -0,0 +1,26 @@ +/* + * Example stylesheet MBSE BBS file listings. + */ + + +BODY { background: beige } + +/* + * H1 is the header in the area pages, H2 in the main page. + */ +H1 { color: red; font-family: Arial; font-size: 13pt; font-weight: bold } +H2 { color: black; font-family: Arial; font-size: 13pt; font-weight: bold } + +A:link { color: blue } +A:visited { color: blue } +A:active { color: red } + +/* + * The look and feel of the file listings. Use a fixed font in the TD + * fields, not Truetype or it will look ugly. + */ +TABLE { background: #CCCCCC } +TH { background: #99CCFF; font-family: Helvetica } +TH.head { background: #FF9900; font-family: Helvetica } +TD { font-family: Fixed; font-size: 12pt } + diff --git a/html/Makefile.am b/html/Makefile.am new file mode 100644 index 00000000..69b2338a --- /dev/null +++ b/html/Makefile.am @@ -0,0 +1,84 @@ +## Process this file with automake to produce Makefile.in +# Makefile for @PACKAGE@-@VERSION@ html documentation + +SUBDIRS = . + +EXTRA_DIST = basic.html date.html dist.html manual.css \ +flow.html postfix.html gwnews.html index.htm ups.html \ +install.html intergate.html intro.html invoking.html \ +known_bugs.html mgetty.html routing.html nodelist.html \ +ftsc/fsc-0039.html ftsc/fsc-0056.html ftsc/fsc-0087.html \ +ftsc/fsp-1003.html ftsc/fsp-1009.html ftsc/fts-0007.html \ +ftsc/fsc-0046.html ftsc/fsc-0057.html ftsc/fsc-0091.html \ +ftsc/fsp-1004.html ftsc/fta-1005.html ftsc/fts-0008.html \ +ftsc/fsc-0048.html ftsc/fsc-0059.html ftsc/fsc-0092.html \ +ftsc/fsp-1005.html ftsc/fts-0001.html ftsc/fts-0009.html \ +ftsc/fsc-0049.html ftsc/fsc-0062.html ftsc/fsc-0093.html \ +ftsc/fsp-1006.html ftsc/fts-0004.html ftsc/index.htm \ +ftsc/fsc-0050.html ftsc/fsc-0070.html ftsc/fsp-1001.html \ +ftsc/fsp-1007.html ftsc/fts-0005.html ftsc/fsc-0053.html \ +ftsc/fsc-0072.html ftsc/fsp-1002.html ftsc/fsp-1008.html \ +ftsc/fts-0006.html ftsc/fsc-0035.html ftsc/fsp-1010.html \ +ftsc/fsp-1011.html ftsc/ftscprod.html ftsc/fsc-0088.html \ +ftsc/fts-4001.html \ +images/b_arrow.gif images/magic.gif images/nodes1.gif \ +images/connec.gif images/mbsetup0.gif images/nodes2.gif \ +images/domains.gif images/mbsetup1.6.S.gif images/nodes3.gif \ +images/e_menu.gif images/mbsetup1.6.gif images/nodes4.gif \ +images/emareas.gif images/mbsetup2.gif images/nodes5.gif \ +images/emgroup.gif images/modems0.gif images/oneliner.gif \ +images/fdb.gif images/newfiles.gif images/protocol.gif \ +images/fegroup.gif images/newgroups.gif images/rarrow.gif \ +images/fileecho.gif images/nodelist.gif images/security.gif \ +images/filefind.gif images/nodelist1.gif images/tty.gif \ +images/files.gif images/nodelist2.gif images/tty1.gif \ +images/go_to.gif images/nodelist3.gif images/tty2.gif \ +images/hatch.gif images/nodelist4.gif images/tty3.gif \ +images/language.gif images/nodelist5.gif images/uarrow.gif \ +images/larrow.gif images/nodes.gif images/users.gif \ +images/mbse.jpg images/taskmgr.gif \ +license/copying.html license/hydracom.html license/index.htm \ +license/jam.html \ +menus/control.html menus/index.htm menus/menu100.html \ +menus/menu300.html menus/menu500.html \ +menus/menu0.html menus/menu200.html menus/menu400.html \ +misc/dropfile.html misc/fileid.html misc/index.htm \ +misc/jam.html misc/semafore.html misc/filefind.html \ +misc/ftpserver.html misc/ipmailer.html misc/outbound.html \ +misc/usleep.html \ +programs/import.html programs/mbchat.html \ +programs/mbfido.html programs/mbmon.html \ +programs/mbtoberep.html \ +programs/index.htm programs/mbcico.html \ +programs/mbfile.html programs/mbmsg.html \ +programs/mbseq.html programs/mbuser.html \ +programs/mbaff.html programs/mbdiff.html \ +programs/mbindex.html programs/mbout.html \ +programs/mbsetup.html programs/mbuseradd.html \ +programs/mball.html programs/mbfbgen.html \ +programs/mblang.html programs/mbsebbs.html \ +programs/mbstat.html programs/mbpasswd.html \ +programs/mbtask.html programs/mbmail.html \ +setup/archiver.html setup/index.htm setup/bbs.html \ +setup/bbslist.html setup/language.html setup/oneliner.html \ +setup/emareas.html setup/magic.html setup/mail.html \ +setup/protocol.html setup/emgroup.html setup/safe.html \ +setup/fdb.html setup/security.html setup/sitedoc.html \ +setup/fegroup.html setup/modems.html setup/softinfo.html \ +setup/fidonet.html setup/tic.html setup/timebank.html \ +setup/fileecho.html setup/newfiles.html setup/filefind.html \ +setup/newgroups.html setup/files.html setup/nodes.html \ +setup/ttyinfo.html setup/global.html setup/users.html \ +setup/hatch.html setup/virscan.html setup/services.html \ +setup/domains.html setup/taskmgr.html + + +install-exec-local: + rm -Rf $(prefix)/html + $(mkinstalldirs) $(prefix)/html + @echo "Installing html documentation in $(prefix)/html" + @cp -Pr $(EXTRA_DIST) $(prefix)/html + chown -R @OWNER@.@GROUP@ $(prefix)/html + chmod -R 0644 $(prefix)/html/*.htm* + chmod -R 0644 $(prefix)/html/images/*.gif + diff --git a/html/Makefile.in b/html/Makefile.in new file mode 100644 index 00000000..52d8bb4d --- /dev/null +++ b/html/Makefile.in @@ -0,0 +1,299 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Makefile for @PACKAGE@-@VERSION@ html documentation + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = basic.html date.html dist.html manual.css flow.html postfix.html gwnews.html index.htm ups.html install.html intergate.html intro.html invoking.html known_bugs.html mgetty.html routing.html nodelist.html ftsc/fsc-0039.html ftsc/fsc-0056.html ftsc/fsc-0087.html ftsc/fsp-1003.html ftsc/fsp-1009.html ftsc/fts-0007.html ftsc/fsc-0046.html ftsc/fsc-0057.html ftsc/fsc-0091.html ftsc/fsp-1004.html ftsc/fta-1005.html ftsc/fts-0008.html ftsc/fsc-0048.html ftsc/fsc-0059.html ftsc/fsc-0092.html ftsc/fsp-1005.html ftsc/fts-0001.html ftsc/fts-0009.html ftsc/fsc-0049.html ftsc/fsc-0062.html ftsc/fsc-0093.html ftsc/fsp-1006.html ftsc/fts-0004.html ftsc/index.htm ftsc/fsc-0050.html ftsc/fsc-0070.html ftsc/fsp-1001.html ftsc/fsp-1007.html ftsc/fts-0005.html ftsc/fsc-0053.html ftsc/fsc-0072.html ftsc/fsp-1002.html ftsc/fsp-1008.html ftsc/fts-0006.html ftsc/fsc-0035.html ftsc/fsp-1010.html ftsc/fsp-1011.html ftsc/ftscprod.html ftsc/fsc-0088.html ftsc/fts-4001.html images/b_arrow.gif images/magic.gif images/nodes1.gif images/connec.gif images/mbsetup0.gif images/nodes2.gif images/domains.gif images/mbsetup1.6.S.gif images/nodes3.gif images/e_menu.gif images/mbsetup1.6.gif images/nodes4.gif images/emareas.gif images/mbsetup2.gif images/nodes5.gif images/emgroup.gif images/modems0.gif images/oneliner.gif images/fdb.gif images/newfiles.gif images/protocol.gif images/fegroup.gif images/newgroups.gif images/rarrow.gif images/fileecho.gif images/nodelist.gif images/security.gif images/filefind.gif images/nodelist1.gif images/tty.gif images/files.gif images/nodelist2.gif images/tty1.gif images/go_to.gif images/nodelist3.gif images/tty2.gif images/hatch.gif images/nodelist4.gif images/tty3.gif images/language.gif images/nodelist5.gif images/uarrow.gif images/larrow.gif images/nodes.gif images/users.gif images/mbse.jpg images/taskmgr.gif license/copying.html license/hydracom.html license/index.htm license/jam.html menus/control.html menus/index.htm menus/menu100.html menus/menu300.html menus/menu500.html menus/menu0.html menus/menu200.html menus/menu400.html misc/dropfile.html misc/fileid.html misc/index.htm misc/jam.html misc/semafore.html misc/filefind.html misc/ftpserver.html misc/ipmailer.html misc/outbound.html misc/usleep.html programs/import.html programs/mbchat.html programs/mbfido.html programs/mbmon.html programs/mbtoberep.html programs/index.htm programs/mbcico.html programs/mbfile.html programs/mbmsg.html programs/mbseq.html programs/mbuser.html programs/mbaff.html programs/mbdiff.html programs/mbindex.html programs/mbout.html programs/mbsetup.html programs/mbuseradd.html programs/mball.html programs/mbfbgen.html programs/mblang.html programs/mbsebbs.html programs/mbstat.html programs/mbpasswd.html programs/mbtask.html programs/mbmail.html setup/archiver.html setup/index.htm setup/bbs.html setup/bbslist.html setup/language.html setup/oneliner.html setup/emareas.html setup/magic.html setup/mail.html setup/protocol.html setup/emgroup.html setup/safe.html setup/fdb.html setup/security.html setup/sitedoc.html setup/fegroup.html setup/modems.html setup/softinfo.html setup/fidonet.html setup/tic.html setup/timebank.html setup/fileecho.html setup/newfiles.html setup/filefind.html setup/newgroups.html setup/files.html setup/nodes.html setup/ttyinfo.html setup/global.html setup/users.html setup/hatch.html setup/virscan.html setup/services.html setup/domains.html setup/taskmgr.html + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps html/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = html + +distdir: $(DISTFILES) + $(mkinstalldirs) $(distdir)/ftsc $(distdir)/images $(distdir)/license \ + $(distdir)/menus $(distdir)/misc $(distdir)/programs \ + $(distdir)/setup + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + rm -Rf $(prefix)/html + $(mkinstalldirs) $(prefix)/html + @echo "Installing html documentation in $(prefix)/html" + @cp -Pr $(EXTRA_DIST) $(prefix)/html + chown -R @OWNER@.@GROUP@ $(prefix)/html + chmod -R 0644 $(prefix)/html/*.htm* + chmod -R 0644 $(prefix)/html/images/*.gif + +# 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/html/basic.html b/html/basic.html new file mode 100755 index 00000000..16beffc6 --- /dev/null +++ b/html/basic.html @@ -0,0 +1,152 @@ + + + + + + + + +MBSE BBS basic installation. + + + +
+
Last update 27-May-2001
+

 

+ +

MBSE BBS Basic Installation

+ +

Introduction.

+

+Before you compile and install MBSE BBS you must first setup the basic +environment. If you don't do this, things will fail. +

 

+ +

Step 1: planning the filesystems.

+

+MBSE BBS is default installed in /opt/mbse. The spoolfiles (in and +outbound, message bases) go into /var/spool/mbse. In the /opt/mbse +path are several subdirectories, bin for the binaries, etc for the +configuration and some scripts, english and dutch for the language +files and menus, home for the users homedirectories, log for the +logfiles, magic for the filerequest magicnames, fdb for the files +database, var for some statistic files and tmp as temp directory. +

+Don't use UMSDOS or SAMBA filesystems for the bbs, stick by the standard Linux +filesystems (ext2). If you intent to make your bbs also accessible +by FTP and WWW you must create the directory structure under the ftp user +behind the pub directory. Read the +ftp server doc for details. If you don't follow these guidlines, you +will run into trouble later and have to spend a lot of time in correcting +this error. +

+The default setup will be as follows:
+

+/opt/mbse		binaries, config and user home directories.
+/var/spool/mbse		In/outbound, queues, download directories.
+
+

 

+ +

Step 2: Running the installation script.

+

+The installation script must be run by root. It checks if there is a +previous or failed installation on your system. If that's so the script will +not run. In other words, you can only run this script once. The script makes +backup copies of the system files it changes, these files will get the +extension .mbse To run the installation script you need +the archive mbbsebbs-0.33.nn.tar.gz. +Unpack this archive on your system, in /tmp will do fine: +

+cd /tmp
+tar xfvz /path/to/the/mbsebbs-0.33.nn.tar.gz
+
+To start the script type: +
+cd mbsebbs-0.33.nn
+sh ./SETUP.sh
+
+The script does the following: +
    +
  1. Create the group bbs +
  2. Create the user mbse +
  3. Create a .profile for user mbse +
  4. Create and set owner of directory tree under /opt/mbse +
+Then the script will ask you to give a password for user mbse +This password is for system maintenance and for you to make changes to the +bbs. You will need that frequently but you should not make that password +easy to guess of course. The script will then continue again: +
    +
  1. The user bbs is added. +
  2. The password will be removed from user bbs This action +will make changes in /etc/shadow (if you have that) otherwise in /etc/passwd. +
  3. If they don't exist in the file /etc/services the services fido, tfido +and binkp will be added. +
  4. If they don't exist in the file /etc/inetd.conf the internet protocols +for the mailer will be added. The inetd is restarted to +activate the changes. +
+

 

+ +

Step 3: Check the basic installation

+

+The last screen of the script is about sanity checks. Perform those checks! +If something is wrong, now is the time to fix it. Don't panic and remember +the backups of the system files that are changed are in /etc with the +extension .mbse i.e: those were the original files. +

 

+ +

Step 4: Install the basic packages.

+

+Login as user mbse. While in the home directory unpack the distribution +archives: +

+tar xfvz /path/to/mbsebbs-0.33.nn.tar.gz
+
+You now have the subdirectory with sources in the right place. Indeed, if you +have a new installation, you also have unpacked the archive somewere else +to run the installation script. That one can be removed. +Next build the binaries and install them using the folowing commands: +
+cd ~/mbsebbs-0.33.nn
+./configure
+make
+su
+password: enter root password here
+make install
+exit
+
+The last part of the installation procedure shows you the location of the bbs +startup script that is added to your system. Because this is your first +time installation, example menus, textfiles and some databases are installed. +If they already excist on your systems (when you do an upgrade) they +will not be installed again. +

+Now you must start the mbtask daemon by hand by typing /opt/mbse/bin/mbtask. +Check the file /opt/mbse/log/mbtask.log for startup problems. You may notice that +the program mbcico is started everytime, this is not a problem, it simply doesn't work right +now because you haven't configured anything yet. +

 

+ +

Step 5: (RedHat) startup problems.

+

+From RedHat 6.1 (not the older versions) the behaviour of the +su is changed. This may be true for other distributions since +the end of 1999 and for Mandrake as well. The file /etc/rc.d/init.d/mbsed that is +created by the setup script is different then before. The new command +is su - instead of simply su. It might be +that other new distributions also need the extra minus sign. If that's the +case, please let me know and tell me how I can test what version it is. +

 

+ +

Step 6: ready.

+

+Now the basic environment is finished, the next thing is to install +the scripts, examples and configuration. +

 

+Back to Index +Back to Index + +

+ + diff --git a/html/date.html b/html/date.html new file mode 100755 index 00000000..05612d1a --- /dev/null +++ b/html/date.html @@ -0,0 +1 @@ +
Last update 18-Sep-1999
diff --git a/html/dist.html b/html/dist.html new file mode 100644 index 00000000..01da8e5f --- /dev/null +++ b/html/dist.html @@ -0,0 +1,74 @@ + + + + + + + + +Linux distributions. + + + +
+
Last update 06-Jun-2001
+

 

+ +

Linux Distributions.

+

+ +

Which distribution

+

+Linux is available in several distributions, they all have advantages and +disadvantages for bbs use. Which distribution to pick is very personal. +You should also consider the fact if the bbs machine is the same machine on +which you do your daily work on or if you use a seperate system for the bbs. +I will describe the distributions below for use on dedicated bbs computers, +that means you don't do daily work on them and don't use them to play games. +Most important is that this is my personal view. +

 

+ +

Slackware

+

+I am using MBSE BBS on several Slackware distributions. You can make a very small +setup for MBSE BBS like Zipslack. Not included is the mgetty package. +

 

+ +

Redhat and Mandrake

+

+I write this as if these are the same which isn't true of course. From MBSE +BBS's point of view they are almost the same, so that's why I treat them as +the same distributions. For people with little Linux experience these +distributions are a good choice if you can spare the diskspace. I haven't +found a simple dedicated setup for the bbs, so the safest way is to install +allmost everything, which is quite simple. This will cost you about 1200 Megs. +Maybe that someone more experienced with these distro's can give more details +on how to build a small server. Please note that from RedHat 6.1 and up the +startup script (/etc/rc.d/init.d/mbsed) is different than before. Maybe +this is needed for Mandrake 6.1 and up too. +

 

+ +

SuSe

+

+Since SuSE 7.1 the setup scripts are working and tested. Older distro's +might work. +

 

+ +

Debian

+

+The installation works on a Debian 2.1 and 2.2 distribution without any problems. +How to build an optimized Debian system is not tested by me. +

 

+ +

Famous last words...

+

+I don't have the diskspace for all kinds of Linux distributions to install +at the same time, with the current size of Linux, I only have 2 versions +installed. Also, I don't buy every new distro that's available. If you have +a problem with that, just send me the new distro on CD to test by snailmail. +

 

+ +Back Go Back + + + diff --git a/html/flow.html b/html/flow.html new file mode 100644 index 00000000..0adb03cd --- /dev/null +++ b/html/flow.html @@ -0,0 +1,169 @@ + + + + + + + + +Running a BBS under Linux. + + + +

+
Last update 06-Jun-2001
+

 

+ +

Running a BBS under Linux.

+

+ +

Introduction

+

+Everyone who has been running a (single line) BBS under DOS until now will +need to understand that running a BBS under Linux (or any other multitasking +os) is completly different of what you are used to. Under DOS things were +quite simple, from AUTOEXEC.BAT you started a new .BAT file that would run +forever and started all needed programs after each other. +The programs that where started +depended on the errorlevel of the previous program. Only one program could +run at the same time. +

+People who had previous run a BBS on another multitasking os, or were running +a BBS on a small lan with a fileserver and workstations for each line, are +already more used to the idea of running more programs at the same time, +and to "signal" what to do next with semafore files. +

+The Linux aproach is more or less the same, but there are more differences. +The main difference is that there is no mailer connected with the modem waiting +for a call, instead there is a getty process watching your modem(s). Another +big difference is that you don't see what's happening, there is no screen +with the mailer or bbs picture on it. All programs run in the background. If +you don't like that, stop now and go back to your old DOS bbs. It's just the +way everything is done. +

+Programs that must start at specific times (events in DOS), are started from +cron, this is the event scheduler for Linux (and other Unixes). With this +program maintenance can be started, polls created etc. For starting programs +when they are needed there is a taskmanager loaded at system bootup. This +taskmanager "watches" the semafore directory of the bbs and will start what +is needed. +

 

+ +

Waiting for a call .....

+

+Under Linux this is done with the mgetty program, this is the +process that is connected with each modem (or ISDN adapter) and waits for a +call. The mgetty program (written by Gert Doering, gert@greenie.muc.de) will +detect the call, and find out what or who did make the call. It can detect +incoming humans who want a login prompt, PPP calls from users who want to +make a PPP connection (browsing your BBS whith netscape for example), A fax +machine trying to deliver a fax and finally a mailer trying to establish +an EMSI, FSC-0006 or FSC-0001 session. The mgetty program is responsible for +starting the right client programs. How to do this is explained in the +installation manuals, but be sure to compile it with Fido and PPP support. +

 

+ +

A Human is calling.

+

+This could be a bbs user. For each user to login to your bbs there must be a +unix account. They automatic create such an account the first time they login +with the bbs account. During the creation of their account the shell that is +installed for there account is the mbsebbs binary, so that's the only thing +that they get if they call in. When they logout the bbs, or drop carrier etc, +the session is ended and mgetty takes over the line again. +Note that they will never can get a Unix shell +unless you install a door in the bbs that calls a shell for them. +

+There are probably more accounts on your system that can callin, mbse is +such an account, this is the MBSE BBS maintenance account. This user will +get the shell prompt. Use good passwords for shell accounts, and never change +your setup so that the root user can directly login except from the console. +If you need root access, login as mbse and type su at the prompt to become +root. You might consider installing SSH on your system for remote maintenance. +

 

+ +

A PPP call is detected.

+

+Installing a PPP server on your system is beyound the scope of this project. +However if you did install it, users can login your bbs with their favourite +browser and use your bbs. Note that the necessary tools to automatic create +newsgroups don't excist at this time. With the proper setup you can automatic +create and maintain html pages for the file areas. +

 

+ +

A mailer call is detected.

+

+If a mailer is detected by mgetty, the mbcico program is started and will +take over from mgetty. It will establish a mail session with the caller and +the mail and or files will be exchanged just like any DOS mailer would do. +After the call, mbcico will hangup and mgetty will take control of your modem +again. If there is any mail received, mbcico will place the semafore mailin +so that another process can take care of the received mail. Mbcico will also +detect some IEMSI terminal programs (Frontdoor), and will start the bbs. +

 

+ +

There is mail in the inbound

+

+As I said before, if the mailin semafore is present, the task manager will +then start the mbfido program that will toss the mail, process any files +received and if necessary it will create other semafore's for example to link +the message bases, start the nodelist compiler etc. Note that this can be done +while there may be a new mailsession going on, a bbs user is online, it doesn't +matter. Processing mail and files can be done real multitasking without any +damage to other processes. +

 

+ +

It's time to poll a node

+

+At the time that you whish to poll a node, let cron create "poll" requests. +When a poll is created, the semafore scanout is also created. +The taskmanager will then start mbcico at regular intervals so that mail will +get out. If there is no more mail to send, the scanout semafore is removed. +If a timeslot ends, you can just remove the "poll" requests that didn't succeed. +

 

+ +

It's Zone Mail Hour, so now what

+

+Relax, if you have netmail ready for nodes the +mailer script will try to send these mails to those nodes. If it was crash +mail, and the destination was a non CM node, the mailer will try to send those +mails too. Note that other crashmails are send anytime. Also note that packed +mail and files are not send during ZMH. If a node calls you during ZMH he will +get everything that's waiting, including packed mail and files. The task manager +(more on that later) calculates the Zone Mail Hour from UTC time, you don't +have to change anything for summer- and wintertime. +

 

+ +

Daily maintenane

+

+This is started by cron jobs. There is no need to take +your bbs lines down during maintenance, you can do it any time of the day. +I have made several scripts for this, daily, weekly and monthly. +

 

+ +

How about system load

+

+Because Linux is a 32 bit os, not bothered with a graphical user interface +(unless you install it), it has all the time in the world to serve your +bbs programs. Background programs are build to release time to the Linux os, +they don't need to run fast because it's background processing. The bbs and +the mailer, have a low server load although there is no timerelease build +in. Only the bbs has some short moments when it needs a lot of your system, +for example when a user logs in and scans for new mail. The bbs I run is a +486-DX4 100 MHz, 20 MB ram, with 2 analogue lines, this seems to work fine. +When this system's MOBO died, I used a 386DX33 for several months with +20 MB ram, and the only thing users ever noticed was that scanning for new +mail was slower. I think this is the slowest harware that will work. +However, you must always use 16550A uarts for the COM ports. For best +performance use SCSI disks. I noticed that old 5"FH SCSI disks perform better +for bbs usage then modern EIDE disks. This is probably caused by the fact that +the kernel needs more time for the cheap IDE bus. +If you want to use X11 on your bbs, you need more ram and a faster CPU or a +separate machine via a lan and export the display to that machine. +

 

+ +Back Go Back +

+ + + diff --git a/html/ftsc/fsc-0035.html b/html/ftsc/fsc-0035.html new file mode 100755 index 00000000..f8999636 --- /dev/null +++ b/html/ftsc/fsc-0035.html @@ -0,0 +1,79 @@ + + +Transparant Gateways to and from FidoNet. + + + + +
+                  Transparent Gateways to and from FidoNet 
+                           Technical Considerations
+                                    FSC-0035
+
+                            Michael Shiels 22 June 89
+
+Copyright 1989, Michael Shiels.  All rights reserved.  The right to distribute 
+for non-commercial use is granted to the FidoNet Technical Standards Committee,
+provided that no fee is charged.  This may be posted on FidoNet electronic BBSs
+which charge no fee for accessing this document.  Any and all other reproduction
+or excerpting requires the explicit written consent of the author.
+
+
+Gateways
+--------
+
+Gatewaying between Fidonet and other networks seems to be the latest feature
+which hopefully brings more benefits to the users of each network.  But there
+are some real problems with gatewaying and doing "transparent" replies.
+This proposal should allow for almost totally transparent gateways but requires
+the co-operation of BBS software writers to support this following protocol.
+
+Incoming Messages
+-----------------
+
+When a message is entered into fidonet from another network it will be entering
+through one machine (say 1/2).  The userid on the other network may not match
+very will with the 2 word 36 character userid on Fidonet.  So the following is
+done to store away the proper userid of the sender.
+
+Two (2) lines are added to the message (usually at the top of the text portion
+hidden by the infamous ^A KLUDGE).
+
+^AREPLYADDR .....\r
+
+which signifies the FULL userid of the person on the other network.  The first
+36 characters or the full userid if less than 36 characters long, are stored
+in the FROM field of the message header.  When replies are done they use a 
+second line of the following form.
+
+^REPLYTO zone:net/node firstname lastname
+
+which is used to signify the "userid" which mail destined to this other network
+must be sent to and on which machine that userids resides.  Replies are sent
+to this zone:net/node and userid with the first line of the message being
+changed into 'TO: ....' where .... is the FULL userid from the ^AREPLYADDR
+line.
+
+Should you have constructive correction or criticism, please contact:
+
+Michael Shiels
+FidoNet: 1:250/410   michael.shiels@masnet.fidonet.org
+uucp: ?!tmsoft!masnet!michael.shiels
+Internet: michael.shiels@masnet.uucp
+
+----------
+FidoNet is a trademark of Tom Jennings and Fido Software, to whom we all owe
+        much thanks for the origin and spirit of FidoNet.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0039.html b/html/ftsc/fsc-0039.html new file mode 100755 index 00000000..53e8e955 --- /dev/null +++ b/html/ftsc/fsc-0039.html @@ -0,0 +1,362 @@ + + +A Type-2 Packet Extension Proposal. + + + + +
+Document: FSC-0039
+Version:  04
+Date:     29-Sep-90
+
+
+                      A Type-2 Packet Extension Proposal
+                       Mark A. Howard 1:260/340@FidoNet
+
+  Status of this document:
+  ------------------------
+  This FSC suggests a proposed protocol for the FidoNet(r) community,
+  and requests discussion and suggestions for improvements.  Distribution
+  of this document is unlimited.
+
+  Fido and FidoNet are registered marks of Tom Jennings and Fido Software.
+  FTS-0001 is a copyrighted work of Randy Bush.
+
+  Introduction
+  ------------
+  This document serves two major purposes.  The first is an attempt to define
+  and document the Type-2 packet which is widely in use in FidoNet today.
+  Although FTS-0001 defines the structure of a Type-2 packet, the natural
+  evolution of our network, mostly with regards to addressing methodology,
+  has made it necessary to utilize hitherto unused portions of the header
+  to insert Zone and Point information.  Also, it has become apparent that
+  some of the existing fields are not large enough to accomplish their
+  original tasks.
+
+  The second is to propose a simple mechanism to allow FidoNet to begin to
+  utilize advanced mail packing techniques.  It is quite apparent that while
+  Type-2 has served us faithfully for some time now, the evolution of our
+  network in terms of technical and physical complexity has caused us to
+  consider more efficient and functional ways to pack mail.
+
+  It should be made clear that with the exception of the Capability Word,
+  Capability Word Validation Copy, ProductCode(hi), and Revision(minor),
+  which are proposed extensions to the Type-2 packet header, this FSC is
+  an attempt to correctly document existing practices with regards to the
+  insertion of zone and point info by at least three mail processors in
+  use today.
+
+
+  The Type-2 Header (Where's the Zone?)
+  -------------------------------------
+  Although FTS-0001 has recently been updated to reflect the use of some of
+  the areas in the packed message header for zone data, at least two other
+  methods for inserting the zone information have been adopted, making it
+  necessary to provide support for both formats in all of the zone aware mail
+  processors.  The end result is more code, and redundant information in the
+  packet header.
+
+  This has presented a problem in logistics, as it is difficult to consider
+  the project of updating mail processors using one type to use the other.
+  As sufficient indentification is provided, in the form of the product code,
+  to determine the expected location of the zone information, and because
+  code already exists in most of the mail processors to overcome this, this
+  proposal does not attempt to suggest that one method be used over the
+  other, rather the intent is to attempt to document the extensions in use,
+  and the products involved.
+
+  See the accompanying chart and cross-reference.
+
+
+  The Product Code
+  ----------------
+  Based upon the current rate of requests for product codes from the FTSC,
+  it is probable that the Product Code byte will not be large enough to
+  accomodate all of the codes required.  While it is not reasonable to
+  expect that all Type-2 processors will eventually check the hi-order byte
+  proposed here, it is likely that 'current' mail processors will.  This
+  can be nothing but benefical, as it will force users to upgrade their
+  mail processors to a product which will as a minimum, support Type-2
+  with Zone and Point extensions, and quite possibly, processors that will
+  utilize more advanced mail packing techniques, making Type-2 extinct once
+  and for all.
+
+ 
+  The Capability Word  (How do we GET there from here?)
+  -----------------------------------------------------
+  Everybody would like to see more efficient and functional ways to pack and
+  exchange mail.  Several Type-3 message bundle proposals exist, but none
+  really address a problem which must be solved first.  The problem is that
+  since FidoNet is a hobbyist network, no demands can be placed on any one
+  sysop to upgrade or change their bundling software.  Because of this, it
+  is necessary to consider strategies which allow for the existence of Type-2
+  bundlers in the network topology.
+
+  Considerable advantages can be realized, however, between systems that
+  consent to use advanced bundling techniques.  One way to do this is to
+  simply send netmail to all of your connecting systems, saying "Hey, I've
+  got a Type-3 bundler now, how about you?"  This could become quite
+  tiresome, and does not represent much of an improvement on the current
+  situation.
+
+  What would be desirable is a network that would 'upgrade itself'.  Given a
+  situation where mail processors of various capabilities will exist in a
+  network topology, the goal is to provide a mechanism whereby two links can
+  determine and utilize the most efficient bundling method to use, in a
+  manner transparent to the sysop.
+
+  For instance, let's say that the FTSC releases the Type-7 All New Singing
+  and Dancing bundle format.  Well, your current version of SlingToss can
+  only support Types 2, 3, and 5.  One of your downlinks gets a new version
+  of MailMangle which can support Types 2, 3, 4, and 7.  Well, it is quite
+  obvious that since you and he are exchanging 4 megs of mail each night,
+  and it's an overseas call, that it would be in your interest to obtain a
+  new version of SlingToss which can support Type 7.
+
+  Note that this is *optional*.  Because both processors can support Type-3,
+  they will continue to exchange Type-3 mail quite happily, even though
+  MailMangle is happily advertising the availability of Type-7.  Even your
+  downlinks which are still using stone-age Type-2 processors will be fine,
+  as SlingToss will always export Type-2 bundles when no higher capability
+  can be determined.
+
+  So, after dashing off the check to the author, your new version of
+  SlingToss comes in the mail!  You rush over to your system, and install it.
+  The next time SlingToss exports mail to the MailMangle system, it says
+  "Hey!  I can now support Type 2, 3, 5, and 7!  So, whattya got?"  This is
+  no skin off MailMangle's nose, he's had Type-7 for quite a while, and he
+  begins to export Type-7 bundles to SlingToss.  "It's about time.", he says.
+
+  Now, this scenario is made possible by implementing a 'Capability Word' in
+  the present and future packet headers.  The Capability Update mechanism
+  depends on several assumptions:
+
+  1)   Any Advanced Capability Bundler *MUST* be capable of receiving and
+     faithfully processing Type-2 bundles.  Hopefully, the inbound packets
+     will be in the new format proposed by this document, but then again,
+     this is not an exact science.  What this means is that it is likely
+     that some packets may arrive with the Capability Word (CW) set to 0.
+     In this case, Type-2 is assumed, assuring compatibility.  The only
+     caveat is that it is conceivable that some obscure mail processor
+     uses the location proposed for the CW for other arcane purposes.  This
+|    can detected through the CWValidation Copy, which is byte-swapped and
+|    compared with the CW at that time.  If a mismatch is found, a CW of
+|    type 0 is assumed, and a Type-2 bundling method is used.
+
+  2) An Advanced Capability Bundler, hereafter referred to as a Type-N
+     Bundler, must have a method to store and maintain the node-by-node
+     capability information.  This can be done many ways, and in fact
+     several processors already have begun to maintain node information
+     outside of that found in AREAS.BBS, mostly to implement pre-arranged
+     alternate compression methods.  In a text configuration file, you
+     might see the following:
+
+     ;       Address      Comp    Send  LastCW ; Comments
+     Node    1:260/340    ZIP     Auto  7      ; Auto detect & upgrade
+     Node    1:135/20     LZH     3     2,3,7  ; Always send Type-3
+     Node    1:           ARC     2     0      ; Stone-Age processor
+     Node    1:135/4      ---     Auto  7      ; Sent me netmail
+     Node    1:           ---     0     0      ; Don't send CW
+
+     In this example, the fields are:
+
+     Address - downlink address.  Note that this is not necessarily
+               relative to echomail, only, it is possible to append
+               information to the node database as netmail packets are
+               receieved from different addresses.
+
+     Comp    - desired mail compression method.
+
+     Send    - Auto - automatically determined maximum common packing
+                      method to use.  Automatically update to LastCW
+                      when packing.
+
+     LastCW  - Last CW received from remote system.
+
+
+  3) A Type-N Bundle will always advertise it's capabilities in the CW
+     regardless of the type being sent.  As shown in the above example,
+     it allows Type-N processors to automatically track the capability
+     of your system.  Again, in cases where a stone-age processor is
+     being used, this field will be ignored, and in the unusual event
+     that it is not ignored, and is somehow harmful to the far system,
+     the Type-N processor can be configured to send a CW of 0.
+
+  The format of the Capability Word is designed to support up to 15 future
+  bundle types, and is bit-mapped to facilitate the easy determination of
+  the maximum common level supported between two nodes:
+
+                 msb           Capability Word               lsb
+  Node Supports  ------------FTSC Type Supported----------------
+
+                  U 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
+
+  2, 3, and 7     0  0  0  0  0  0  0  0  0  0  1  0  0  0  1  1
+  2, 3, and 5     0  0  0  0  0  0  0  0  0  0  0  0  1  0  1  1
+  2 (this FSC)    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
+  Stone Age**     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
+                  ^
+                  +--- Indicates UseNet RFC-822 capability
+
+                  ** - a mismatch in the CWValidation Copy also
+                       produces a CW=0.
+
+  In this example, the Type-N bundler would first compare the remote CW
+| and the byte-swapped remote CWValidation Copy, and check for a mismatch.
+  Prior to the compare, the MSB of the CW's are masked, as this bit is
+  reserved to indicate whether the mail processor is capable of also
+  accepting UseNet RFC-822 bundles.  Following the MSB mask, and bit
+  comparison, if they do not match, a remote CW of 0 is assumed.  If they
+  match, the Type-N processor would AND the local and remote CW words,
+  obtaining a CW expressing the Types which are in common to both systems.
+  The most significant Type will be used, by default, but note that this
+  assumes that new bundling Types will be increasingly more efficient or
+  in some way more beneficial.
+
+  Because this may not always be the case, there should be a method provided,
+  as illustrated above, to override the automatic upgrade should this become
+  the case.
+
+  The MSB of the CW is used to indicate whether the mail processor can accept
+  UseNet RFC-822 bundles or not.  It is a separate indicator, and not intended
+  to be used as a part of the above comparison, however can be used to also
+  advertise RFC-822 capability to other systems.  Since RFC-822 is 'set in
+  stone', there is no need to assign more than one capability bit.
+
+  It might seem somewhat limiting to only consider the possibility of 15
+  different future bundling methods, but it is my opinion that the careful
+  use of a 'Sub-Type' byte in the packet header can allow for the variations
+  on a single theme, and that proposals for new formats should be evaluated
+  by the FTSC to determine whether sufficient benefit can be realized in
+  the implementation of the given format, prior to assigning a new type
+  code.
+
+
+  Mailers
+  -------
+  It is quite clear to me that should this concept take hold, that the
+  logical place to store node capability data is in the local nodelist
+  database, or an index-associated data file.  As above, it is necessary
+  to generate Type-2 packets for whatever purpose, unless it is known
+  by prior association, that the far mailer can accept other types of
+  packets.  It is also quite reasonable to assume that a nodelist flag
+  could be assigned to advertise the CW for a given node, which the
+  native mailer nodelist compiler could then immediately determine the
+  preferred bundling method for any given node in FidoNet.
+
+  Another possibility would be to pass a capability advertisement in the
+  extensible portion of a handshake protocol, which may or may not already
+  exist in FidoNet.
+
+  The approach suggested previously in this document suggests the use of
+  a text configuration file, but it is quite obvious that many benefits
+  can be realized through the use of the nodelist, including the use of
+  additional flags to indicate the preferred compression method, etc.
+
+
+  Summary
+  -------
+  This document has been created in an attempt to define a method to allow
+  the future expansion and enhancement of FidoNet technology mail processors
+  and mailers, and in a way that is the least disruptive to existing mail
+  operations.  The intent is to provide for an environment that is as open,
+  and extensible as possible.
+
+  The mechanism described should allow many different types of processors
+  (FTSC-registered) to exist in the network at once, and to provide an
+  environment which is designed to operate at it's maximum efficiency
+  wherever possible or practical.
+
+  Revision 2 of this document was produced to implement suggestions made
+  primarily by Jan Vroonhof, who suggested the use of the CW Validation
+  Copy.  Jan presented this idea in his FSC-0048, along with other concepts
+  relating to the correct indentification and handling of zone and point
+  addressing.   This document sanctions the improvements to the CW as
+  recommended, but does not address or support the other extensions
+  recommended in FSC-0048.
+
+
+  Thanks
+  ------
+  To Ward Christensen, creator of XModem and BYE.
+
+     Tom Jennings, who started this whole mess.
+
+     Joaquim Homrighausen, for lots of good ideas, and motivation.  Here's
+                           another Lamborghini to work on.
+
+     Wynn Wagner, Oliver McDonald, Roeland Meyer, Andrew Farmer, Claude
+     Warren, Jan Vroonhof, Bob Hartman, and Vince Perriello, who all
+     contributed in some way to the creation of this document, mostly
+     through their messages in NET_DEV.
+
+
+
+  Type-2 Packet Format (proposed, but currently in use)
+  -----------------------------------------------------
+    Field    Ofs Siz Type  Description                Expected value(s)
+    -------  --- --- ----  -------------------------- -----------------
+    OrgNode  0x0   2 Word  Origination node address   0-65535
+    DstNode    2   2 Word  Destination node address   1-65535
+    Year       4   2  Int  Year packet generated      19??-2???
+    Month      6   2  Int  Month  "        "          0-11 (0=Jan)
+    Day        8   2  Int  Day    "        "          1-31
+    Hour       A   2  Int  Hour   "        "          0-23
+    Min        C   2  Int  Minute "        "          0-59
+    Sec        E   2  Int  Second "        "          0-59
+    Baud      10   2  Int  Baud Rate (not in use)     ????
+    PktVer    12   2  Int  Packet Version             Always 2
+    OrgNet    14   2 Word  Origination net address    1-65535
+    DstNet    16   2 Word  Destination net address    1-65535
+    PrdCodL   18   1 Byte  FTSC Product Code     (lo) 1-255
+  * PVMajor   19   1 Byte  FTSC Product Rev   (major) 1-255
+    Password  1A   8 Char  Packet password            A-Z,0-9
+  * QOrgZone  22   2  Int  Orig Zone (ZMailQ,QMail)   1-65535
+  * QDstZone  24   2  Int  Dest Zone (ZMailQ,QMail)   1-65535
+    Filler    26   2 Byte  Spare Change               ?
+| * CapValid  28   2 Word  CW Byte-Swapped Valid Copy BitField
+  * PrdCodH   2A   1 Byte  FTSC Product Code     (hi) 1-255
+  * PVMinor   2B   1 Byte  FTSC Product Rev   (minor) 1-255
+  * CapWord   2C   2 Word  Capability Word            BitField
+  * OrigZone  2E   2  Int  Origination Zone           1-65535
+  * DestZone  30   2  Int  Destination Zone           1-65535
+  * OrigPoint 32   2  Int  Origination Point          1-65535
+  * DestPoint 34   2  Int  Destination Point          1-65535
+  * ProdData  36   4 Long  Product-specific data      Whatever
+    PktTerm   3A   2 Word  Packet terminator          0000
+
+  * - extensions to FTS-0001
+
+  Ofs, Siz are in hex, other values are decimal.
+
+
+  Zone/Point Aware Mail Processors (probably a partial list)
+  ----------------------------------------------------------
+    Prod
+    Code Name - Uses QOrg/QDstZone Orig/DestZone Orig/DestPoint
+    ---- ----------- ------------- ------------- --------------
+    0x0C  FrontDoor  Reads/Updates      Yes           Yes
+    0x1A  DBridge        ?????          Yes           Yes
+    0x45  XRS        Reads/Updates      Yes           Yes
+    0x29  QMail           Yes          ?????      Not point-aware
+    0x35  ZMailQ          Yes          ?????      Not point-aware
+    0x3F  TosScan    Reads/Updates      Yes           Yes
+
+
+
+
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0046.html b/html/ftsc/fsc-0046.html new file mode 100755 index 00000000..09688a5d --- /dev/null +++ b/html/ftsc/fsc-0046.html @@ -0,0 +1,227 @@ + + +A Product Identiefier for FidoNet Message Handlers. + + + +
+Document: FSC-0046
+Version:  005
+Date:     30-Aug-94
+
+
+
+
+
+
+
+
+            A Product Idenfifier for FidoNet Message Handlers
+
+                            Joaquim Homrighausen
+                       2:270/17@fidonet or joho@abs.lu
+
+                              August 30, 1994
+
+         Copyright 1994 Joaquim Homrighausen; All rights reserved.
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+    Purpose
+
+    This document should serve as a guide for the product identfier, PID
+    hereafter, format for FidoNet message handlers. The purpose behind PIDs
+    is related to my attempt to remove the requirement of Origin lines in
+    conference mail messages.
+
+    While I fully understand that this won't happen in all conferences, I
+    would like to provide the facility to those who can use it (i.e. for
+    conferences where all the participants are using software that supports
+    messages without origin lines).
+
+    Another use for PIDs is to minimize the excessive amount of information
+    some programs put on the tear lines which increases overall
+    transportation cost and time of conference mail.
+
+
+    PID
+
+    A PID replaces the program identifier often seen on the tear line of
+    conference mail messages and is hidden behind a ^A (ASCII SOH, 01h).
+    This also allows for better tracking of software causing problems in
+    conferences.
+
+:   Only one PID per message is allowed and should only be added by the
+:   program that creates the message. I.e. programs passing the message on
+:   to someone else may not add additional PIDs. If a PID is added, no
+:   program information may be present after the tear line.
+
+    A PID also offers the ability to add serial numbers to identify a
+    specific copy of a program as being the source of a message with little
+    or no effort.
+
+
+    Format
+
+      ^APID:  [ ]
+
+
+    Sample
+
+      ^APID: FM 2.11.b
+
+      Would identify FrontDoor's editor, beta version 2.11 and replace:
+
+       --- FM 2.11 (beta)
+
+
+    Fields
+
+    pID         The ID of the product responsible for creating the message.
+                This should be kept as short as possible. The maximum
+                length for this field is 10 characters.
+
+    version     The version of the product including any alpha, beta, or
+                gamma status. Only the relevant part of the version should
+                be included. I.e. 1.00 should be expressed as 1, 1.10 as
+                1.1 and 1.01 as 1.01. Alpha, beta, or gamma status should
+                be expressed by appending a / or . followed by a, b, or g
+                and optionally a revision indicator, such as a1, b2, etc.
+                The maximum length for this field is 10 characters.
+
+    serial#     The serial number of the product, omitted if irrelevant
+                or zero. The maximum length for this field is ten (10)
+                characters.
+
+
+    TID
+
+    TIDs or "Tosser IDs" started to appear shortly after the first
+    revision of this document was released. They are added by Conference
+    Mail ("EchoMail") processors when a message is exported from the
+    local message base and injected into the network distribution scope
+    for a conference.
+
+    When a Conference Mail processor adds a TID to a message, it may not
+    add a PID. An existing TID should, however, be replaced. TIDs follow
+    the same format used for PIDs, as explained above.
+
+
+    List of products
+
+    The accompanying file, PIDLIST.TXT, is a list of products known to
+    support the PID proposal. Software authors are encouraged to inform
+    the author of this document of changes and additions to this list.
+
+     --- end of file "fsc-0046.005" ---
+
+
+
+Document: PIDLIST.TXT (FSC-0046)
+Date:     30-Aug-94
+
+
+
+                     A list of used product idenfifiers
+
+                            Joaquim Homrighausen
+                      2:270/17@fidonet or joho@abs.lu
+
+
+
+Product identifiers
+
+Product                Version  ID        Author
+-----------------------------------------------------------------------------
+!!MessageBase           1.6+    !!MB      Holger Lembke          2:240/500.20
+Alert                   2.1+    Alert     Richard Kail           2:310/25.2
+ANet                    921213+ ANet      Thomas Ekstroem        2:201/411
+ArcMail RISC OS         1.04+   AM        Philip Blundell        2:440/34.4
+Artmail Mailer System   1.00+   ART       Klaus Landefeld        2:247/402
+Auto Message Taker      1.00+   AMT       Patrik Torstensson     n/a
+AVALON                  3.10+   AVALON    Stephan Slabihoud      2:2401/103.6
+CrossPoint              2.10+   XP        Peter Mandrella        2:243/97.80
+EchoSprint              1.02+   ES        Ben Elliston           3:620/262
+Enhanced Mail MAnager   .01+    EMMA      Johan Zwiekhorst       2:292/118
+Enhanced Message EDitor .02+    EMED      Johan Zwiekhorst       2:292/118
+EZMail                  .67+    EZMail    Torben Paving          2:234/41
+F_POINT                 1.1+    F_POINT   Florian Rupp           2:248/107.2
+FastEcho                1.21a+  FastEcho  Tobias Burchhardt      2:245/39
+FileScan                1.5+    FileScan  Matthias Duesterhoeft  2:241/4513
+Freqit (Windows)        1.0+    FIW       Marvin Hart            1:106/462
+Freqit (MS-DOS)         1.0+    FID       Marvin Hart            1:106/462
+FrontDoor APX           1.00+   FDAPX     Joaquim Homrighausen   2:270/17
+FrontDoor (Editor)      2.00+   FM        Joaquim Homrighausen   2:270/17
+FrontDoor (Mailer)      2.00+   FD        Joaquim Homrighausen   2:270/17
+FrontEnd FX             1.00+   FEFX      Eric Theriault         1:132/220
+GEcho                   1.00+   GE        Gerard van der Land    2:2802/110
+GeeMail                 2.00+   GeeMail   Lech Szychowski        2:480/4.7
+HbToSca                 1.00+   HTS       Jani Laatikainen       2:220/150
+HyperBBS                2.00+   HyperBBS  Jani Laatikainen       2:220/150
+JetMail                 1.00+   JetMail   Daniel Roesen          2:243/93.8
+LazyBBS                 .5+     LazyBBS   Franck Arnaud          2:320/100
+Mail FX                 1.00+   MFX       Eric Theriault         1:132/220
+MsgTrack                3.20+   MT        Andrew Farmer          1:243/1
+NewsFlash               1.01+   NwF       Chris Lueders          2:2402/330
+NodeDiff Processor      3.00+   NDP       Serge Vikulov          2:5080/5
+Notify                  2.1     Notify    Frank Schuhardt        2:247/160
+OFFFax                  3.03    OFFFax    Frank Schuhardt        2:247/160
+Pobble                  0.15+   Pobble    Josh Parsons           3:771/340
+QBBed                   2.64+   qbbed     Werner Berghofer       2:310/90.100
+RemoteAccess            1.10+   RA        Andrew Milner          2:270/18
+RASS                    1.00+   RASS      Yossi Gottlieb         2:403/139.75
+SendFile                1.00+   SendFile  Mike Shoyher           2:5020/17.3
+Synchronet              1.00+   SYNC      Rob Swindell           1:103/705
+TB-Edit                 1.10+   TB-Edit   Arjen Lentz            2:283/512
+TB-Mailer               1.97+   TB-Mailer Arjen Lentz            2:283/512
+TB-Point                .10+    TB-Point  Arjen Lentz            2:283/512
+TechBBS                 1.00    TECHBBS   Marcel Tegelaar        2:281/409
+TechMail                1.00    TECHMAIL  Raymond van der Holst  2:281/409.2
+TosScan                 1.10+   TosScan   Joaquim Homrighausen   2:270/17
+TPCS                    .89b    TPCS      Krister Hansson-Renaud 2:201/201.7
+                                          Mikael Kjellstrom      2:201/201.10
+XRobot                  3.00+   XRobot    Joaquim Homrighausen   2:270/17
+Xrs Alternative Packer  1.04+   XAP       Jeroen Smulders        2:512/1.8
+ZeroToss                1.00    ZeroToss  Jeff Masud             1:103/115
+-----------------------------------------------------------------------------
+
+
+Product identifier registration
+
+Simply fill in the required information and send this form to the author of
+this document via private netmail.
+
+ Product: _________________________________________
+
+ Version: __________
+
+PID info: _________________________________________
+
+  Author: _________________________________________
+
+ Address: ___________________________ (eMail address)
+
+--- end of file "pidlist.txt" ---
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0048.html b/html/ftsc/fsc-0048.html new file mode 100755 index 00000000..c43b8505 --- /dev/null +++ b/html/ftsc/fsc-0048.html @@ -0,0 +1,417 @@ + + +A Proposed Type-2 Packet Extension. + + + + +
+Document: FSC-0048
+Version:  002
+Date:     21-Oct-90
+
+
+
+
+
+                   A Proposed Type-2 Packet Extension
+                              Jan Vroonhof
+                           2:281/1.12@fidonet
+                              Oct 21, 1990
+
+
+
+
+
+     Status of this document
+     =======================
+
+     This  FSC  suggests  a proposed  protocol  for  the  FidoNet(r) 
+     community,   and   requests  discussion  and  suggestions   for 
+     improvements. Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and  Fido 
+     Software.
+
+     Purpose
+     =======
+
+     The  final  goal of this document is to become  a  widely  used 
+     standardised  extension to FTS-0001,  like FTS-0006,  0007  and 
+     0008  are,  and  provide  an elegant way to  switch  to  a  new 
+     bundling  method  without requiring major  effort  or  breaking 
+     anything.
+
+     Prologue
+     ========
+
+     The  main  thing  that needs stressing is  that  the  additions 
+     covered  by this document are FULLY (I repeat FULLY)  BACKWARDS 
+     COMPATIBLE  with  FTS-0001 (and other  existing  standards  and 
+     practices  in  FidoNet and WhatEverOtherNets that I  know  of). 
+     When I say "backwards compatible" I mean that problems it would 
+     create  already  exist  in the current  FTS-0001  system  (e.g. 
+     zone  conflicts when dealing with a non compliant  system).  In 
+     short   it  only  corrects  some  flaws  in  FTS-0001   WITHOUT 
+     generating new ones.
+
+     In  this document I have tried to stay as much as  possible  on 
+     the   paths   of  existing   practices.   Therefore   I   think 
+     implementation  of  the additions it proposes will not  be  too 
+     hard.
+
+!    Prologue to revision 2
+!    ======================
+
+!    Revision   2   of  this  document  reserves  a   bit   in   the 
+!    CapabilityWord  for one bundle type already in use  outside  of 
+!    FidoNet,  RFC-822.  A small change was made to the  "receiving" 
+!    flowchart  in order to ensure compatibility with  FSC-0039.004. 
+!    In  the process a lot of errors and omissions in the  spelling, 
+!    credits etc. were corrected.
+
+     ===============
+
+!    All  references in the following to FSC-0039 are to Revision  1 
+!    of that document.
+
+     My thoughts on FSC-0039 and FTS-0001 rev 12
+     ===========================================
+
+     First,  revision  12  of FTS-0001 introduced  the  term  "(some 
+     impls)"  to indicate that some implementations used  their  own 
+!    extensions  to FTS-0001 (Note that in later revisions this  was 
+!    changed to "optional"). The problem is that this info cannot be 
+     relied upon,  because there is no way to actually validate  the 
+     data. One can only check whether the values of these fields are 
+     in the range of valid values and hope for the best.
+
+     Second,  FSC-0039  introduced  the idea of  having  a  bitfield 
+     (called the Capability Word) indicating whether extension  data 
+     was  valid.  Through  the  Capability Word,  it  also  made  it 
+     possible to indicate the ability to support other,  non type 2, 
+     packets,  thus allowing for flexible migration towards type  3. 
+     It  also documented the addressing extensions used  by  various 
+     programs.
+
+     However, FSC-0039 has two flaws:
+
+     1. One  cannot  be  sure the bitfield  is  zero  because  other 
+        implementations might use this field for their own purposes. 
+        Therefore  this document includes a second  validation  copy 
+        for the Capability Word (CW hereafter). This copy allows the 
+        FSC-xxxx compliant software to validate the CW by  comparing 
+        the two.  The chance of some junk portraying itself as a  CW 
+        is significantly reduced by this.
+
+!       Please  note  that  the  validation  copy  is  byte  swapped 
+!       compared to the normal capability word.  While this  started 
+!       out  as a typo,  I decided to leave it in as  it  introduces 
+!       some extra safety, without requiring much extra code effort. 
+!       In later revisions of FSC-0039,  Mark adopted this idea of a 
+!       validation copy too and eliminated the problem.
+
+     2. Although  FSC-0039 provides a way to make packet headers  4D 
+        it  is not backwards compatible.  It cannot be used in  FTS-
+        0001 sessions to unknown systems,  making FidoNet still  not 
+        totally 4D capable.  Although it implements fields for  zone 
+        and point number,  an FTS-0001 compliant application is  not 
+        required to look at these fields.  When a point mails  using 
+        these  fields  to implement its 4D address,  a  system  only 
+        looking  at the net/node info,  as is required by  FTS-0001, 
+        still sees it as a boss node, causing the obvious problems.
+
+        This document provides a way for transparent point handling, 
+        using   a  technique  already  exploited  by  many   mailers 
+        internally.  It  will allow this document to be  implemented 
+        and used by mailers not supporting it.  At the same time the 
+        danger that a point is seen as the boss node is eliminated.
+ 
+        It does NOT provide full inter-zone backwards compatibility, 
+        but that is not needed as badly, as problems are not yet too 
+        great.  Any  measures to ensure backwards  compatibility  in 
+        this  area  might  harm  communication  with  non-supporting 
+        programs, when the old system could handle the situation.
+
+     Packet Header
+     =============
+
+     The "|" character is used to indicate extensions documented  in 
+     FTS-0001  revision  12,   the  ":"  character  indicates  those 
+     documented here and in FSC-0039.
+
+       Offset
+      dec hex
+              .-----------------------------------------------------.
+        0   0 | origNode     (low order) | origNode    (high order) |
+              +--------------------------+--------------------------+
+        2   2 | destNode     (low order) | destNode    (high order) |
+              +--------------------------+--------------------------+
+        4   4 | year         (low order) | year        (high order) |
+              +--------------------------+--------------------------+
+        6   6 | month        (low order) | month       (high order) |
+              +--------------------------+--------------------------+
+        8   8 | day          (low order) | day         (high order) |
+              +--------------------------+--------------------------+
+       10   A | hour         (low order) | hour        (high order) |
+              +--------------------------+--------------------------+
+       12   C | minute       (low order) | minute      (high order) |
+              +--------------------------+--------------------------+
+       14   E | second       (low order) | second      (high order) |
+              +--------------------------+--------------------------+
+       16  10 | baud         (low order) | baud        (high order) |
+              +--------------------------+--------------------------+
+       18  12 |      0      |      2     |      0      |      0     |
+              +--------------------------+--------------------------+
+       20  14 | origNet      (low order) | origNet     (high order) |
+:             |               Set to -1 if from point               |
+              +--------------------------+--------------------------+
+       22  16 | destNet      (low order) | destNet     (high order) |
+              +--------------------------+--------------------------+
+|      24  18 | ProductCode  (low order) | Revision         (major) |
+|             +--------------------------+--------------------------+
+|      26  1A |                      password                       |
+|             |               8 bytes, null padded                  |
+|             +--------------------------+--------------------------+
+|:     34  22 | origZone     (low order) | origZone    (high order) | }
+|             +--------------------------+--------------------------+ } As in
+|:     36  24 | destZone     (low order) | destZone    (high order) | } QMail
+:             +--------------------------+--------------------------+
+:      38  26 | AuxNet       (low order) | AuxNet      (high order) |
+:             +--------------------------+--------------------------+
+:      40  28 | CWvalidationCopy  (high) | CWvalidationCopy   (low) |
+:             +--------------------------+--------------------------+
+:      42  2A | ProductCode (high order) | Revision         (minor) |
+:             +--------------------------+--------------------------+
+:      44  2C | CapabilWord  (low order) | CapabilWord (high order) |
+:             +--------------------------+--------------------------+
+:      46  2E | origZone     (low order) | origZone    (high order) | }
+:             +--------------------------+--------------------------+ } As in
+:      48  30 | destZone     (low order) | destZone    (high order) | } FD etc
+:             +--------------------------+--------------------------+
+:      50  32 | origPoint    (low order) | origPoint   (high order) | }
+:             +--------------------------+--------------------------+ } As in
+:      52  34 | destPoint    (low order) | destPoint   (high order) | } FD etc
+:             +--------------------------+--------------------------+
+:      54  46 |                 Product Specific Data               |
+:             +                                                     +
+:             |                       4 Bytes                       |
+              +--------------------------+--------------------------+
+       58  3A |                     zero or more                    |
+              ~                        packed                       ~
+              |                       messages                      |
+              +--------------------------+--------------------------+
+              |      0      |      0     |      0      |      0     |
+              '-----------------------------------------------------'
+
+    Packet       = PacketHeader  { PakdMessage }  00H 00H
+
+    PacketHeader = origNode       (* of packet, not of messages in packet   *)
+                   destNode       (* of packet, not of messages in packet   *)
+                   year           (* of packet creation, e.g. 1986          *)
+                   month          (* of packet creation, 0-11 for Jan-Dec   *)
+                   day            (* of packet creation, 1-31               *)
+                   hour           (* of packet creation, 0-23               *)
+                   minute         (* of packet creation, 0-59               *)
+                   second         (* of packet creation, 0-59               *)
+                   baud           (* max baud rate of orig and dest         *)
+                   PacketType     (* old type-1 packets now obsolete        *)
+                   origNet        (* of packet, not of messages in packet
+                                     set to -1 if orig=point                *)
+                   destNet        (* of packet, not of messages in packet   *)
++                  productCode Lo (* 0 for Fido, write to FTSC for others   *)
+|+                 serialNo Maj   (* binary serial number (otherwise null)  *)
+|                  password       (* session pasword  (otherwise null)      *)
+|                  origZone       (* zone of pkt sender (otherwise null)    *)
+|                  destZone       (* zone of pkt receiver (otherwise null)  *)
+|                  auxNet         (* contains Orignet if Origin is a point  *)
++!        Bytesw.  CWvalidationCopy (* Must be equal to CW to be valid      *)
++                  ProductCode Hi
++                  revision Minor
++                  origZone       (* zone of pkt sender (otherwise null)    *)
++                  destZone       (* zone of pkt receiver (otherwise null)  *)
++                  ProdData       (* Product specific filler                *)
+
+     When  the two copies of the CW match they can be asumed  to  be 
+     valid and used.
+
+     Stone-Aged: Old FTS-0001
+     Type-2+   : Old FTS-0001 plus changes indicated by "|" and  ":" 
+                 are valid
+
+     A  Type-N Bundle will always advertise its capabilities in  the 
+     CW regardless of the type being sent.   As shown in the example 
+     below,  the CW allows Type-N processors to automatically  track 
+     the capability of your system.   Again, in cases where a stone-
+     age processor is being used, this field will be ignored, and in 
+     the  unusual  event  that it is not  ignored,  and  is  somehow 
+     harmful  to  the  far  system,  the  Type-N  processor  can  be 
+     configured to send a CW of 0.
+
+     The format of the Capability Word is designed to support up  to 
+     15  future bundle types,  and is bit-mapped to  facilitate  the 
+     easy  determination  of  the  maximum  common  level  supported 
+     between two nodes:
+
+                    msb           Capability Word               lsb
+     Node Supports  ------------FTSC Type Supported **)------------
+
+                     U 16 15 14 13 12 11 10  9  8  7  6  5  4  3 2+
+
+     2+,3, and 7     0  0  0  0  0  0  0  0  0  0  1  0  0  0  1  1
+     2+,3, and 5     0  0  0  0  0  0  0  0  0  0  0  0  1  0  1  1
+     2+ (this Doc)   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
+     Stone Age       0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
+
+!                    ^-- "U" Indicates nodes able to process RFC-822 
+!                        bundles.
+                    ** - In the example bit definitions only type 2, 
+                         and  the Stone-Age type,  are defined  now. 
+                         The rest are to be concidered "reserved  by 
+                         FTSC".
+
+     The receiving Type-N bundler would AND the two words, obtaining 
+     a  word  expressing  the Types which are  common  to  both  the 
+     receiving  and the sending system.   The most significant  Type 
+     will be used for future sessions,  by default. Please note that 
+     this assumes that new bundling Types will be increasingly  more 
+     efficient or in some way more beneficial.  Because this may not 
+     always  be  the  case,  there should be a  method  provided  to 
+     override the automatic upgrade,  as illustrated  above,  should 
+     this ever happen.
+
+!    N.B. The  one bit left over (Msb) is now used as indicator  for 
+!         RFC-822 type bundles. For info on RFC-822 please check out 
+!         the relevant documents themselves.
+
+!         For  a more explanatory text on using the CW to  its  full 
+!         potential,  refer  to  the FSC-0039 text by  Mark  Howard. 
+!         Mark also gives some more rationale for the origional idea 
+!         of the CW.
+
+     Generating Type-2+ bundles
+     ==========================
+
+      Do we have a CW              Does CW indicate
+     stored for dest?  YES ---->   higher packets  YES ---> Generate higher
+           NO                       we support?                packet
+           |                            NO
+          \|/                           |
+           +-----<----------------------+
+           |
+      Fill header with all info
+           |
+          \|/
+           |
+      Are we sending from a point? (origPoint != 0) YES --+
+           |                                              |
+          NO                                              |
+           |                                             \|/
+           |                                    set AuxNet = OrigNet
+          \|/                                  set OrigNet = -1
+           |                                              |
+           +-----<----------------------------------------+
+           |
+      Add Messages
+           |
+      Terminate packet
+           |
+       Send packet
+
+     Receiving Type-2+ bundles
+     =========================
+
+       Receive Packet
+           |
+       Packettype = 2  NO  -------------> Process Type-Other
+          YES
+           |
+           |
+       CWcopies match  NO --------+------> Treat as normal Stone-Age packet
+          YES                     |     |
+           |                      |     |
+       Store CW                  /|\    |
+           |                      |    /|\
+       CW is 0 YES  --------------+     |
+          NO                            |
+           |                            |
+           |                            |
+       CW indicates support for 2+ NO --+
+          YES
+           |
+           |
+!      OrigPoint is not 0 and OrigNet = -1 YES -------+
+           NO                                         |
+           |                                         \|/
+!         \|/                            Set OrigNet is AuxNet
+           |                                          |
+           +------<-----------------------------------+
+           |
+        Process using added info
+
+     Credits
+     =======
+
+     To Mark Howard,  for introducing the idea of a CW in his  FSC-
+     0039  document and quite rightly pointing out one big  omision 
+     in revision 1 of this document.
+
+     To  Rick Moore,  for doing a good job in processing all  these 
+     revisions by Mark and myself, and for his work for the FTSC in 
+     general.
+
+     To  Joaquim  Homrighausen,  for his contributions  to  FidoNet 
+     software  in general,  and especially for his time devoted  to 
+     reading,  discussing  and  implementing the ideas Mark  and  I 
+     introduced.
+
+     To  Andre van de Wijdeven,  for producing and letting me  beta 
+     test his TS-MM software, which in my opinion is the best point 
+     software around.  (I'm not saying available,  because it isn't 
+     :-()
+
+     To john lots, for shipping this stuff to the US.
+
+     To  Jon  Webb,  for doing a much needed grammar  and  spelling 
+     check.
+
+     To Bob Hartman, Vince Periello, Tom Jennings, Eelco de Graaff, 
+     aXel Horst,  Arjen van Loon,  jim nutt,  Odinn Sorensen, David 
+     Nugent,  Peter  Janssens and many others,  for making  FidoNet 
+     what it is now, for me and for everybody.
+
+     Epilog
+     ======
+
+     So  this it,  now it's up to you to decide whether or  not  to 
+     implement  it.  A  small  change was  made  in  the  receivers 
+     flowchart and a small incompatibility with the later revisions 
+     of  FSC-0039 was removed.  That will ensure that FSC-0048  and 
+     FSC-0039 mailers can happily talk to each other....
+
+     The best way to implement this would be to always support FSC-
+     0048  on inbound trafic and generate FSC-0048 on  outbound  by 
+     default. A switch on a per-node basis will force your software 
+     to be FSC-0039 or even FSC-0001 only,  and you will cover  all 
+     bases.
+
+     This can be done easily, as FSC-0048 is a superset of FSC-0039 
+     (The -1 thing on points being the difference) which in turn is 
+     a superset of FTS-0001 (CW). I'd be glad to get some feedback. 
+     You can put it in NET_DEV or netmail me.
+
+                              Jan Vroonhof (2:281/1.12@fidonet)
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0049.html b/html/ftsc/fsc-0049.html new file mode 100755 index 00000000..d4787917 --- /dev/null +++ b/html/ftsc/fsc-0049.html @@ -0,0 +1,103 @@ + + +A Proposal for Passing Domain Information During an FST-0006 Session. + + + + +
+Document: FSC-0049
+Version:  001
+Date:     03-Jul-90
+
+
+
+
+                               A Proposal for
+                         Passing Domain Information
+                         During an FTS-0006 Session
+
+                                     by
+                                Bob Hartman
+                           1:104/501@fidonet.org
+                                July 3, 1990
+
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+FSC-0045 proposes a method for sending five dimensional FidoNet addresses
+(ie, zone:net/node.point@domain) via the type 2 packet header.  This
+document describes a proposed method for sending the same five dimensional
+address in the Hello packet of an FTS-0006 session, with the additional
+advantage of being able to utilize the full Internet recognized domain name
+for various Fidonet technology networks.  This proposal, combined with
+FSC-0045 will help to solve one of FidoNet's most pressing problems: How to
+recognize alternative networks without the need of some centralized
+management looking at all of them and what they are doing with Zone numbers,
+etc.  Like FSC-0045, this proposal remains backwards compatible with what it
+is replacing.
+
+Currently FTS-0006 has provisions for zone, net, node, and point information
+to be passed in the Hello packet.  To extend this to allow the domain name
+to be passed, an extra capability bit is used.  This bit corresponds to the
+0x4000 bit, and will be called the DO_DOMAIN bit.  If this bit is set, it
+means that the sender is domain aware, and has enclosed his domain in the
+Hello packet.  The domain is stored in the system name field, after the null
+that terminates the real system name.  The system name field is a maximum of
+60 characters, so the sender must make the real system name, a null, the
+domain name, and another null byte fit within the 60 bytes.  The domain will
+start at the byte immediately after the first null byte.  The domain is
+arbitrary length and should correspond to the Internet assigned domain name.
+This is NOT the same as the FSC-0045 domain, and therefore there needs to be
+a mapping between real Internet domains, and the FSC-0045 style domain name,
+if FSC-0045 is accepted by the FTSC as a standard for use by all mailers.
+This mapping is normally straightforward (for example, Internet fidonet.org
+would correspond to FSC-0045 domain FidoNet).  Since most alternative nets
+do not have a registered Internet domain, the naming convention should be
+"known by" domain (ie, FSC-0045 domain name) followed by .ftn (for FidoNet
+Technology Network).  So, the FSC-0045 domain "Alternet" would be converted
+to alternet.ftn under this proposal.  This allows domains which are not
+normally FidoNet aware to use FTS-0006 to talk to FidoNet technology mail
+programs.  For example, a mailer located at Camex in Manchester, NH might
+send it's mail as 'man.camex.com' during an FTS-0006 session.  When parsing
+the domain name, the parsing should try to match the domain from right to
+left (Internet naming is hierarchical from right to left), so that if a
+mailer knew about man.camex.com, that could also match something of the form
+super.machine.silly.name.man.camex.com.  The domain name should be case
+INSENSITIVE, and the FSC-0045 abbreviation of it should be unique within the
+first 8 characters, and also should not include any periods ('.') or at-signs
+('@') since those characters are significant in the Internet domain naming
+scheme.
+
+In order for this proposal to be adopted, the FTSC would have to assign the
+DO_DOMAIN bit, and have it documented in FTS-0006.  This method is fully
+backwards compatible, since a domain aware mailer could send the domain
+information, and if the other end was not domain aware, it would ignore it.
+If the other end was domain aware, it would be able to extract the domain
+information easily and would then have a full five dimensional address
+available for the sender.  This proposal remains fully backward compatible
+with the current uses of all FTS-0006 fields, and should not affect operation
+of any mailer that has used reserved bytes in the Hello packet.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0050.html b/html/ftsc/fsc-0050.html new file mode 100755 index 00000000..a1a7cb0e --- /dev/null +++ b/html/ftsc/fsc-0050.html @@ -0,0 +1,98 @@ + + +A Character Set Identifier For FidoNet Message Editors. + + + + +
+Document: FSC-0050
+Version:  001
+Date:     14-Jul-90
+
+
+
+
+         A Character Set Identifier For FidoNet Message Editors
+
+                                Draft I
+
+                           Thomas Sundblom
+                          2:201/114@fidonet
+
+
+
+			  
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+   Purpose
+
+        This document should serve as a guide for the character set 
+        identifier, CHARSET hereafter, format for FidoNet message Editors.
+        The purpose behind CHARSET is related to my attempt to make it
+        easier for each reader of a FidoNet message to identify the 
+        characters used in the messages.
+
+        Since FidoNet messages aren't restricted to use any special character
+        sets in the messages, there will be differences between computer 
+        kinds and special country dependent characters. To avoid confusion
+        in such cases, I'm hereby introducing the CHARSET kludge.
+
+        There is no need that each FidoNet Message reader should be able
+        to understand every possible character set. If the reader can't
+        handle the special character set found in a message, then it should
+        use a default character set (as most readers do today).
+
+
+   Format
+
+        ^aCHARSET: 
+
+   Sample
+
+        ^aCHARSET: ISO-11
+
+        Would identify that the message is written using the ISO-11 
+        character set, which relates to the character set mainly used
+        in Sweden.
+
+
+   Supported character sets
+
+        No special character set is specified, but it is recomended to
+        use the ISO numbering of the different character sets. Where no
+        ISO number is available, an easy to understand code should by used.
+
+
+   Character set identifier examples
+
+        ISO-6       Relates to plain ASCII 7 bit character set.
+        ISO-11      Swedish character set, 7 bit.
+        ISO-21      Germany character set, 7 bit.
+        ISO-69      French character set, 7 bit.
+
+        Other character set identifiers could be
+        PC-8        IBM PC complete character set.
+        ATARI       ATARI ST complete character set
+        AMIGA       AMIGA complete character set
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0053.html b/html/ftsc/fsc-0053.html new file mode 100755 index 00000000..fe764e7a --- /dev/null +++ b/html/ftsc/fsc-0053.html @@ -0,0 +1,187 @@ + + +Specifications for the ^aFLAGS field. + + + + +
+Document: FSC-0053
+Version:  002
+Date:     08-Dec-92
+
+
+
+
+
+
+                    Specifications for the ^aFLAGS field
+
+                           Joaquim H. Homrighausen
+                       2:270/17@fidonet or joho@ae.lu
+
+                              December 8, 1992
+
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+     Purpose
+
+     To explain and document the existing usage of the ^aFLAGS field used
+     by many software packages, including FrontDoor, TosScan, and
+     D'Bridge. And to inform software authors of its proper usage.
+
+
+     Prologue
+
+     One of the problems with the FTS-1 (stored) message format is its
+     limitations in regards to message attributes. Several bits are used
+     (reserved) by SEAdog, another by several packers and editors - even
+     though most mailer authors don't support them, they remain. One
+     reason would be backward compatibility with older software.
+
+     Unfortunately, this presents a problem for software authors that
+     would like to pass extended message attributes for use and handling
+     by other software.
+
+     Some software packages have been using an alternate method called
+     "FLAGS" which is 7-bit ASCII placed behind FLAGS somewhere near
+     the beginning of a message. The various flags will now be described.
+
+
+     Flags
+
+     The FLAGS string should be placed somewhere near the beginning of
+     the message text, and is preceeded by a  (^a) character. There
+     is no need to support all or any of the below mentioned flags.
+
+     If flags are stripped when a message passes through a system, all
+     relevant and correct FTS-1 status bits should be updated to indicate
+     the original contents of the FLAGS field.
+
+
+     Flag      Brief          Long description
+     --------------------------------------------------------------------
+     PVT       Private        Indicates that the message may only be read
+                              by its addressee and author.
+
+     HLD       Hold           Message should be held for pickup by its
+                              destination system.
+
+     CRA       Crash          High-priority mail.
+
+     K/S       Kill/Sent      Remove message after it has been success-
+                              fully sent.
+
+     SNT       Sent           Message has been successfully sent (used
+                              for message without Kill/Sent status).
+
+     RCV       Received       Message has been read by its addressee.
+
+     A/S       Archive/Sent   Place message in "sent mail" archival
+                              system after it has been successfully sent.
+
+     DIR       Direct         Message must be sent directly to its
+                              destination and may not be routed.
+
+     ZON       Zonegate       Send message through zonegate (if
+                              possible).
+
+     HUB       Hub/Host-route Host- or Hub-route message (as
+                              appropriate).
+
+     FIL       File attach    Message has one or more files attached to
+                              it.
+
+     FRQ       File request   Message has one or more file requests in
+                              subject field.
+
+     IMM       Immediate      NOW!-priority mail. Send at first
+                              opportunity, override any transmission
+                              restrictions enforced by events, costs, or
+                              qualification.
+
+     XMA       Xmail          Message has alternate form of compressed
+                              mail attached.
+
+     KFS       Kill file      Remove attached file(s) after they have
+                              been successfully sent. Only valid for file
+                              attach message.
+
+     TFS       Truncate file  Truncate attached file(s) to zero length
+                              after they have been successfully sent.
+                              Only valid for file attach message.
+                              Primarily used by Conference Mail
+                              processors.
+
+     LOK       Lock           Prevent message from being processed.
+                              This includes sending, deleting,
+                              purging, and editing.
+
+     RRQ       Receipt REQ    When the mailer/packer at the message's
+                              final destination unpacks the message, it's
+                              asked to generate a receipt to the author
+                              of the message that indicates that the
+                              message arrived at its final destination.
+
+     CFM       Confirm REQ    When message is read by its addressee, a
+                              Confirmation Receipt should be generated to
+                              the author of the message.
+
+     HIR       HiRes          FAX: Hi-Resolution image.
+
+     COV       CoverLetter    FAX: Cover sheet.
+
+     SIG       Signature      FAX: Signature.
+
+     LET       LetterHead     FAX: LetterHead.
+
+|    FAX       Fax image      The filename specified in the message's
+|                             subject field contains a fax document that
+|                             should be viewed using software capable of
+|                             doing so.
+
+|    FPU       Force pickup   Treated as a message with an IMM flag. This
+|                             instructs the mailer to keep calling the
+|                             destination system, if the connection is
+|                             aborted for some reason, until a valid "End
+|                             of files" signal is received (i.e. no more
+|                             files remain to pick up).
+
+
+     Notes
+
+     Xmail is related to the ARCmail 0.60 standard as adopted by the FTSC.
+     The exception is that any type of compression method may be used and
+     the naming convention isn't necessarily limited to that of the
+     ARCmail 0.60 standard.
+
+
+     Epilogue
+
+     Feedback would be appreciated and can be sent to me at the addresses
+     specified on the title page. Please send feedback via netmail.
+
+ +Back Go Back + + + + + diff --git a/html/ftsc/fsc-0056.html b/html/ftsc/fsc-0056.html new file mode 100755 index 00000000..eeb6b3ad --- /dev/null +++ b/html/ftsc/fsc-0056.html @@ -0,0 +1,1078 @@ + + +EMSI/IEMSI Protocol Definitions. + + + + +
+Document: FSC-0056
+Version:  001
+Date:     03-May-1991
+
+
+
+
+
+                      EMSI/IEMSI Protocol Definitions
+                          Joaquim H. Homrighausen
+                               May 3, 1991
+ 
+
+
+
+    Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is subject to the restrictions
+     specified on the next page.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+
+
+      (Also known as EMSC-001; Electronic Mail Standards Document #001)
+    ---------------------------------------------------------------------
+      Copyright 1989-1991 Joaquim H. Homrighausen. All rights reserved.
+    ---------------------------------------------------------------------
+
+
+    Notice
+    =====================================================================
+    This document obsoletes EMSI_003 and any previous document describing
+    the EMSI, UZAP, and/or IEMSI handshake protocol. I apologize for the
+    lack of proper state charts. I am currently under a fairly heavy
+    work-load and thought it would be better to release something half-
+    decent than not to release anything at all.
+
+    Restrictions
+    =====================================================================
+    EMSI/IEMSI may be used by any developer as long as these
+    specifications are followed exactly. The IEMSI and EMSI specifications
+    may be implemented independently of each other.
+
+    EMSI/IEMSI may be used free-of-charge by any developer for any
+    purpose, commercially or otherwise. In creating EMSI/IEMSI, we are
+    taking the first step towards developing a clear protocol definition
+    for state-of-the-art E-Mail systems to follow.
+
+    This document and its NOTES file (EMSI.NOT) may be freely copied and
+    distributed, but must NEVER be distributed in a modified form. If you
+    have an enhancement request, please contact the author of this
+    document; do not change it yourself.
+
+    Permission is hereby granted to the FTSC (Fidonet Technical Standards
+    Committee) and other technical organisations to republish this
+    document in its entirety. Librarians may change the title page and
+    page headers to match their library format as long as all copyrights
+    and body text remain unaltered. The original document name and source
+    (EMSC) must be mentioned in any republished versions of this
+    document.
+
+    No organization, company, person, or other being may impose any fees
+    for any reason for providing this document. This document may not be
+    sold or otherwise transferred for personal or company gain under any
+    circumstances.
+
+    Layout
+    =====================================================================
+    This document consists of four major parts; A short introduction and
+    explanation of the EMSI/IEMSI handshake protocol, the EMSI
+    definitions, the IEMSI definitions, and finally various notes and
+    credits.
+
+
+    PART I
+
+    Introduction
+    =====================================================================
+    The EMSI/IEMSI handshake protocol allows for maximum flexibility in
+    E-Mail session start-up and control. The YooHoo (FTS-6) standard,
+    designed by Wynn Wagner III, was a good idea, but did not allow
+    sufficient room for growth and cannot be used in 7-bit environments.
+    EMSI/IEMSI should provide for virtually unlimited growth and
+    expansion of its own scope. By providing variable-length packets,
+    EMSI/IEMSI is capable of being as simple or as complex as necessary
+    and entirely backwards compatible when new features and/or protocols
+    are added.
+
+    All EMSI/IEMSI packets and sequences consists of 7-bit printable
+    ASCII characters. This format allows us to establish a universal
+    handshake between "PCs" and "mainframes" alike. The more complicated
+    the computer system, the more restrictions affect its I/O; there are
+    many I/O channels that cannot transmit control characters such as XON
+    and XOFF; for this, we have created a universal handshake protocol
+    that uses all printable characters.
+
+    EMSI/IEMSI does allow control and 8-bit ASCII characters to be
+    transmitted. This is, however, accomplished by escaping the data
+    and converting it to 7-bit printable ASCII characters.
+
+    Data layer
+    =====================================================================
+    EMSI/IEMSI is a protocol based on multi-character sequences rather
+    than single character flow control. There are several advantages of
+    using several characters rather than just one, but there is also a
+    drawback. On very poor-quality telephone lines, EMSI will most likely
+    require several retransmissions of packets since line noise usually
+    come in bursts. That aside, there is little advantage in using a
+    protocol based on single characters.
+
+    All EMSI/IEMSI sequences are terminated by a single  unless
+    otherwise specified. This is necessary to force some data collection
+    equipment to flush their buffers. Appending  to EMSI/IEMSI
+    sequences in a FidoNet environment is a delicate matter and it is
+    important that you follow the notes regarding this.
+
+    Note regarding file requests
+    ---------------------------------------------------------------------
+    The file request concept mentioned in the EMSI document refers to
+    WaZOO style file requests as specified in FTS-6. No other file
+    request mechanism is supported in the EMSI specifications.
+
+
+    Separator usage
+    ---------------------------------------------------------------------
+    To designate the fields within the EMSI/IEMSI packets and retain
+    complete transparency, both start and stop characters are used.
+
+    The ASCII1 type is used for all fields within the packet. This uses
+    the brace characters to delimit the fields. The '{' (ASCII 123)
+    character is the start byte and '}' (ASCII 125) is the stop byte.
+    If a stop byte is used as literal data within a field, it must be
+    transmitted twice. The end of a field is designated by a stop byte
+    that is not followed by another identical stop byte.
+
+    The ASCII2 fields are delimited in exactly the same way, but use the
+    square brackets as delimiters. The '[' (ASCII 91) is the start byte
+    and ']' (ASCII 93) is the stop byte. ASCII2 is used to delimit data
+    within the ASCII1 extra_field information.
+
+    7-bit data restriction
+    ---------------------------------------------------------------------
+    It is the developer's responsibility to ensure that the software
+    generates EMSI/IEMSI packets and sequences containing only 7-bit
+    (00H through 7eH) printable ASCII characters.
+
+    It is recommended that all EMSI/IEMSI implementations strip the high-
+    order bit of all received characters prior to processing the packet/
+    sequence and prior to calculating CRC values.
+
+    CRC values
+    ---------------------------------------------------------------------
+    The polynomial used to calculate a 16-bit CRC is the same polynomial
+    used in the Xmodem file transfer protocol. The polynomial used to
+    calculate a 32-bit CRC is the same polynomial used in the Zmodem file
+    transfer protocol.
+
+    Binary values
+    ---------------------------------------------------------------------
+    Since the EMSI environment specifies only 7-bit printable ASCII
+    characters to be used, binary values, such as CRC and length
+    descriptors are expressed as a four character hexadecimal string. The
+    only exception to this is a 32-bit CRC value which is expressed as an
+    eight character hexadecimal string.
+
+    The application must treat them case insensitive, eg. ffaa should be
+    treated identical to FFAA. 
+
+
+    Handling 8-bit data
+    ---------------------------------------------------------------------
+    Although EMSI only uses 7-bit printable ASCII characters, there is an
+    escape mechanism that allows systems to transmit control and 8-bit
+    ASCII characters without the requirement of an 8-bit data link. The
+    escape character is a backslash character ('\') and is followed by two
+    characters in hexadecimal notation. Eg. "\80" is the ASCII character
+    128. To insert an actual backslash character, two backslashes are used
+    ("\\"), or a backslash followed by the hexadecimal code for a
+    backslash, eg. "\5c".
+
+    The hexadecimal code following a backslash MUST always be two
+    characters, ie. to insert ASCII 15 (hexadecimail 'f'), the result
+    would be "0f". All hexadecimal sequences must be treated case
+    insensitively.
+
+
+    PART II - Electronic Mail Standard Idenfitication
+
+    Connecting two EMSI capable systems
+    =====================================================================
+    This assumes that the two systems are connected and that no data
+    has been transmitted by the Caller.
+
+    It should be mentioned that sending/monitoring for the "YooHoo",
+    "TSYNC", and other protocol start characters is optional and not
+    required for a strict EMSI implementation.
+
+    STEP 1, EMSI INIT    
+
+        Calling system                   Answering system
+    +-+-------------------------------+----------------------------------+
+    :1: Send  until ANY character : Send EMSI_REQ and possible       :
+    : : is received.                  : banner, etc.                     :
+    +-+-------------------------------+----------------------------------+
+    :2: Receive banner, etc. Monitor  : Monitor line for the EMSI_INQ    :
+    : : line for the EMSI_REQ         : sequence and if received,        :
+    : : sequence and if received,     : attempt to handshake immediately.:
+    : : transmit EMSI_INQ and attempt :                                  :
+    : : to handshake immediately.     :                                  :
+    +-+-------------------------------+----------------------------------+
+    :3: No EMSI_REQ sequence received,: Monitor line for EMSI_INQ and    :
+    : : send EMSI_INQ twice followed  : possible other protocol start    :
+    : : by possible other protocol    : characters and if received,      :
+    : : start characters.             : attempt to handshake immediately.:
+    : :                               :                                  :
+    : : Transmit                  : Go to step 3.                    :
+    +-+-------------------------------+----------------------------------+
+    :4: If EMSI_REQ sequence received,:
+    : : send EMSI_INQ and attempt to  :
+    : : handshake immediately,        :
+    : : otherwise repeat step 3.      :
+    +-+-------------------------------+
+
+    In steps 1 and 2, both the Calling and Answering system terminate all
+    sequences with . In step 3, the Calling system does not terminate
+    sequences with  as it is explicitly transmitted after possible
+    protocol start characters. In step 4, the Calling system once again
+    terminate all sequences with a .
+
+
+    STEP 2A, RECEIVE EMSI HANDSHAKE
+
+    At this point, all sequences are terminated with a .
+
+    +-+------------------------------------------------------------------+
+    :1: Tries=0, T1=20 seconds, T2=60 seconds                            :
+    +-+------------------------------------------------------------------+
+    :2: Increment Tries                                                  :
+    : :                                                                  :
+    : : Tries>6?                      Terminate, and report failure.     :
+    : +------------------------------------------------------------------+
+    : : Are we answering system?      Transmit EMSI_REQ, go to step 3.   :
+    : +------------------------------------------------------------------+
+    : : Tries>1?                      Transmit EMSI_NAK, go to step 3.   :
+    : +------------------------------------------------------------------+
+    : : Go to step 4.                                                    :
+    +-+------------------------------------------------------------------+
+    :3: T1=20 seconds                                                    :
+    +-+------------------------------------------------------------------+
+    :4: Wait for EMSI sequence until EMSI_HBT or EMSI_DAT or any of the  :
+    : : timers have expired.                                             :
+    : :                                                                  :
+    : : If T2 has expired, terminate call and report failure.            :
+    : +------------------------------------------------------------------+
+    : : If T1 has expired, go to step 2.                                 :
+    : +------------------------------------------------------------------+
+    : : If EMSI_HBT received, go to step 3.                              :
+    : +------------------------------------------------------------------+
+    : : If EMSI_DAT received, go to step 5.                              :
+    : +------------------------------------------------------------------+
+    : : Go to step 4.                                                    :
+    +-+------------------------------------------------------------------+
+    :5: Receive EMSI_DAT packet                                          :
+    : +------------------------------------------------------------------+
+    : : Packet received OK?                Transmit EMSI_ACK twice, and  :
+    : :                                    go to step 6.                 :
+    : +------------------------------------------------------------------+
+    : : Go to step 2.                                                    :
+    +-+------------------------------------------------------------------+
+    :6: Received EMSI_DAT packet OK, exit.                               :
+    +-+------------------------------------------------------------------+
+
+    All processing of the information in the EMSI_DAT packet must be done
+    after transmitting EMSI_ACK twice to the remote system. It is
+    recommended that an EMSI_HBT sequence is issued once every seven
+    seconds while such processing is taking place to avoid unnecessary
+    handshake collissions. Emitting EMSI_HBT should only be done when
+    it is obvious that the remote system is waiting for the second phase
+    of the EMSI handshake to take place.
+
+
+
+    STEP 2B, TRANSMIT EMSI HANDSHAKE
+
+    At this point, all sequences are terminated with a .
+
+    +-+------------------------------------------------------------------+
+    :1: Tries=0, T1=60 seconds                                           :
+    +-+------------------------------------------------------------------+
+    :2: Transmit EMSI_DAT packet and increment Tries                     :
+    : :                                                                  :
+    : +------------------------------------------------------------------+
+    : : Tries>6?                        Terminate, and report failure.   :
+    : +------------------------------------------------------------------+
+    : : Go to step 3.                                                    :
+    +-+------------------------------------------------------------------+
+    :3: T2=20 seconds                                                    :
+    +-+------------------------------------------------------------------+
+    :4: Wait for EMSI sequence until T1 has expired                      :
+    : :                                                                  :
+    : : If T1 has expired, terminate call and report failure.            :
+    : +------------------------------------------------------------------+
+    : : If T2 has expired, go to step 2.                                 :
+    : +------------------------------------------------------------------+
+    : : If EMSI_REQ received, go to step 4.                              :
+    : +------------------------------------------------------------------+
+    : : If EMSI_ACK received, go to step 5.                              :
+    : +------------------------------------------------------------------+
+    : : If any other sequence received, go to step 2.                    :             :
+    +-+------------------------------------------------------------------+
+    :5: Received EMSI_ACK, exit.                                         :
+    +-+------------------------------------------------------------------+
+
+
+    EMSI packet and sequence definitions
+    =====================================================================
+
+    =====================================================================
+    EMSI Inquiry                                    **EMSI_INQ
+    ---------------------------------------------------------------------
+    EMSI Inquiry is transmitted by the calling system to identify it as
+    EMSI capable. If an EMSI_REQ sequence is received in response, it is
+    safe to assume the answering system to be EMSI capable.
+
+    =====================================================================
+    EMSI Request                                    **EMSI_REQ
+    ---------------------------------------------------------------------
+    EMSI Request is transmitted by the answering system in response to an
+    EMSI Inquiry sequence. It should also be transmitted prior to or
+    immediately following the answering system has identified itself by
+    transmitting its program name and/or banner. If the calling system
+    receives an EMSI Request sequence, it can safely assume that the
+    answering system is EMSI capable.
+    
+    =====================================================================
+    EMSI Client                                     **EMSI_CLI
+    ---------------------------------------------------------------------
+    EMSI Client is used by terminal emulation software to force a mailer
+    front-end to bypass any unnecessary mail session negotiation and
+    treat the call as an incoming human caller. The EMSI_CLI sequence may
+    not be issued by any software attempting to establish a mail session
+    between two systems and must only be acted upon by an answering
+    system.
+
+    =====================================================================
+    EMSI Heartbeat                                  **EMSI_HBT
+    ---------------------------------------------------------------------
+    EMSI Heartbeat is used to prevent unnecessary timeouts from occurring
+    while attempting to handshake. It is most commonly used when the
+    answering system turns around to transmit its EMSI_DAT packet. It is
+    quite normal that any of the timers of the calling system (which at
+    this stage is waiting for an EMSI_DAT packet) expires while the
+    answering system is processing the recently received EMSI_DAT packet.
+
+    =====================================================================
+    EMSI Data                      **EMSI_DAT
+    ---------------------------------------------------------------------
+    EMSI Data is transmitted by both the calling and answering system at
+    the appropriate time to exchange system information. Following the
+    header is a four byte number representing the length of 
+    excluding the CRC and terminating .
+
+    The EMSI_DAT packet is a variable length packet. Since this is a
+    synchronous protocol, the inbound data buffer should be purged
+    between transmission of the  and  fields to prevent
+    accidental EMSI_NAK sequences, etc.
+
+
+    =====================================================================
+    EMSI ACK                                        **EMSI_ACK
+    ---------------------------------------------------------------------
+    EMSI ACK is transmitted by either system as a positive
+    acknowledgement of the valid receipt of a EMSI_DAT packet. This should
+    only be used as a response to EMSI_DAT and not any other packet.
+    Redundant EMSI_ACK sequences should be ignored.
+
+    =====================================================================
+    EMSI NAK                                        **EMSI_NAK
+    ---------------------------------------------------------------------
+    EMSI NAK is transmitted by either system as a negative
+    acknowledgement of the valid receipt of a EMSI_DAT packet. This
+    should only be used as a response to EMSI_DAT and not any other
+    packet. Redundant EMSI_NAK packets should be ignored.
+
+    The EMSI_DAT packet
+    =====================================================================
+    The EMSI_DAT packet is the core of an EMSI negotiated session. It
+    contains information vital to the mail session. The following pseudo
+    structure shows the layout of the EMSI_DAT packet.
+
+    EMSI_DAT
+        fingerprint,            "EMSI"
+        system_address_list,
+        password,
+        link_codes,
+        compatibility_codes,
+        mailer_product_code,
+        mailer_name,
+        mailer_version,
+        mailer_serial_number:    ASCII1;
+        extra_field_1,
+            ..
+            ..
+        extra_field_n:            EMSI_addon; (optional fields)
+    end;
+
+    The EMSI_addon structure is defined as follows:
+
+    EMSI_addon
+        product_ID,
+        specific_data:            ASCII1;
+    end;
+
+
+    Following is an example of the actual data transmitted as an EMSI_DAT
+    packet:
+
+    {EMSI}{2:270/17}{}{8N1,PUA}{ZAP,ZMO,ARC,XMA}{44}{AirMail}{0.10}
+    {Beta-2}{IDENT}{[Advanced Engineering S.A.R.L.][Luxembourg]
+    [Joaquim Homrighausen][-Unpublished-][9600][MO,XA,HST,V32B,V42B]}
+
+    EMSI_DAT field definitions
+    ---------------------------------------------------------------------
+    
+    =====================================================================
+    Fingerprint                                                      EMSI
+    ---------------------------------------------------------------------
+    The constant "EMSI". There is no need for a revision level since this    
+    basic format cannot change and remain backward compatible.
+
+    =====================================================================
+    System address list
+    ---------------------------------------------------------------------
+    The system address list is a list of system-specific identifiers for
+    the E-Mail system separated by spaces.
+
+    For FidoNet-technology based networks, it is required that
+    Zone:Net/Node be presented, and .Point be omitted if zero. Zone and
+    Net must not be zero.
+
+    In other networks, an address such as "jhom@csource.oz.au" should be
+    considered valid.
+
+    =====================================================================
+    Password
+    ---------------------------------------------------------------------
+    For systems using a session level password, it would be passed in
+    this field. Note that the same password is used for all presented
+    addresses and that it must be treated case insensitive.
+
+    =====================================================================
+    Link codes
+    ---------------------------------------------------------------------
+    Link codes is a string of flags that specify desired connect
+    conditions. These codes are separated by commas. New codes may be
+    added with prior approval from the author of this document.
+
+    Calling system/answering system options:
+
+        8N1,
+        7E1,
+        7O2,
+        etc.       Communication parameters.
+
+    Calling system options:
+
+        PUA        Pickup mail for all presented addresses.
+        PUP        Pickup mail for primary address only.
+        NPU        No mail pickup desired.
+
+
+    Answering system options:
+
+        HAT        Hold ALL traffic.
+        HXT        Hold compressed mail traffic.
+        HRQ        Hold file requests (not processed at this time).
+
+    =====================================================================
+    Compatibility codes
+    ---------------------------------------------------------------------
+    Compatibility codes is a string of flags that specifies the
+    capabilities and enabled features of the mailer. These codes are
+    separated by commas. New codes may be added with prior approval from
+    the author of this document.
+     
+    The calling system must list supported protocols first and descending
+    order of preference (the most desirable protocol should be listed
+    first). The answering system should only present one protocol and it
+    should be the first item in the compatibility_codes field.
+
+        Protocols
+        -----------------------------------------------------------------
+        DZA*    DirectZAP (Zmodem variant).
+        ZAP     ZedZap (Zmodem variant).
+        ZMO**   Zmodem w/1,024 byte data packets.
+        JAN     Janus.
+        KER     Kermit.
+
+        Other codes
+        -----------------------------------------------------------------
+        NCP     No compatible protocols (failure).
+        NRQ     No file requests accepted by this system.
+        ARC     ARCmail 0.60-capable, as defined by the FTSC.
+        XMA     Supports other forms of compressed mail.
+        FNC     Filename conversion. This indicates that any transmitted
+                files must follow the MS-DOS restrictions of an eight
+                character file name followed by a three character
+                extension; eg. FILENAME.EXT
+
+    (*) DirectZAP is a variant of ZedZap. The difference is that the
+    transmitter only escapes CAN (18H). It is not recommended to use the
+    DirectZAP protocol when two systems are connected via a packet
+    switching network, or via another layer sensitive to control
+    characters such as XON and XOFF.
+
+    (**) The minimum protocol requirement for an EMSI implementation is
+    to support plain Zmodem (16- or 32-bit CRC, 1,024 byte packets) which
+    is represented by the ZMO flag in EMSI.
+
+    =====================================================================
+    Mailer product code
+    ---------------------------------------------------------------------
+    The hexadecimal representation of the EMSC product code assigned to
+    the mailer. Currently, the EMSC codes are the same as the FTSC
+    assigned codes.
+
+    =====================================================================
+    Mailer name
+    ---------------------------------------------------------------------
+    Specifies the name of the E-Mail system sending the EMSI packet.
+
+    =====================================================================
+    Mailer version
+    ---------------------------------------------------------------------
+    The version number of the mailer software, ie. "1.10", "2.00".
+
+    =====================================================================
+    Mailer serial number
+    ---------------------------------------------------------------------
+    The serial number, distribution source, version information, etc.
+    This field is usually displayed like:
+
+        NameVersion/Serial_number
+
+    eg.
+
+        AirMail 0.10/Beta-2
+
+    =====================================================================
+    Extra fields
+    ---------------------------------------------------------------------
+    The extra fields make the EMSI handshake protocol extremely flexible.
+    Any program or mailer may add fields to the end of the pre-defined
+    structure so that program-specific data may be passed without the
+    concern of interferring with other systems.
+
+    There may be any number of extra fields added to the end of this
+    structure. Each EXTRA_FIELD contains two ASCII1 strings:
+
+    PRODUCT_IDENTIFIER      A unique "tag" that defines a specific
+                            program (such as a mailer or a utility).
+
+    SPECIFIC_DATA           ASCII text that is specific data to the
+                            program defined in PRODUCT_IDENTIFIER. With
+                            this structure, any program can add its own
+                            data to the EMSI packet without affecting
+                            other applications.
+
+    It is recommended that you contact the author of this document should
+    you have any EXTRA_FIELDS that you may think worthwhile for other
+    developers to implement and support.
+
+    Predefined extra fields
+    ---------------------------------------------------------------------
+    The following extra fields have been defined to date.
+
+    PRODUCT_IDENTIFIER   :  IDENT
+
+    Purpose              :  General identification of system that
+                            includes all information to generate a St.
+                            Louis-format nodelist entry.
+
+    SPECIFIC_DATA        :  system_name,
+                            city,
+                            operator_name,
+                            phone_number,
+                            baud_rate,
+                            flags:            ASCII2;
+
+        SYSTEM_NAME         The name of the system given by the user.
+                            This would normally be a company name, BBS
+                            name or other identifying text.
+
+        CITY                The geographical location of the system.
+
+        OPERATOR_NAME       The name of the person primarily responsible
+                            for the system.
+
+        PHONE_NUMBER        The telephone number of the system, or
+                            "-Unpublished-" if the telephone number is
+                            unpublished. This MUST be in the standard
+                            format COUNTRY-CITY-NUMBER. Leading zeros
+                            should be stripped from the city code,
+                            ie. Stockholm (Sweden) has a city code of 08,
+                            included in an EMSI packet, it would read
+                            46-8-.
+
+        BAUD_RATE           The maximum baud rate supported by the
+                            system. This is NOT necessarily the same as
+                            the highest DTE rate.
+
+        FLAGS               The St. Louis (FTSC) nodelist flags
+                            associated with the system.
+
+
+    PART III - Interactive Electronic Mail Standard Idenfitication
+
+    Connecting two IEMSI capable systems
+    =====================================================================
+    Two specific labels are used when discussing the IEMSI definitions.
+    The Client, which in this case is the Terminal software, and the
+    Server, which in this case is the interactive on-line software,
+    such as a BBS package or database system. It is assumed that the
+    Client and the Server have established a data link and that no
+    data has been transmitted by the Server.
+
+    STEP 1, IEMSI INIT    
+
+    There is no specific sequence of events in the IEMSI definition. The
+    Client must monitor incoming data and if the EMSI_IRQ sequence is
+    detected, it attempts to negotiate an IEMSI session with the Server.
+    Under no circumstances is the Client allowed to transmit an EMSI_ICI
+    packet prior to receiving the EMSI_IRQ sequence from the Server.
+    All IEMSI sequences and EMSI sequences used during an IEMSI session
+    are terminated by a single . There are no exceptions to this.
+
+
+    STEP 2A, Server
+
+    +-+------------------------------------------------------------------+
+    :1: Tries=0, T2=60 seconds                                           :
+    +-+------------------------------------------------------------------+
+    :2: Transmit EMSI_IRQ sequence                                       :
+    +-+------------------------------------------------------------------+
+    :3: T1=20 seconds, increment Tries                                   :
+    : :                                                                  :
+    : : Tries>3?                        Discontinue IEMSI negotiation.   :
+    +-+------------------------------------------------------------------+
+    :4: Wait for EMSI_ICI packet until any of the timers have expired.   :
+    : :                                                                  :
+    : : If T2 has expired, discontinue IEMSI negotiation.                :
+    : +------------------------------------------------------------------+
+    : : If T1 has expired, go to step 2.                                 :
+    : +------------------------------------------------------------------+
+    : : If EMSI_ICI seen, go to step 5.                                  :
+    : +------------------------------------------------------------------+
+    : : Go to step 4.                                                    :
+    +-+------------------------------------------------------------------+
+    :5: Receive EMSI_ICI packet                                          :
+    : +------------------------------------------------------------------+
+    : : Packet received OK?             Transmit EMSI_ISI packet, and    :
+    : :                                 go to step 6.                    :
+    : +------------------------------------------------------------------+
+    : : Packet not received OK?         Transmit EMSI_NAK and go to step :
+    : :                                 3.                               :
+    +-+------------------------------------------------------------------+
+    :6: Tries=0                                                          :
+    +-+------------------------------------------------------------------+
+    :7: T1=20 seconds, increment Tries                                   :
+    : :                                                                  :
+    : : Tries>3?                        Discontinue IEMSI negotiation.   :
+    +-+------------------------------------------------------------------+
+    :8: Wait for EMSI_ACK/EMSI_NAK until any of the timers have expired. :
+    : :                                                                  :
+    : : If T2 has expired, discontinue IEMSI negotiation.                :
+    : +------------------------------------------------------------------+
+    : : If T1 has expired or EMSI_NAK received, transmit EMSI_ISI packet :
+    : : again and go to step 7.                                          :
+    : +------------------------------------------------------------------+
+    : : If EMSI_ACK received, go to step 9.                              :
+    : +------------------------------------------------------------------+
+    : : Go to step 8.                                                    :
+    +-+------------------------------------------------------------------+
+    :9: IEMSI session successfully established, exit.                    :
+    +-+------------------------------------------------------------------+
+
+    The Server must monitor its incoming data channel for 'normal' data,
+    ie. data not transmitted as IEMSI sequences, to detect if the user is
+    attempting to log-in without the use of IEMSI. The only basic
+    restriction this imposes on the Server is that user names and/or IDs
+    may not start with the character '*' since all EMSI/IEMSI sequences
+    start with this character.
+
+    All processing of the information in the EMSI_ICI packet must be done
+    after transmitting the EMSI_ISI packet and receiving two EMSI_ACK
+    sequences in return.
+
+
+    STEP 2B, Client
+
+    Note that this assumes that the Client has seen the EMSI_IRQ sequence
+    transmitted by the Server and that the negotiation is ready to take
+    place.
+
+    +-+------------------------------------------------------------------+
+    :1: Tries=0, T2=60 seconds                                           :
+    +-+------------------------------------------------------------------+
+    :2: Transmit EMSI_ICI packet                                         :
+    +-+------------------------------------------------------------------+
+    :3: T1=20 seconds, increment Tries                                   :
+    +-+------------------------------------------------------------------+
+    :5: Tries>3 or T2 expired?            Discontinue IEMSI negotiation. :
+    : +------------------------------------------------------------------+
+    : : If T1 has expired, go to step 2.                                 :
+    : +------------------------------------------------------------------+
+    : : If EMSI_ISI seen, go to step 6.                                  :
+    : +------------------------------------------------------------------+
+    : : Go to step 5.                                                    :
+    +-+------------------------------------------------------------------+
+    :6: Receive EMSI_ISI packet                                          :
+    : +------------------------------------------------------------------+
+    : : Packet received OK?              Transmit EMSI_ACK packet twice, :
+    : :                                  and go to step 7.               :
+    : +------------------------------------------------------------------+
+    : : Packet not received OK?          Transmit EMSI_NAK and go to step:
+    : :                                  3.                              :
+    +-+------------------------------------------------------------------+
+    :7: IEMSI session successfully established, exit.                    :
+    +-+------------------------------------------------------------------+
+
+    All processing of the information in the EMSI_ISI packet must be done
+    after transmitting two EMSI_ACK sequences in return.
+
+    If either of the ICI or ISI packets are NAK'd three consecutive times,
+    the session negotiation attempt is terminated and the Client proceeds
+    as it would have done should the Server not have supported IEMSI.
+
+
+    IEMSI packet and sequence definitions
+    =====================================================================
+
+    =====================================================================
+    EMSI ACK                                        **EMSI_ACK
+    ---------------------------------------------------------------------
+    EMSI ACK is transmitted by either Client or Server as a positive
+    acknowledgement of the valid receipt of an IEMSI packet such as
+    EMSI_ISI and EMSI_ICI. During an IEMSI session, this sequence can,
+    however, be used as a positive acknowledgement for other IEMSI
+    packets. Redundant EMSI_ACK sequences should be ignored.
+
+    =====================================================================
+    EMSI NAK                                        **EMSI_NAK
+    ---------------------------------------------------------------------
+    EMSI NAK is transmitted by either Client or Server as a negative
+    acknowledgement of the valid receipt of an IEMSI packet such as
+    EMSI_ISI and EMSI_ICI. During an IEMSI session, this sequence can,
+    however, be used as a negative acknowledgement for other IEMSI
+    packets. Redundant EMSI_NAK sequences should be ignored.
+
+    =====================================================================
+    EMSI IRQ                                        **EMSI_IRQ
+    ---------------------------------------------------------------------
+    Similar to EMSI_REQ which is used by mailer software to negotiate a
+    mail session. IRQ identifies the Server as being capable of
+    negotiating an IEMSI session. When the Client detects an IRQ sequence
+    in its inbound data stream, it attempts to negotiate an IEMSI
+    session.
+
+    =====================================================================
+    EMSI IIR                                        **EMSI_IIR
+    ---------------------------------------------------------------------
+    The IIR (Interactive Interrupt Request) sequence is used by either
+    Client or Server to abort the current negotiation. This could be
+    during the initial IEMSI handshake or during other interactions
+    between the Client and the Server.
+
+    =====================================================================
+    EMSI ICI                             **EMSI_ICI
+    ---------------------------------------------------------------------
+    The ICI packet is used by the Client to transmit its configuration
+    and Server-related information to the Server. It contains Server
+    parameters, Client options, and Client capabilities.
+
+    =====================================================================
+    EMSI ISI                             **EMSI_ISI
+    ---------------------------------------------------------------------
+    The ISI packet is used by the Server to transmit its configuration
+    and Client-related information to the Client. It contains Server data
+    and capabilities.
+
+    =====================================================================
+    EMSI ISM                             **EMSI_ISM
+    ---------------------------------------------------------------------
+    The ISM packet is used to transfer ASCII images from the Server to
+    the Client. These images can then be recalled by the Client when
+    the Server needs to display a previously displayed image. This will
+    be further described in future revisions of this document.
+
+    =====================================================================
+    EMSI CHT                                        **EMSI_CHT
+    ---------------------------------------------------------------------
+    The CHT sequence is used by the Server to instruct the Client
+    software to enter its full-screen conversation mode function (CHAT).
+    Whether or not the Client software supports this is indicated in the
+    ICI packet.
+
+    If the Server transmits this sequence to the Client, it must wait for
+    an EMSI_ACK prior to engaging its conversation mode. If no EMSI_ACK
+    sequence is received with ten seconds, it is safe to assume that the
+    Client does not support EMSI_CHT. If, however, an EMSI_NAK sequence
+    is received from the Client, the Server must re-transmit the
+    EMSI_CHT sequence. Once the on-line conversation function has been
+    sucessfully activated, the Server must not echo any received
+    characters back to the Client.
+
+    =====================================================================
+    EMSI TCH                                        **EMSI_TCH
+    ---------------------------------------------------------------------
+    The TCH sequence is used by the Server to instruct the Client
+    software to terminate its full-screen conversation mode function
+    (CHAT).
+
+    If the Server transmits this sequence to the Client, it must wait for
+    an EMSI_ACK prior to leaving its conversation mode. If no EMSI_ACK
+    sequence is received with ten seconds, a second EMSI_TCH sequence
+    should be issued before the Server resumes operation. If, however, an
+    EMSI_NAK sequence is received from the Client, the Server must
+    re-transmit the EMSI_TCH sequence.
+
+
+    The EMSI_ICI packet
+    =====================================================================
+    The following pseudo structure shows the layout of the EMSI_ICI
+    packet. Note that the information in the EMSI_ICI packet may not
+    exceed 2,048 bytes.
+
+    EMSI_ICI
+        name,
+        alias,
+        location,
+        data#,
+        voice#,
+        password,
+        birthdate,
+        crtdef,
+        protocols,
+        capabilities,
+        requests,
+        software,
+        xlattabl:                ASCII1;
+    end;
+
+    EMSI_ICI field definitions
+    ---------------------------------------------------------------------
+    
+    =====================================================================
+    Name and Alias (or Handle)
+    ---------------------------------------------------------------------
+    The name and possible alias (AKA) of the user (Client). This must be
+    treated case insensitively by the Server.
+
+    =====================================================================
+    Location
+    ---------------------------------------------------------------------
+    The geographical location of the user, ie. Stockholm, Sweden.
+
+    =====================================================================
+    data# and voice#
+    ---------------------------------------------------------------------
+    Unformatted data and voice telephone numbers of the user. Unformatted
+    is defined as the full telephone number, including country and local
+    area code. Eg. 46-8-90510 is a telephone number in Stockholm, Sweden.
+
+    =====================================================================
+    Password
+    ---------------------------------------------------------------------
+    The password for the user. This must be treated case insensitively by
+    the Server.
+
+    =====================================================================
+    Birthdate
+    ---------------------------------------------------------------------
+    Hexadecimal string representing a long integer containing the birth-
+    date of the user in UNIX notation (number of seconds since midnight,
+    Jan 1 1970). This must be treated case insensitively by the Server.
+
+    =====================================================================
+    CrtDef
+    ---------------------------------------------------------------------
+    Consisting of four sub-fields separated by commas, this field
+    contains from left to right: The requested terminal emulation
+    protocol, the number of rows of the user's CRT, the number of columns
+    of the user's CRT, and the number of ASCII NUL (00H) characters the
+    user's software requires to be transmitted between each line of text.
+
+    The following terminal emulation protocols are defined:
+
+        AVT0    AVATAR/0+. Used in conjunction with ANSI. If AVT0 is
+                specified by the Client, support for ANSI X3.64 emulation
+                should be assumed to be present.
+        ANSI    ANSI X3.64
+        VT52    DEC VT52
+        VT100   DEC VT100
+        TTY     No terminal emulation, also referred to as RAW mode.
+
+    =====================================================================
+    Protocols
+    ---------------------------------------------------------------------
+    The file transfer protocol option specifies the preferred method of
+    transferring files between the Client and the Server in either
+    direction. The Client presents all transfer protocols it is capable
+    of supporting and the Server chooses the most appropriate protocol.
+
+        DZA*    DirectZAP (Zmodem variant)
+        ZAP     ZedZap (Zmodem variant)
+        ZMO     Zmodem w/1,024 byte data packets
+        SLK     SEAlink
+        KER     Kermit
+    
+    (*) DirectZAP is a variant of ZedZap. The difference is that the
+    transmitter only escapes CAN (18H). It is not recommended to use the
+    DirectZAP protocol when the Client and the Server are connected via a
+    packet switching network, or via another layer sensitive to control
+    characters such as XON and XOFF.
+
+
+    =====================================================================
+    Capabilities
+    ---------------------------------------------------------------------
+    The capabilities of the user's software. If more than one capability
+    is listed, each capability is separated by a comma.
+
+    The following capability codes are defined:
+
+        CHT     Can do full-screen on-line conversation (CHAT).
+        MNU     Can do ASCII image download (see ISM packet).
+        TAB     Can handle TAB (ASCII 09H) characters.
+        ASCII8  Can handle 8-bit IBM PC ASCII characters.
+
+    =====================================================================
+    Requests
+    ---------------------------------------------------------------------
+    The requests field specifies what the user wishes to do once the
+    initial IEMSI negotiation has been successfully completed. If more
+    than one capability is listed, each capability is separated by a
+    comma.
+
+    The following request codes are defined:
+
+        NEWS    Show bulletins, announcements, etc.
+        MAIL    Check for new mail.
+        FILE    Check for new files.
+        HOT     Hot-Keys.
+        CLR     Screen clearing.
+        HUSH    Do not disturb.
+        MORE    Page pausing, often referred to as "More".
+        FSED*   Full-screen editor.
+        XPRS    .
+
+    (*) Note that this allows the Client to request use of a full-screen
+    editor without requiring that it also supports a full-screen terminal
+    emulation protocol.
+
+    =====================================================================
+    Software
+    ---------------------------------------------------------------------
+    The name, version number, and optionally the serial number of the
+    user's software. Eg. {FrontDoor,2.00,AE000001}.
+
+    =====================================================================
+    XlatTabl
+    ---------------------------------------------------------------------
+    Used for character translation between the Server and the Client.
+    This field has not been completely defined yet and should always be
+    transmitted as {} (empty).
+
+
+    The EMSI_ISI packet
+    =====================================================================
+    The following pseudo structure shows the layout of the EMSI_ISI
+    packet. Note that the information in the EMSI_ISI packet may not
+    exceed 2,048 bytes.
+
+    EMSI_ISI
+        id,
+        name,
+        location,
+        operator,
+        localtime,
+        notice,
+        wait,
+        capabilities:            ASCII1;
+    end;
+
+    EMSI_ISI field definitions
+    ---------------------------------------------------------------------
+    
+    =====================================================================
+    ID
+    ---------------------------------------------------------------------
+    The name, version number, and optionally the serial number of the
+    Server software. Eg. {RemoteAccess,1.10/b5,CS000001}.
+
+    =====================================================================
+    Name
+    ---------------------------------------------------------------------
+    The name of the Server system. Eg. {Advanced Engineering S.A.R.L.}.
+
+    =====================================================================
+    Location
+    ---------------------------------------------------------------------
+    The geographical location of the user, ie. Stockholm, Sweden.
+
+    =====================================================================
+    Operator
+    ---------------------------------------------------------------------
+    The name of the primary operator of the Server software. Eg. {Joaquim
+    H. Homrighausen}.
+
+
+
+    =====================================================================
+    Localtime
+    ---------------------------------------------------------------------
+    Hexadecimal string representing a long integer containing the current
+    time of the Server in UNIX notation (number of seconds since midnight,
+    Jan 1 1970). This must be treated case insensitively by the Client.
+
+    =====================================================================
+    Notice
+    ---------------------------------------------------------------------
+    May contain copyright notices, system information, etc. This field
+    may optionally be displayed by the Client.
+
+    =====================================================================
+    Wait
+    ---------------------------------------------------------------------
+    A single character used by the Server to indicate that the user
+    has to press the  key to resume operation. This is used in
+    conjunction with ASCII Image Downloads (see ISM packet).
+
+    =====================================================================
+    Capabilities
+    ---------------------------------------------------------------------
+    The capabilities of the Server software. No Server software
+    capabilities have currently been defined.
+
+    Credits and other notes
+    =====================================================================
+    The original EMSI specifications were designed by Chris Irwin and
+    Joaquim H. Homrighausen. The original IEMSI specifications were
+    designed by Joaquim H. Homrighausen and Andrew Milner.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0057.html b/html/ftsc/fsc-0057.html new file mode 100755 index 00000000..1355fff7 --- /dev/null +++ b/html/ftsc/fsc-0057.html @@ -0,0 +1,533 @@ + + +Conference Managaers - Specifications for Requests. + + + + +
+Document: FSC-0057
+Version:  003
+Date:     07-Dec-92
+
+
+
+
+               Conference Managers - Specifications for Requests
+
+                               December 7, 1992
+
+                   Fabiano Fabris      Joaquim H. Homrighausen
+                2:285/304.100@fidonet      2:270/17@fidonet
+
+
+
+
+    Status of this document:
+
+    This FSC suggests a proposed protocol for the FidoNet(r) community, and
+    requests discussion and suggestions for improvements. Revision 3
+    presents several additions and enhancements over the previous revision.
+
+    Distribution of this document is unlimited.
+
+    Fido and FidoNet are registered marks of Tom Jennings and Fido
+    Software.
+
+
+
+    1  Purpose
+
+       This document will explore the methods implemented by various
+       conference managers which process requests (in net mail form)
+       for changes to the conference mail links on the system on which
+       they are in use.
+
+       Until now, it would appear that no real standard exists, so most
+       software authors have either tried to emulate another program, or
+       to create a new method of their own, or both.
+
+       Here, an attempt will be made to define a standard, one which tries
+       to maintain compatibility with methods already in use, while also
+       extending them to provide new functions.
+
+
+
+    2  Conventions
+
+       The names of the commands described in the following paragraphs are
+       given in upper case, for legibility. However, a conference manager
+       should be able to interpret them even if they are given in lower
+       or mixed case.
+
+       Similarly, conference names, or tags, are given in upper case, but
+       the conference manager should be able to handle them even if typed
+       in lower or mixed case.
+
+       Optional information is enclosed with square brackets, while
+       variable information is enclosed with angle brackets. For example:
+
+          +CONF [,R=]
+
+       indicates that the section within square brackets is optional, and
+       if supplied, requires a parameter after the equals sign.
+
+       Some conference managers may allow commands to be abbreviated to the
+       shortest non-ambiguous string. For example, %LIST might be reduced
+       to %L.
+
+
+
+    3  Format of the request
+
+       A request to a conference manager is generally made in a net mail
+       message containing specific information in some of the fields. In
+       particular, the addressee is the name of the conference manager
+       itself, and the subject of the message is a password assigned by
+       the sysop of the system running the program.
+
+       For example:
+
+          From:     John Doe, on 2:123/56
+          To:       Program,  on 2:234/0
+          Subject:  password
+
+       Here the first problem is encountered. Each of the existing programs
+       recognizes a different addressee. For this reason it is proposed
+       that all such programs recognize requests made to a single,
+       "standard" addressee, besides any other they may wish to implement.
+       The term "ConfMgr" has been arbitrarily chosen, and should be used
+       by those programs which adhere fully to all the standards proposed
+       in this document.
+
+       The text of the message itself contains the request proper, and is
+       the subject of the following paragraphs.
+
+
+
+    4  Linking and Unlinking of conferences.
+
+       The current methods for requesting that a conference be linked are
+       basically two:
+
+          +CONFNAME
+          CONFNAME
+
+       For reasons of uniformity, it is proposed that all conference
+       manager programs recognize the first method.
+
+       Requests that a conference be unlinked are given by:
+
+          -CONFNAME
+
+       It might be interesting to implement some form of pattern matching,
+       similar to the unix shell. The following basic wildcards should be
+       considered:
+
+          *        matches zero or more characters
+          ?        matches any one (not zero) character
+
+       Since the requests are processed top-down, a request of the form
+
+          +CONFNAME
+          -*
+
+       would be redundant, since the ConfMgr would link CONFNAME from the
+       first line, and then immediately unlink it again because of the
+       second line, which requests that all linked conferenecs be unlinked.
+
+       It should also be possible to specify more than one conference tag
+       on the same line. For example:
+
+          +CONF1 CONF2 CONF3
+
+       would link the three conferences CONF1, CONF2 and CONF3.
+
+
+
+    5  Rescanning Conference Mail
+
+       Many conference managers currently allow a system to request that an
+       area be "rescanned". In other words, the system receiving the
+       request will export all mail in one or more areas to the requesting
+       system.
+
+       This may be accomplished by specifying the %RESCAN command in the
+       body of the request. This will force the ConfMgr to generate a scan
+       request for those areas which the remote system requested with the
+       message containing the %RESCAN command.
+
+       Rescans of a single area, newly linked, could be requested as
+       follows:
+
+          +CONFNAME, R[=]
+
+       where 'n' is the number of messages in that area to be rescanned.
+       (The space following the comma is optional, but allowed.)
+
+       Rescanning has one serious drawback: dupes! It is very possible for
+       the requesting system to have already set up the area with several
+       downlinks. Thus, when the rescanned mail is received, it could be
+       exported to other systems. In a tree-based topology, this is
+       harmless, but in circular topologies this would create dupes.
+
+       Thus, it is proposed that system receiving the rescan request add a
+       kludge to the messages, so that they can be recognized by the
+       requesting system and not re-exported.
+
+       The proposed kludge is:
+
+          ^ARESCANNED 
+
+       where  is the network address, including domain, of the
+       system from which the mail was rescanned.
+
+       In alternative to a rescan, a sysop might request a "sample",
+       consisting of a series of messages contained in a text file. The
+       ConfMgr would export some or all messages from an area to a plain
+       ASCII text file, and send it along with the reply, to the requesting
+       system. A "sample" request would be made as follows:
+
+          +CONFNAME, S[=]
+
+       where 'n' indicates how many messages should be sampled.
+
+       a) Updating Conferences
+
+          Update requests allow a sysop to rescan or "sample" an area
+          without having to first unlink from it, and then relink with the
+          rescan or "sample" parameter.
+
+          The format of this command is:
+
+             =CONFNAME, [=]
+
+          Thus a rescan request for the most recent 50 messages would be
+          specified as:
+
+             =CONFNAME, R=50
+
+
+
+    6  Information Requests
+
+       Requests for information have until now taken two forms. In one
+       case, they are given as switches after the password on the subject
+       line, while in the second they are given as "commands" within the
+       body of the message text. It is proposed that the second method be
+       chosen as standard, since it is considerably more flexible.
+
+       Below are listed the proposed commands:
+
+         %HELP                    Sends a (pre-defined) help text to the
+                                  requesting system, explaining how the
+                                  ConfMgr is to be used.
+
+         %LIST[,B]                Lists the conferences currently available
+                                  to the requesting system, on the basis
+                                  of a method internal to the conference
+                                  manager itself. This list would flag the
+                                  areas which are already linked. The 'B'
+                                  modifier would generate the list in
+                                  binary format (see section 8e).
+
+         %BLIST                   Equivalent to %LIST,B above.
+
+         %QUERY                   Lists the conferences currently linked to
+                                  the requesting system.
+
+         %UNLINKED                Lists the conferences which are available
+                                  to the requesting system, but not
+                                  currently linked. This is the logical
+                                  difference between a %LIST and a %QUERY.
+
+
+
+    7  Remote Maintenance
+
+       Besides these simple functions, it is becoming more and more
+       interesting to make handling of the conference mail flow even more
+       automatic. For this reason, for example, it might be useful to
+       allow another sysop control over your own system, adding and
+       removing conferences as need requires. Thus a hub or coordinator
+       could automatically have a new area added to their conference
+       lists, or discontinued ones removed.
+
+       Naturally, the ConfMgr must be able to distinguish which system has
+       the ability to make such changes, but that is beyond the scope of
+       this document.
+
+       It is proposed that a conference manager be able to automatically
+       add a new conference to the system's list if/when it is detected.
+       Thus no special commands would be required. The manager should be
+       able to determine a default list of down-links for the new area,
+       and also the "group" of systems which could then request it.
+
+       However, should it be desired to explicitly create a new conference
+       via remote, this could be done by including a line such as the
+       following in the message text:
+
+          &CONFNAME
+
+       In order to remote delete an area, the requesting sysop should
+       include a line like this in the body of the message text:
+
+          ~CONFNAME
+
+       Thus, if the system has remote privileges, the conference would be
+       deleted (and optionally, all systems linked to the conference could
+       be informed of this fact).
+
+       Similarly, it would also be possible to allow a system to change the
+       tag of a conference. This would be accomplished by a line such as:
+
+          # OLD_NAME  NEW_NAME
+
+       The ConfMgr should inform all downlinks of the change by sending a
+       net mail message.
+
+       It might also be desirable to allow a sysop to make changes on
+       behalf of another system. This could be done by inserting a special
+       command at the beginning of the request itself. For example:
+
+          From:     John Doe, on 2:123/1
+          To:       Program,  on 2:987/65
+          Subject:  password
+          Text:
+          %FROM: 2:234/56
+          +CONFNAME
+
+       The %FROM command would make the ConfMgr carry out the changes as if
+       the system 2:234/56 had requested them. The password should
+       nonetheless be the one assigned to 2:123/1.
+
+
+
+    8  Further Automation
+
+       In order to make the system more powerful, and to reduce the
+       necessity for human intervention, several extensions are feasible.
+
+       a) ARCmail Compression Method
+
+          One interesting application is the possibility of allowing a
+          remote system to change the compression program used to "pack"
+          mail bound for his system. This could be done with the following
+          command in the message to a ConfMgr:
+
+             %COMPRESS 
+
+          where  is one of the compression programs supported by
+          the system. Of course, the remote system should also be able to
+          determine which compression methods are available; this could be
+          done with
+
+             %COMPRESS ?
+
+          Requests for an unsupported compression method should also be
+          responded to with a list of those available.
+
+          From the practical point of view, only systems which pick up
+          their mail (as opposed to those to whom mail is sent) should be
+          allowed to change the compression method used. How this
+          distinction is achieved is beyond the scope of this document.
+
+       b) Passwords
+
+          A sysop should be able to change the password used to make
+          requests to a ConfMgr without requiring the intervention of the
+          other system's sysop. This could easily be done if the
+          conference manager implemented the following command:
+
+             %PWD 
+
+          The new password (case insensitive) would replace the current
+          one as of the next request.
+
+       c) Temporary Unlink
+
+          Should a system's sysop be absent for a prolonged period of time,
+          he might want to temporarily cut all conferences from his
+          uplink.  This could be accomplished with the
+
+             %PAUSE
+
+          command. This would tell the ConfMgr to temporarily stop sending
+          conferences to that system.  On his return, the sysop could
+          reactivate them all with the
+
+             %RESUME
+
+          command.
+
+       d) Forwarding Remote Requests
+
+          If a conference manager receives a remote request to delete an
+          area, it could very easily "forward" that request to all its
+          downlinks by producing a similar request.  In that way, a single
+          request originating from, for example, a Region Coordinator,
+          would result in the conference being deleted from all systems
+          "below" him.
+
+          Similarly, remote requests for conference name changes could
+          also be passed on to downlinks.
+
+       e) Automatic Requests for Conferences
+
+          A conference manager should also be able to automatically request
+          an area from an uplink. This would become necessary if, for
+          example, it processed a request for an area not currently
+          available on the system. In this case, it would scan a series of
+          conference lists for the requested area, and if found, would
+          send a request for that area.
+
+          In order to be able to do this, the ConfMgr would need to have
+          one or more lists of conferences from the uplinks. These lists
+          could be produced on request by the ConfMgr itself. In order to
+          simplify matters, a binary format is proposed. (Note that these
+          are C-style structures, with everything which that implies.)
+          This binary file is called a Binary Conference List (BCL).
+
+          The file starts with a header, containing some basic system
+          information:
+
+             struct bcl_header {
+               char    FingerPrint[4];     /* BCL */
+               char    ConfMgrName[31];    /* Name of "ConfMgr" */
+               char    Origin[51];         /* Originating network addr */
+               long    CreationTime;       /* UNIX-timestamp when created */
+               long    flags;              /* Options, see below */
+               char    Reserved[256];      /* Reserved data */
+             }
+
+          The currently defined flags for the header are:
+
+            BCLH_ISLIST     0x00000001L
+              File is complete list
+
+            BCLH_ISUPDATE   0x00000002L
+              File contains update/diff information
+
+          The BCL would then contain a series of entries having the
+          following format:
+
+             struct bcl {
+               int     EntryLength;      /* Length of entry data */
+               long    flags1, flags2;   /* Conference flags */
+               char    *AreaTag;         /* Area tag [51] */
+               char    *Description;     /* Description [51] */
+               char    *Administrator;   /* Administrator or contact [51] */
+             }
+
+          The flags currently defined are:
+
+             FLG1_READONLY   0x00000001L
+                Read only, software must not allow users to enter mail.
+
+             FLG1_PRIVATE    0x00000002L
+                Private attribute of messages is honored.
+
+             FLG1_FILECONF   0x00000004L
+                File conference.
+
+             FLG1_MAILCONF   0x00000008L
+                Mail conference.
+
+             FLG1_REMOVE     0x00000010L
+                Remove specified conference from list (otherwise add/upd).
+
+          Thus, instead of scanning an AREAS.BBS style list, the ConfMgr
+          would parse and use lists in the above format. Naturally, each
+          list would be in some way "attached" to a node number, and a
+          corresponding ConfMgr password.
+
+          Each system may only have one master file, called anything they
+          want. But when transmitted to other systems, this file must
+          always be named ????????.BCL.
+
+          The list would be generated in response to a
+
+            %LIST, B
+
+          command in the message text.
+
+       f) Receipts
+
+          It might be useful to have the ConfMgr generate a receipt to be
+          sent to another system, perhaps a co-sysop or a sysop point
+          node. This could be done with the command:
+
+            %RECEIPT ,
+ + embedded in the request message. For example: + + %RECEIPT JoHo,2:270/17 + + + + 9 Comments in the request + + It should be possible for a sysop to insert a comment in the request + made to a conference manager. These comments, naturally, would be + destined to the sysop of the system, and not to the conference + manager itself. Such comments should be placed at the end of the + message, following a %NOTE command. + + In all cases except the above, the request can be deleted by the + ConfMgr once processed, but messages containing comments should be + retained. + + Note: the current method used is to supply comments after a tear- + line. This practice is somewhat "messy", but it might be wise to + support it until such time as all conference managers have + implemented the %NOTE command. + + + + 10 Summary + + +CONFNAME[,R|S] Request to link to CONFNAME + -CONFNAME Request to unlink from CONFNAME + =CONFNAME,R|S Rescan or "sample" linked conference + &CONFNAME Request to create CONFNAME + ~CONFNAME Request to delete CONFNAME + #OLD NEW Name change request + + %LIST[,B] List available areas, flag linked + %QUERY Only list linked areas + %UNLINKED List available but unlinked areas + %HELP Send help text + %FROM Simulate request from another system + %RESCAN Rescan conferences linked in current request + %COMPRESS Change compression method + %PWD Change ConfMgr password + %PAUSE Suspend link + %RESUME Resume link + %RECEIPT , Send copy of receipt to another system + %NOTE Introduces comment to the sysop + + + + 11 Final Note + + This document is to be considered as a suggestion for software + developers to make their programs compatible with one another, so as + to make life easier for the average sysop when dealing with + conference managers. + + Feedback would be appreciated and can be sent to us at the addresses + specified on the title page. Please send feedback via netmail only. + +
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0059.html b/html/ftsc/fsc-0059.html new file mode 100755 index 00000000..1060f8e3 --- /dev/null +++ b/html/ftsc/fsc-0059.html @@ -0,0 +1,1622 @@ + + +Newsgroup Interchange within FidoNet. + + + + +
+Document: FSC-0059
+Version:  001
+Date:     08-Mar-1992
+
+
+
+
+                  Newsgroup Interchange within FidoNet
+                              Jack Decker
+                            1:154/8@fidonet
+
+  A proposed standard for the interchange of USENET News messages among
+                             FidoNet nodes.
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+
+Introduction:
+
+This document defines the standard format for the interchange of USENET
+news messages among FidoNet nodes.  It incorporates by reference the
+document RFC-1036, "Standard for Interchange of USENET Messages" by M.
+Horton of AT&T Bell Laboratories and R. Adams of the Center for Seismic
+Studies.  A copy of RFC-1036 should be included in the distribution
+archive of this standard.  However, RFC-1036 is NOT applicable in its
+entirety to FidoNet.  Therefore, unless specifically referenced
+elsewhere in this document, only section 2 of RFC-1036 should be
+considered part of this standard.  Section 3, which deals with "control
+messages", may be implemented in FidoNet on an optional basis, and if
+processing of control messages is included in a FidoNet implementation,
+it should be done in accordance with section 3 of RFC-1036 to the
+extent possible.  Section 4 of RFC-1036 is *NOT* applicable to FidoNet
+(except for section 4.3, which will be discussed later) and therefore
+is NOT included as part of this standard.  Section 5 of RFC-1036 is a
+treatise on the News Propagation Algorithm used within UseNet, and
+should be studied even though it is not directly applicable to FidoNet,
+in particular because it contains a discussion on the prevention of
+loops (what we in FidoNet commonly refer to as "dupe loops").
+
+Please note that FidoNet implementations do not recognize nor support
+what is referred to as the "old format" or the "A format" in section 2
+of RFC-1036.
+
+The goal of this document is to define a standard for the interchange
+of news messages between FidoNet nodes in a format that will also be
+acceptable to UseNet hosts.  In order to simplify the creation of
+software that conforms to this standard, we do not intend to support
+every news format that has ever existed in UseNet.  The standard
+described in RFC-1036 is used by the majority of UseNet hosts, and
+therefore it is the standard that will be adopted in this document.
+
+This standard will contain three sections:  General theory of newsgroup
+transmission, Format and protocols of batched newsgroups, and the
+translation of newsgroup messages to and from FidoNet message format.
+
+1. General theory of newsgroup transmission:
+
+Prior to the introduction of the DoveMail program, the usual method of
+gating a UseNet newsgroup into FidoNet was to convert it to FidoNet
+echomail, and then send it to "downstream" nodes in echomail format.
+This method is still used at the majority of gateway systems at this
+writing.  Unfortunately, no conversion process is perfect, and some
+useful control information is usually lost in the conversion.  In
+addition, most FidoNet echomail processors don't handle long messages
+(which are fairly common in newsgroups) well at all, and many gateway
+systems either try to split these messages into multiple parts (a
+somewhat awkward process) or discard them entirely.  Because the
+duplicate message detection algorithms used in many FidoNet echomail
+processors incorrectly identify some of the parts of a split message as
+duplicates, parts of long messages often get "lost" when transmitted as
+echomail.  Also, UseNet allows a message to be posted to multiple
+newsgroups, and when such messages are converted to echomail, it may be
+necessary to create multiple copies of the message (one for each
+echomail area that it would be placed in), thus increasing the
+transmission time for such messages.
+
+Even normal-length newsgroup messages may be falsely discarded as
+duplicates by some "downstream" echomail processors.  The reason this
+is a particular problem in newsgroups converted to echomail is because
+some echomail processors use a checksum of parts of FidoNet message
+headers to determine if messages are duplicates. Since all newsgroup
+messages are assumed to be addressed to "All", and since some gateway
+software uses the date and time that the message was converted to
+echomail rather than the original date and time from the message, it's
+quite possible that the remainder of the message header contains
+information that is similar enough to information in another message's
+header to cause it to be discarded as a duplicate message.  This
+happens far more frequently with converted newsgroup messages than with
+messages originally entered as echomail.
+
+Finally, when a BBS user enters a reply to a news message that has been
+converted to echomail, in many cases the information is simply not
+available in the original message to generate a proper "References:"
+line in the reply, as required by RFC-1036.  If the original message
+contained a "Followup-To:" line, which requires that replies be posted
+to a different newsgroup than the one in which the original message was
+entered, this line may not transmitted in the message as converted to
+echomail.  And even if this information is available, no echomail
+processor currently available will modify the reply message as required
+(to add the "References:" line where necessary, or to move the message
+to a different area if it is a reply to a message that contained a
+"Followup-To:" line).
+
+Under this proposed standard, none of the UseNet message header
+information is lost in transmission between nodes, and reply messages
+can be generated that conform to UseNet specifications.  If a message
+is posted to multiple newsgroups, it is only transmitted once (instead
+of multiple times as it might be if converted to echomail).  Also, long
+messages are not truncated or changed in transmission between nodes,
+and finally, there is no chance that a message will be improperly
+discarded as a duplicate.
+
+The main thing to remember is that under this standard, news messages
+are never converted to echomail.  Echomail is an irrelevant concept in
+this context, since we are not passing echomail between nodes.
+Instead, newsgroups are transmitted in the native format specified by
+RFC-1036, and tossed directly from batched newsgroup packets to the
+FidoNet message format (e.g. the *.msg format) if necessary.  Keep in
+mind that most FidoNet BBS software uses the same general format not
+only for echomail messages, but also for netmail and local message
+areas, so it is not necessary to transmit messages between nodes in
+echomail format if another format is more suitable for the type of
+message being transmitted.
+
+2. Format and protocols of batched newsgroups:
+
+When newsgroup messages are transmitted between systems, the individual
+messages must conform to the specifications of section 2 of RFC-1036,
+and section 3 of this document.  Where section 3 of this document
+defines a more restrictive standard than RFC-1036, this document shall
+take precedence.
+
+When transmitting news messages between FidoNet nodes, they must be
+sent in a batched newsgroup file (as described in section 4.3 of
+RFC-1036) unless some other format is agreed upon in advance.  The
+transmission of unbatched news messages, or the use of any batching
+method other than that described in section 4.3 of RFC-1036 shall be
+considered non-standard.  Please note that RFC-1036 section 4.3 refers
+to this batching process as combining several messages into "one large
+message", but we will refer to this "one large message" as a "batched
+newsgroup file", or a "UseNet format mail packet" rather than as a
+"large message", since FidoNet systems do not normally handle large
+"messages".
+
+When messages pass through a FidoNet system on their way to other
+nodes, the header lines in the message may be modified to conform with
+the standards given here.  However, the text (body) of a message should
+NEVER be altered (one exception: Carriage Returns MAY be converted to
+Line Feeds in order to conform to this standard, but this is neither
+required nor expected of software).
+
+The standard format for sending a batched newsgroup file to other
+FidoNet nodes is as follows:
+
+First, as will be noted in section 3 of this document, individual lines
+of the batched newsgroup file must be terminated with Line Feeds only,
+and the file must NOT contain Carriage Return characters (ASCII 13).
+
+Batched newsgroup files shall be transmitted between FidoNet nodes as
+files named using the filename ????????.PKU, where the eight character
+root name can be any of the hexadecimal digits 0 - 9 or A - F.  The
+.PKU extension (which stands for "PacKet - Usenet format") is the news
+equivalent of the .PKT file used to transmit FidoNet format netmail and
+echomail between nodes.
+
+Batched newsgroup files with the filespec ????????.PKU may be archived
+into a standard mail archive file (bearing the extension *.MO?, *.TU?,
+*.WE? ... *.SU?).  It is assumed that the receiver of batched newsgroup
+files will take any necessary steps to make sure that both *.PKU and
+*.PKT files are extracted from incoming mail archive files before the
+mail archive files are deleted.  In certain cases, this may mean that
+an external unarchive shell may have to be used, instead of allowing
+the echomail processor to call the unarchiver (typical external
+unarchive shell programs at this writing are GUS, POLYXARC, and SPAZ).
+
+A batched newsgroup file awaiting transmission may be stored in a
+FidoNet system's "outbound" area in uncompressed form, prior to being
+archived for transmission or sent in uncompressed form.  It is
+suggested that when a system uses the .OUT extension to indicate an
+uncompressed netmail or echomail packet, the .UUT extension be used to
+indicate an uncompressed batched newsgroup packet.  It is expected that
+a .UUT file in a system's "outbound" area will be treated in much the
+same way as an .OUT file, except it will be renamed to a file with an
+extension of .PKU (rather than .PKT) before being archived into the
+mail archive.  This implies that the root name of the .UUT file will
+contain the net number and node number of the destination system,
+expressed as four hexadecimal digits each for net and node numbers, in
+the same manner as the root name for a FidoNet .OUT file is
+constructed.
+
+The root filename of the *.PKU file should be an eight digit
+hexadecimal number, with leading zeroes used if necessary, in order to
+make an eight character root filename.  It is suggested that this
+hexadecimal number be based on time of year, with 00000000.PKU
+generated at exactly midnight on January 1 and FFFFFFFF.PKU generated
+at just a moment before midnight on December 31.  However, it is
+permissible to use the same algorithm that is used to generate the root
+filename for *.PKT files.
+
+The normal sequence for transmission of messages between FidoNet nodes
+might then be described as follows:
+
+a. Messages created on the originating system are placed into a batched
+newsgroup file conforming to the specifications of RFC-1036 section
+4.3.  When this batched newsgroup file is destined for another FidoNet
+node, it will have a filename of the format:
+
+     [4 hex digit net number][4 hex digit node number].UUT
+
+This file will then be placed in the outbound mail area for packing.
+
+b. A mail packing program will examine the outbound mail area and, upon
+finding the .UUT file, will rename it to a file with an extension of
+.PKU, and then shell to a compression program in order to place the
+*.PKU file into a new or existing mail archive file for the destination
+node.  Mail archive files bear extension names consisting of the first
+two letters of a day of the week (in the English language) plus a
+numeric character in the range 0 - 9 (for example, .MO5 or .TH7).  The
+method of compression for the mail archive is as agreed upon between
+the originating and destination nodes.  No "standard" method of
+compression for the mail archive is specified in this document.  NOTE:
+If the compression program fails for any reason (such as running out of
+disk space), the mail packing program MUST rename the .PKU file back to
+the original *.UUT filename before exiting.  Since batched newsgroup
+files do not contain a header that indicates the destination node,
+there would be no way to determine the proper destination node if the
+file were not renamed back to the original filename.
+
+c. The mail archive is transmitted in the usual manner by a FidoNet
+compatible mailer, or such other means as may be agreed upon in advance
+by the sysops of the originating and destination nodes.
+
+d. At the destination system, the individual files are extracted from
+the mail archive.  *.PKT files are processed in the usual manner to
+extract any netmail or echomail messages, while *.PKU files are
+processed by software designed to handle batched newsgroup files.  In
+this context, such files could be "handled" by re-processing the
+messages and batching them to be sent on to one or more additional
+node(s), or by tossing the messages to the local message base, or both.
+
+Please note that this standard does not anticipate that batched
+newsgroup files will be converted to FidoNet echomail at any point
+along the way.  It is realized that this may indeed happen, but such
+conversions should be considered as something to be avoided if at all
+possible due to the problems discussed in section 1 of this document.
+
+3. Translation of newsgroup messages to and from FidoNet message
+format:
+
+NOTE: Where applicable, the standards defined in this section for
+messages shall apply not only to locally created messages, but also to
+all messages sent to "downstream" FidoNet nodes.
+
+In this context, "FidoNet message format" means that format in which
+messages commonly reside on a FidoNet BBS.  At this writing, there are
+three formats commonly used for message storage on FidoNet systems, but
+other formats may be in use as well.  The three most common formats are
+the "*.msg" format as used by the original Fido program (and a host of
+programs since), also commonly referred to as the "single message per
+file format"; the "Hudson" format, used by QuickBBS, Remote Access, and
+some other products; and the "Squish" format used by the Maximus BBS
+and the "Squish" echomail processor.
+
+Because there are so many message formats, some other programs have
+taken the approach of trying to convert UseNet news into echomail,
+creating *.PKT files which can theoretically be processed by any
+FidoNet system.  However, since the *.PKT files are processed by the
+echomail processor, all the limitations and pitfalls associated with
+converting newsgroup messages to echomail come into play.
+
+The preferred way of handling incoming messages would be to have the
+BBS (or message reader/editor) software directly read batched newsgroup
+files.  In this way, the files would not have to be "processed" per se.
+As new batched newsgroup files arrived on a system, they could simply
+be concatenated to the existing message base, and then a utility could
+be run that would build an index to the message base, in a manner
+somewhat similar to the way "flat file" message bases are currently
+implemented on some BBS's.  Of course, you'd need to occasionally run a
+utility to delete old messages in order to keep the message base from
+growing too large, and new messages entered on the system would have to
+be exported from the system in a separate batched newsgroup file.
+However, at this writing no FidoNet-compatible BBS or message editor is
+capable of directly reading a batched newsgroup file.
+
+The second most preferable method is to convert news messages directly
+to the message format used by that system.  At this writing the
+DoveMail software includes utilities (NewsToss and NewsScan) that can
+convert batched newsgroup files to and from messages in the *.msg
+(single message per file) format.  It should be possible to convert
+batched newsgroup files to and from other FidoNet message formats as
+well.
+
+The method in which messages are stored on a BBS, and the method in
+which it is determined which new (locally-entered) messages need to be
+exported from the system will necessarily be implementation-specific.
+One method that can be used with *.msg type message bases is to
+maintain a "high water mark" in 1.msg, similar to the "high water mark"
+used for echomail messages, and additionally to mark messages received
+from other nodes as "sent" when they arrive, and locally-entered
+messages as "sent" when they have been exported, and to never re-send a
+message marked as "sent".
+
+When tossing incoming messages, duplicate messages can be detected by
+comparing the contents of the "Message-ID:" line with those of
+previously received messages.  This may be slow processing
+considerably, however, and would require storage of a history file of
+"previously seen" messages.  Another method is to look in the "Path"
+line and see if we are already listed in the path; if so, the message
+is a duplicate and should be deleted.  This method is faster and does
+not require maintenance of a history file, but will not guard against
+duplicate messages arriving from one's feed that have not passed
+through the system twice (for example, a message that arrived from two
+different paths).  Fortunately, UseNet folks seem to understand the
+need for proper topology, so those types of dupes are relatively rare.
+FidoNet sysops taking UseNet feeds must understand that it is
+IMPERATIVE that a feed of any one newsgroup be obtained from only ONE
+source, especially if they are then passing that newsgroup to any
+"downstream" nodes.  This absolutely does NOT imply that geographic
+restrictions on newsgroup distribution are necessary or desirable!
+
+Additional comments on preventing "loops" can be found in section 5 of
+RFC-1036, in the discussion of the News Propagation Algorithm.  Please
+note that only two methods of loop prevention are included in this
+standard:
+
+1) The history mechanism.  Each host keeps track of all messages it has
+seen (by their Message-ID) and whenever a message comes in that it has
+already seen, the incoming message is discarded immediately.
+
+2) Not sending a message to a system listed in the "Path" line of the
+header, or to the system that originated the message (which, in
+practice, should be listed in the Path line).
+
+No other methods of dupe loop prevention are acceptable.  In
+particular, checksums of portions of the message header or message
+itself are NOT permitted to be used for loop prevention, except perhaps
+as a method to quickly identify POTENTIAL duplicate messages before
+doing a full string comparison with the Message-ID data in the history
+file.  In no case should a checksum be used as the SOLE method of
+determining whether a message is a duplicate.
+
+When newsgroup messages are created for transmission to other systems,
+or when received messages are transmitted other systems, the individual
+messages must conform to the specifications of section 2 of RFC-1036.
+However, in order to simply programming of software designed to handle
+such messages, the following modifications to the standard are proposed
+for use within FidoNet.  Please note that these are slightly more
+restrictive than the standard permitted by RFC-1036:
+
+a. The "old format" or "A format" described in section 2 of RFC-1036 is
+NOT supported in FidoNet.  Only the format detailed in RFC-1036
+(sometimes referred to as the "B" News format) is supported.  The vast
+majority of UseNet sites currently use the "B" News format.
+
+b. The UseNet standard permits the use of "white space" to separate
+certain items in the message header, with "white space" defined as
+blanks or tabs.  It also states that "the Internet convention of
+continuation header lines (beginning with a blank or tab) is allowed."
+However, it should NOT be ASSUMED that "continuation header lines" will
+be used in any message.  It is suggested that when creating newsgroup
+messages for transmission to other systems, the use of tab characters
+be avoided in header lines, and that "continuation header lines" NOT be
+used, even if this means that a header line will be considerably longer
+than the length of a screen line.  Software that creates FidoNet-format
+messages (for display to BBS callers) from batched newsgroup files
+(that is, newsgroup message tossers) should break up such extra-long
+header lines, using a single space character ONLY (NOT a tab!) at the
+start of "continuation header lines."  Since batched newsgroup files
+received from a UseNet site may contain "continuation header lines"
+and/or tabs as "white space" in header lines, it is necessary to be
+able to decode such header lines properly, but it is strongly suggested
+that FidoNet software not CREATE messages with tabs or "continuation
+header lines" for transmission through the network.
+
+c. All lines in news messages, including header lines, shall be
+terminated with a LINE FEED (ASCII 10 decimal) ONLY.  Under NO
+circumstances shall a CARRIAGE RETURN (ASCII 13 decimal) appear in news
+messages transmitted through FidoNet (if a Carriage Return is found in
+an in-transit message it MAY be changed to a Line Feed, this being the
+sole exception to the rule about not changing the body of a message,
+but the expectation is that no Carriage Returns will appear in a news
+message).  Also, spaces appearing at the end of lines (just prior to
+the Line Feed character) are strongly discouraged since they convey no
+useful information.  Finally, there should be only a single line feed
+at the end of each message (blank lines following the last line of a
+message are not allowed, again because they convey no useful
+information).  Please note that the use of the Line Feed as a line
+terminator is fairly standard throughout UseNet, and when a news
+message is converted to a FidoNet format message it is a simple matter
+to replace Line Feeds with Carriage Returns so that the message will
+display properly.
+
+d. When constructing or adding to "Path" lines, RFC-1036 (section
+2.1.6) states that "The names may be separated by any punctuation
+character or characters (except '.' which is considered part of the
+hostname)."  However, in actual practice, only the "!" (exclamation
+point or "bang" character) is commonly used to separate names.
+Therefore, the "!" character will be considered the "standard"
+separator for system names in Path lines in messages generated in
+FidoNet.  Also, RFC-1036 states that "Normally, the rightmost name will
+be the name of the originating system.  However, it is also permissible
+to include an extra entry on the right, which is the name of the
+sender.  This is for upward compatibility with older systems." In
+actual practice, it appears that most Path lines originating in UseNet
+have a user name as the rightmost entry.  Therefore, when a Path line
+is created for a message originating in FidoNet, it is suggested that
+the following format be used (assuming a message entered by user John
+Smith at node 1:123/456):
+
+     Path: f456.n123.z1.fidonet.org!john.smith
+
+When a user name is placed in the path, all spaces in the user name
+must be replaced with periods, and all uppercase characters in the name
+should be converted to lowercase.  It is permissible to use an alias in
+place of a user's real name if the originating system runs software
+that will recognize that alias in incoming netmail messages, and remap
+such messages to the proper user if necessary.  Also, note the
+restrictions on prohibited characters in the user name as specified in
+RFC-1036 section 2.1.1.  Although section 2.1.1. deals with the "From"
+line, common sense would indicate that these same restrictions on
+prohibited characters should apply if the user name is placed in the
+Path line (with the obvious exception of the use of the period to
+replace spaces in the user name, which is required).
+
+e. Header lines defined as "optional" may be more or less optional
+depending on the keyword.  For example, the "Reply-To" and
+"Followup-To" lines should be automatically honored, if at all
+possible, when reply messages are created, and the "References" line,
+even though listed as an "optional" line, is "required for all
+follow-up messages" (replies).  On the other hand, lines such as
+"Control" and "Distribution" may have little meaning to FidoNet nodes
+(in particular, "Distribution" is meant to control distribution of a
+message along hierarchial lines, but since FidoNet topology has little
+relation to UseNet hierarchies, it is probably best to just ignore
+"Distribution" lines on in-transit messages).
+
+Additional specifications for messages, including required and optional
+header lines, are detailed in section 2 of RFC-1036.
+
+When a newsgroup is moderated, it is the responsibility of the sysop of
+each participating BBS to prevent users from entering messages in that
+area (unless the message exporting software is capable of sending any
+locally-entered messages to the conference moderator via MAIL).
+However, if a software newsgroup processor is written that both imports
+(tosses) messages to a FidoNet-format message base, and exports locally
+entered messages, and if the software does not have a way to send
+replies to the moderator via mail, then some mechanism must be provided
+to prevent the export of messages from a moderated area, so that in the
+unlikely event that there is no easy way to prevent users from posting
+messages in the moderated area, such messages will still not be sent
+out.  Since this standard does not deal with the transport of UseNet
+MAIL within FidoNet, the method for transmission of replies in
+moderated newsgroups is undefined by this document.  However, software
+authors are encouraged to provide some mechanism for private mail
+replies to newsgroup messages, in both moderated and unmoderated areas.
+
+Note that if a moderated newsgroup is carried on a system, it is the
+responsibility of the sysop to provide mail access to users so that
+replies can be (manually) sent to the conference moderator, especially
+if replies in the newsgroup area cannot be automatically routed to the
+conference moderator.
+
+One point that needs to be emphasized is there is NO message length
+limit on UseNet messages.  If a FidoNet node passes newsgroup messages
+to, or on behalf of other FidoNet nodes, it is NOT permissible to
+discard or truncate messages that exceed a preset length limit.  Note
+that in a batched newsgroup file, each message is preceded by a header
+of the form "#! rnews ".  Since the message text
+length is never changed in processing, it is possible to determine the
+length of a message after processing by reading in all the header
+lines, calculating the combined length of the header lines prior to
+making changes in the header (e.g. the Path line), then calculating the
+combined length of the header lines after making changes.  The
+difference between the original and the new length of the header lines
+can then be applied to the value given in the "#! rnews" line to
+determine the new message length, when is then used in the "#! rnews"
+header of the modified message.  Also, the number of bytes given in the
+"#! rnews" line, MINUS the length of the message header lines, is the
+length of the body of the message.  Once this length is known, the body
+of the message can be copied from the input file to the output file(s)
+in "chunks" small enough to fit in memory, until the end of the message
+is reached.
+
+The following comments are implementation suggestions applicable to
+current FidoNet-compatible BBS systems, though not necessarily to
+software that may be written in the future:
+
+It should be noted that when a BBS user enters a reply message, most
+FidoNet BBS software will "link" the reply message to the original by
+placing the message number of the original message in the message
+header (this is almost always the case if messages are stored in the
+"*.msg" format, in which case the number of the message being replied
+to is found at bytes 185-186 in the message header).  If the
+appropriate header lines have been stored in the text of the original
+message, it is possible to construct a reply message that meets all
+RFC-1036 specifications.  For example, a "References" line can be
+constructed from the "Message-ID" line (and the "References" line, if
+any) of the original message.  Similarly, if the original message
+contains a "Followup-To:" line, the reply can be posted to the
+newsgroup(s) specified in that line.  This may not work as expected if
+a message renumbering program or similar program messes with the
+message base before reply message is exported, so it is highly
+recommended that locally-entered newsgroup messages be exported as soon
+as practicable after they are entered.
+
+Since the user of a BBS may reply to a message entered by another user
+of the same BBS, it is recommended that when a message is exported, any
+UseNet format header lines created for the exported message also be
+written back to the original message if possible.  This will permit
+reply linking to remain intact even if two or more users of the same
+BBS participate in the same message thread.
+
+If a message is received that specifies more than one newsgroup in the
+"Newsgroups" header line, and corresponding message areas are available
+on the local system, one copy of the message should be placed in each
+such area.  For example, if the message is posted to four different
+newsgroups, and two of those groups are carried on the local BBS, then
+a copy of the message should be placed in the message base for each of
+those groups.  If users of a BBS are allowed to post a message to
+multiple newsgroups, then any message thus posted should be copied to
+the message bases of any of the other areas that are also carried on
+that system (and that the message was posted to) at the time the
+message is exported.
+
+Corrections and Additions to this document:
+
+Proposed corrections and additions to this document should be submitted
+to Jack Decker at 1:154/8, or jack.decker@f8.n154.z1.fidonet.org
+
+ +
+ +
+Network Working Group                                          M. Horton
+Request for Comments:  1036                       AT&T Bell Laboratories
+Obsoletes: RFC-850                                              R. Adams
+                                              Center for Seismic Studies
+                                                           December 1987
+
+
+              Standard for Interchange of USENET Messages
+
+
+
+STATUS OF THIS MEMO
+
+    This document defines the standard format for the interchange of
+    network News messages among USENET hosts.  It updates and replaces
+    RFC-850, reflecting version B2.11 of the News program.  This memo is
+    disributed as an RFC to make this information easily accessible to
+    the Internet community.  It does not specify an Internet standard.
+    Distribution of this memo is unlimited.
+
+1.  Introduction
+
+    This document defines the standard format for the interchange of
+    network News messages among USENET hosts.  It describes the format
+    for messages themselves and gives partial standards for transmission
+    of news.  The news transmission is not entirely in order to give a
+    good deal of flexibility to the hosts to choose transmission
+    hardware and software, to batch news, and so on.
+
+    There are five sections to this document.  Section two defines the
+    format.  Section three defines the valid control messages.  Section
+    four specifies some valid transmission methods.  Section five
+    describes the overall news propagation algorithm.
+
+2.  Message Format
+
+    The primary consideration in choosing a message format is that it
+    fit in with existing tools as well as possible.  Existing tools
+    include implementations of both mail and news.  (The notesfiles
+    system from the University of Illinois is considered a news
+    implementation.)  A standard format for mail messages has existed
+    for many years on the Internet, and this format meets most of the
+    needs of USENET.  Since the Internet format is extensible,
+    extensions to meet the additional needs of USENET are easily made
+    within the Internet standard.  Therefore, the rule is adopted that
+    all USENET news messages must be formatted as valid Internet mail
+    messages, according to the Internet standard RFC-822.  The USENET
+    News standard is more restrictive than the Internet standard,
+
+
+
+Horton & Adams                                                  [Page 1]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    placing additional requirements on each message and forbidding use
+    of certain Internet features.  However, it should always be possible
+    to use a tool expecting an Internet message to process a news
+    message.  In any situation where this standard conflicts with the
+    Internet standard, RFC-822 should be considered correct and this
+    standard in error.
+
+    Here is an example USENET message to illustrate the fields.
+
+              From: jerry@eagle.ATT.COM (Jerry Schwarz)
+              Path: cbosgd!mhuxj!mhuxt!eagle!jerry
+              Newsgroups: news.announce
+              Subject: Usenet Etiquette -- Please Read
+              Message-ID: <642@eagle.ATT.COM>
+              Date: Fri, 19 Nov 82 16:14:55 GMT
+              Followup-To: news.misc
+              Expires: Sat, 1 Jan 83 00:00:00 -0500
+              Organization: AT&T Bell Laboratories, Murray Hill
+
+              The body of the message comes here, after a blank line.
+
+      Here is an example of a message in the old format (before the
+      existence of this standard). It is recommended that
+      implementations also accept messages in this format to ease upward
+      conversion.
+
+               From: cbosgd!mhuxj!mhuxt!eagle!jerry (Jerry Schwarz)
+               Newsgroups: news.misc
+               Title: Usenet Etiquette -- Please Read
+               Article-I.D.: eagle.642
+               Posted: Fri Nov 19 16:14:55 1982
+               Received: Fri Nov 19 16:59:30 1982
+               Expires: Mon Jan 1 00:00:00 1990
+
+               The body of the message comes here, after a blank line.
+
+      Some news systems transmit news in the A format, which looks like
+      this:
+
+                Aeagle.642
+                news.misc
+                cbosgd!mhuxj!mhuxt!eagle!jerry
+                Fri Nov 19 16:14:55 1982
+                Usenet Etiquette - Please Read
+                The body of the message comes here, with no blank line.
+
+    A standard USENET message consists of several header lines, followed
+    by a blank line, followed by the body of the message.  Each header
+
+
+
+Horton & Adams                                                  [Page 2]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    line consist of a keyword, a colon, a blank, and some additional
+    information.  This is a subset of the Internet standard, simplified
+    to allow simpler software to handle it.  The "From" line may
+    optionally include a full name, in the format above, or use the
+    Internet angle bracket syntax.  To keep the implementations simple,
+    other formats (for example, with part of the machine address after
+    the close parenthesis) are not allowed.  The Internet convention of
+    continuation header lines (beginning with a blank or tab) is
+    allowed.
+
+    Certain headers are required, and certain other headers are
+    optional.  Any unrecognized headers are allowed, and will be passed
+    through unchanged.  The required header lines are "From", "Date",
+    "Newsgroups", "Subject", "Message-ID", and "Path".  The optional
+    header lines are "Followup-To", "Expires", "Reply-To", "Sender",
+    "References", "Control", "Distribution", "Keywords", "Summary",
+    "Approved", "Lines", "Xref", and "Organization".  Each of these
+    header lines will be described below.
+
+2.1.  Required Header lines
+
+2.1.1.  From
+
+    The "From" line contains the electronic mailing address of the
+    person who sent the message, in the Internet syntax.  It may
+    optionally also contain the full name of the person, in parentheses,
+    after the electronic address.  The electronic address is the same as
+    the entity responsible for originating the message, unless the
+    "Sender" header is present, in which case the "From" header might
+    not be verified.  Note that in all host and domain names, upper and
+    lower case are considered the same, thus "mark@cbosgd.ATT.COM",
+    "mark@cbosgd.att.com", and "mark@CBosgD.ATt.COm" are all equivalent.
+    User names may or may not be case sensitive, for example,
+    "Billy@cbosgd.ATT.COM" might be different from
+    "BillY@cbosgd.ATT.COM".  Programs should avoid changing the case of
+    electronic addresses when forwarding news or mail.
+
+    RFC-822 specifies that all text in parentheses is to be interpreted
+    as a comment.  It is common in Internet mail to place the full name
+    of the user in a comment at the end of the "From" line.  This
+    standard specifies a more rigid syntax.  The full name is not
+    considered a comment, but an optional part of the header line.
+    Either the full name is omitted, or it appears in parentheses after
+    the electronic address of the person posting the message, or it
+    appears before an electronic address which is enclosed in angle
+    brackets.  Thus, the three permissible forms are:
+
+
+
+
+
+Horton & Adams                                                  [Page 3]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+              From: mark@cbosgd.ATT.COM
+              From: mark@cbosgd.ATT.COM (Mark Horton)
+              From: Mark Horton 
+
+    Full names may contain any printing ASCII characters from space
+    through tilde, except that they may not contain "(" (left
+    parenthesis), ")" (right parenthesis), "<" (left angle bracket), or
+    ">" (right angle bracket).  Additional restrictions may be placed on
+    full names by the mail standard, in particular, the characters ","
+    (comma), ":" (colon), "@" (at), "!" (bang), "/" (slash), "="
+    (equal), and ";" (semicolon) are inadvisable in full names.
+
+2.1.2.  Date
+
+    The "Date" line (formerly "Posted") is the date that the message was
+    originally posted to the network.  Its format must be acceptable
+    both in RFC-822 and to the getdate(3) routine that is provided with
+    the Usenet software.  This date remains unchanged as the message is
+    propagated throughout the network.  One format that is acceptable to
+    both is:
+
+                      Wdy, DD Mon YY HH:MM:SS TIMEZONE
+
+    Several examples of valid dates appear in the sample message above.
+    Note in particular that ctime(3) format:
+
+                          Wdy Mon DD HH:MM:SS YYYY
+
+    is not acceptable because it is not a valid RFC-822 date.  However,
+    since older software still generates this format, news
+    implementations are encouraged to accept this format and translate
+    it into an acceptable format.
+
+    There is no hope of having a complete list of timezones.  Universal
+    Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
+    CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be
+    supported.  It is recommended that times in message headers be
+    transmitted in GMT and displayed in the local time zone.
+
+2.1.3.  Newsgroups
+
+    The "Newsgroups" line specifies the newsgroup or newsgroups in which
+    the message belongs.  Multiple newsgroups may be specified,
+    separated by a comma.  Newsgroups specified must all be the names of
+    existing newsgroups, as no new newsgroups will be created by simply
+    posting to them.
+
+
+
+
+
+Horton & Adams                                                  [Page 4]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    Wildcards (e.g., the word "all") are never allowed in a "News-
+    groups" line.  For example, a newsgroup comp.all is illegal,
+    although a newsgroup rec.sport.football is permitted.
+
+    If a message is received with a "Newsgroups" line listing some valid
+    newsgroups and some invalid newsgroups, a host should not remove
+    invalid newsgroups from the list.  Instead, the invalid newsgroups
+    should be ignored.  For example, suppose host A subscribes to the
+    classes btl.all and comp.all, and exchanges news messages with host
+    B, which subscribes to comp.all but not btl.all.  Suppose A receives
+    a message with Newsgroups: comp.unix,btl.general.
+
+    This message is passed on to B because B receives comp.unix, but B
+    does not receive btl.general.  A must leave the "Newsgroups" line
+    unchanged.  If it were to remove btl.general, the edited header
+    could eventually re-enter the btl.all class, resulting in a message
+    that is not shown to users subscribing to btl.general.  Also,
+    follow-ups from outside btl.all would not be shown to such users.
+
+2.1.4.  Subject
+
+    The "Subject" line (formerly "Title") tells what the message is
+    about.  It should be suggestive enough of the contents of the
+    message to enable a reader to make a decision whether to read the
+    message based on the subject alone.  If the message is submitted in
+    response to another message (e.g., is a follow-up) the default
+    subject should begin with the four characters "Re:", and the
+    "References" line is required.  For follow-ups, the use of the
+    "Summary" line is encouraged.
+
+2.1.5.  Message-ID
+
+    The "Message-ID" line gives the message a unique identifier.  The
+    Message-ID may not be reused during the lifetime of any previous
+    message with the same Message-ID.  (It is recommended that no
+    Message-ID be reused for at least two years.)  Message-ID's have the
+    syntax:
+
+                     ">
+
+    In order to conform to RFC-822, the Message-ID must have the format:
+
+                          
+
+    where full_domain_name is the full name of the host at which the
+    message entered the network, including a domain that host is in, and
+    unique is any string of printing ASCII characters, not including "<"
+    (left angle bracket), ">" (right angle bracket), or "@" (at sign).
+
+
+
+Horton & Adams                                                  [Page 5]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    For example, the unique part could be an integer representing a
+    sequence number for messages submitted to the network, or a short
+    string derived from the date and time the message was created.  For
+    example, a valid Message-ID for a message submitted from host ucbvax
+    in domain "Berkeley.EDU" would be "<4123@ucbvax.Berkeley.EDU>".
+    Programmers are urged not to make assumptions about the content of
+    Message-ID fields from other hosts, but to treat them as unknown
+    character strings.  It is not safe, for example, to assume that a
+    Message-ID will be under 14 characters, that it is unique in the
+    first 14 characters, nor that is does not contain a "/".
+
+    The angle brackets are considered part of the Message-ID.  Thus, in
+    references to the Message-ID, such as the ihave/sendme and cancel
+    control messages, the angle brackets are included.  White space
+    characters (e.g., blank and tab) are not allowed in a Message-ID.
+    Slashes ("/") are strongly discouraged.  All characters between the
+    angle brackets must be printing ASCII characters.
+
+2.1.6.  Path
+
+    This line shows the path the message took to reach the current
+    system.  When a system forwards the message, it should add its own
+    name to the list of systems in the "Path" line.  The names may be
+    separated by any punctuation character or characters (except "."
+    which is considered part of the hostname).  Thus, the following are
+    valid entries:
+
+                   cbosgd!mhuxj!mhuxt
+                   cbosgd, mhuxj, mhuxt
+                   @cbosgd.ATT.COM,@mhuxj.ATT.COM,@mhuxt.ATT.COM
+                   teklabs, zehntel, sri-unix@cca!decvax
+
+    (The latter path indicates a message that passed through decvax,
+    cca, sri-unix, zehntel, and teklabs, in that order.) Additional
+    names should be added from the left.  For example, the most recently
+    added name in the fourth example was teklabs.  Letters, digits,
+    periods and hyphens are considered part of host names; other
+    punctuation, including blanks, are considered separators.
+
+    Normally, the rightmost name will be the name of the originating
+    system.  However, it is also permissible to include an extra entry
+    on the right, which is the name of the sender.  This is for upward
+    compatibility with older systems.
+
+    The "Path" line is not used for replies, and should not be taken as
+    a mailing address.  It is intended to show the route the message
+    traveled to reach the local host.  There are several uses for this
+    information.  One is to monitor USENET routing for performance
+
+
+
+Horton & Adams                                                  [Page 6]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    reasons.  Another is to establish a path to reach new hosts.
+    Perhaps the most important use is to cut down on redundant USENET
+    traffic by failing to forward a message to a host that is known to
+    have already received it.  In particular, when host A sends a
+    message to host B, the "Path" line includes A, so that host B will
+    not immediately send the message back to host A.  The name each host
+    uses to identify itself should be the same as the name by which its
+    neighbors know it, in order to make this optimization possible.
+
+    A host adds its own name to the front of a path when it receives a
+    message from another host.  Thus, if a message with path "A!X!Y!Z"
+    is passed from host A to host B, B will add its own name to the path
+    when it receives the message from A, e.g., "B!A!X!Y!Z".  If B then
+    passes the message on to C, the message sent to C will contain the
+    path "B!A!X!Y!Z", and when C receives it, C will change it to
+    "C!B!A!X!Y!Z".
+
+    Special upward compatibility note:  Since the "From", "Sender", and
+    "Reply-To" lines are in Internet format, and since many USENET hosts
+    do not yet have mailers capable of understanding Internet format, it
+    would break the reply capability to completely sever the connection
+    between the "Path" header and the reply function.  It is recognized
+    that the path is not always a valid reply string in older
+    implementations, and no requirement to fix this problem is placed on
+    implementations.  However, the existing convention of placing the
+    host name and an "!"  at the front of the path, and of starting the
+    path with the host name, an "!", and the user name, should be
+    maintained when possible.
+
+2.2.  Optional Headers
+
+2.2.1.  Reply-To
+
+    This line has the same format as "From".  If present, mailed replies
+    to the author should be sent to the name given here.  Otherwise,
+    replies are mailed to the name on the "From" line. (This does not
+    prevent additional copies from being sent to recipients named by the
+    replier, or on "To" or "Cc" lines.)  The full name may be optionally
+    given, in parentheses, as in the "From" line.
+
+2.2.2.  Sender
+
+    This field is present only if the submitter manually enters a "From"
+    line.  It is intended to record the entity responsible for
+    submitting the message to the network.  It should be verified by the
+    software at the submitting host.
+
+
+
+
+
+Horton & Adams                                                  [Page 7]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    For example, if John Smith is visiting CCA and wishes to post a
+    message to the network, using friend Sarah Jones' account, the
+    message might read:
+
+              From: smith@ucbvax.Berkeley.EDU (John Smith)
+              Sender: jones@cca.COM (Sarah Jones)
+
+    If a gateway program enters a mail message into the network at host
+    unix.SRI.COM, the lines might read:
+
+              From: John.Doe@A.CS.CMU.EDU
+              Sender: network@unix.SRI.COM
+
+    The primary purpose of this field is to be able to track down
+    messages to determine how they were entered into the network.  The
+    full name may be optionally given, in parentheses, as in the "From"
+    line.
+
+2.2.3.  Followup-To
+
+    This line has the same format as "Newsgroups".  If present, follow-
+    up messages are to be posted to the newsgroup or newsgroups listed
+    here.  If this line is not present, follow-ups are posted to the
+    newsgroup or newsgroups listed in the "Newsgroups" line.
+
+    If the keyword poster is present, follow-up messages are not
+    permitted.  The message should be mailed to the submitter of the
+    message via mail.
+
+2.2.4.  Expires
+
+    This line, if present, is in a legal USENET date format.  It
+    specifies a suggested expiration date for the message.  If not
+    present, the local default expiration date is used.  This field is
+    intended to be used to clean up messages with a limited usefulness,
+    or to keep important messages around for longer than usual.  For
+    example, a message announcing an upcoming seminar could have an
+    expiration date the day after the seminar, since the message is not
+    useful after the seminar is over.  Since local hosts have local
+    policies for expiration of news (depending on available disk space,
+    for instance), users are discouraged from providing expiration dates
+    for messages unless there is a natural expiration date associated
+    with the topic.  System software should almost never provide a
+    default "Expires" line.  Leave it out and allow local policies to be
+    used unless there is a good reason not to.
+
+
+
+
+
+
+Horton & Adams                                                  [Page 8]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+2.2.5.  References
+
+    This field lists the Message-ID's of any messages prompting the
+    submission of this message.  It is required for all follow-up
+    messages, and forbidden when a new subject is raised.
+    Implementations should provide a follow-up command, which allows a
+    user to post a follow-up message.  This command should generate a
+    "Subject" line which is the same as the original message, except
+    that if the original subject does not begin with "Re:" or "re:", the
+    four characters "Re:" are inserted before the subject.  If there is
+    no "References" line on the original header, the "References" line
+    should contain the Message-ID of the original message (including the
+    angle brackets).  If the original message does have a "References"
+    line, the follow-up message should have a "References" line
+    containing the text of the original "References" line, a blank, and
+    the Message-ID of the original message.
+
+    The purpose of the "References" header is to allow messages to be
+    grouped into conversations by the user interface program.  This
+    allows conversations within a newsgroup to be kept together, and
+    potentially users might shut off entire conversations without
+    unsubscribing to a newsgroup.  User interfaces need not make use of
+    this header, but all automatically generated follow-ups should
+    generate the "References" line for the benefit of systems that do
+    use it, and manually generated follow-ups (e.g., typed in well after
+    the original message has been printed by the machine) should be
+    encouraged to include them as well.
+
+    It is permissible to not include the entire previous "References"
+    line if it is too long.  An attempt should be made to include a
+    reasonable number of backwards references.
+
+2.2.6.  Control
+
+    If a message contains a "Control" line, the message is a control
+    message.  Control messages are used for communication among USENET
+    host machines, not to be read by users.  Control messages are
+    distributed by the same newsgroup mechanism as ordinary messages.
+    The body of the "Control" header line is the message to the host.
+
+    For upward compatibility, messages that match the newsgroup pattern
+    "all.all.ctl" should also be interpreted as control messages.  If no
+    "Control" header is present on such messages, the subject is used as
+    the control message.  However, messages on newsgroups matching this
+    pattern do not conform to this standard.
+
+
+
+
+
+
+Horton & Adams                                                  [Page 9]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    Also for upward compatibility, if the first 4 characters of the
+    "Subject:" line are "cmsg", the rest of the "Subject:" line should
+    be interpreted as a control message.
+
+2.2.7.  Distribution
+
+    This line is used to alter the distribution scope of the message.
+    It is a comma separated list similar to the "Newsgroups" line.  User
+    subscriptions are still controlled by "Newsgroups", but the message
+    is sent to all systems subscribing to the newsgroups on the
+    "Distribution" line in addition to the "Newsgroups" line.  For the
+    message to be transmitted, the receiving site must normally receive
+    one of the specified newsgroups AND must receive one of the
+    specified distributions.  Thus, a message concerning a car for sale
+    in New Jersey might have headers including:
+
+                   Newsgroups: rec.auto,misc.forsale
+                   Distribution: nj,ny
+
+    so that it would only go to persons subscribing to rec.auto or misc.
+    for sale within New Jersey or New York.  The intent of this header
+    is to restrict the distribution of a newsgroup further, not to
+    increase it.  A local newsgroup, such as nj.crazy-eddie, will
+    probably not be propagated by hosts outside New Jersey that do not
+    show such a newsgroup as valid.  A follow-up message should default
+    to the same "Distribution" line as the original message, but the
+    user can change it to a more limited one, or escalate the
+    distribution if it was originally restricted and a more widely
+    distributed reply is appropriate.
+
+2.2.8.  Organization
+
+    The text of this line is a short phrase describing the organization
+    to which the sender belongs, or to which the machine belongs.  The
+    intent of this line is to help identify the person posting the
+    message, since host names are often cryptic enough to make it hard
+    to recognize the organization by the electronic address.
+
+2.2.9.  Keywords
+
+    A few well-selected keywords identifying the message should be on
+    this line.  This is used as an aid in determining if this message is
+    interesting to the reader.
+
+2.2.10.  Summary
+
+    This line should contain a brief summary of the message.  It is
+    usually used as part of a follow-up to another message.  Again, it
+
+
+
+Horton & Adams                                                 [Page 10]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    is very useful to the reader in determining whether to read the
+    message.
+
+2.2.11.  Approved
+
+    This line is required for any message posted to a moderated
+    newsgroup.  It should be added by the moderator and consist of his
+    mail address.  It is also required with certain control messages.
+
+2.2.12.  Lines
+
+    This contains a count of the number of lines in the body of the
+    message.
+
+2.2.13.  Xref
+
+    This line contains the name of the host (with domains omitted) and a
+    white space separated list of colon-separated pairs of newsgroup
+    names and message numbers.  These are the newsgroups listed in the
+    "Newsgroups" line and the corresponding message numbers from the
+    spool directory.
+
+    This is only of value to the local system, so it should not be
+    transmitted.  For example, in:
+
+               Path: seismo!lll-crg!lll-lcc!pyramid!decwrl!reid
+               From: reid@decwrl.DEC.COM (Brian Reid)
+               Newsgroups: news.lists,news.groups
+               Subject: USENET READERSHIP SUMMARY REPORT FOR SEP 86
+               Message-ID: <5658@decwrl.DEC.COM>
+               Date: 1 Oct 86 11:26:15 GMT
+               Organization: DEC Western Research Laboratory
+               Lines: 441
+               Approved: reid@decwrl.UUCP
+               Xref: seismo news.lists:461 news.groups:6378
+
+    the "Xref" line shows that the message is message number 461 in the
+    newsgroup news.lists, and message number 6378 in the newsgroup
+    news.groups, on host seismo.  This information may be used by
+    certain user interfaces.
+
+3.  Control Messages
+
+    This section lists the control messages currently defined.  The body
+    of the "Control" header line is the control message.  Messages are a
+    sequence of zero or more words, separated by white space (blanks or
+    tabs).  The first word is the name of the control message, remaining
+    words are parameters to the message.  The remainder of the header
+
+
+
+Horton & Adams                                                 [Page 11]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    and the body of the message are also potential parameters; for
+    example, the "From" line might suggest an address to which a
+    response is to be mailed.
+
+    Implementors and administrators may choose to allow control messages
+    to be carried out automatically, or to queue them for annual
+    processing.  However, manually processed messages should be dealt
+    with promptly.
+
+    Failed control messages should NOT be mailed to the originator of
+    the message, but to the local "usenet" account.
+
+3.1.  Cancel
+
+                     cancel 
+
+
+    If a message with the given Message-ID is present on the local
+    system, the message is cancelled.  This mechanism allows a user to
+    cancel a message after the message has been distributed over the
+    network.
+
+    If the system is unable to cancel the message as requested, it
+    should not forward the cancellation request to its neighbor systems.
+
+    Only the author of the message or the local news administrator is
+    allowed to send this message.  The verified sender of a message is
+    the "Sender" line, or if no "Sender" line is present, the "From"
+    line.  The verified sender of the cancel message must be the same as
+    either the "Sender" or "From" field of the original message.  A
+    verified sender in the cancel message is allowed to match an
+    unverified "From" in the original message.
+
+3.2.  Ihave/Sendme
+
+                   ihave  []
+                   sendme  []
+
+    This message is part of the ihave/sendme protocol, which allows one
+    host (say A) to tell another host (B) that a particular message has
+    been received on A.  Suppose that host A receives message
+    "<1234@ucbvax.Berkeley.edu>", and wishes to transmit the message to
+    host B.
+
+    A sends the control message "ihave <1234@ucbvax.Berkeley.edu> A" to
+    host B (by posting it to newsgroup to.B).  B responds with the
+    control message "sendme <1234@ucbvax.Berkeley.edu> B" (on newsgroup
+    to.A), if it has not already received the message.  Upon receiving
+
+
+
+Horton & Adams                                                 [Page 12]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    the sendme message, A sends the message to B.
+
+    This protocol can be used to cut down on redundant traffic between
+    hosts.  It is optional and should be used only if the particular
+    situation makes it worthwhile.  Frequently, the outcome is that,
+    since most original messages are short, and since there is a high
+    overhead to start sending a new message with UUCP, it costs as much
+    to send the ihave as it would cost to send the message itself.
+
+    One possible solution to this overhead problem is to batch requests.
+    Several Message-ID's may be announced or requested in one message.
+    If no Message-ID's are listed in the control message, the body of
+    the message should be scanned for Message-ID's, one per line.
+
+3.3.  Newgroup
+
+                      newgroup  [moderated]
+
+    This control message creates a new newsgroup with the given name.
+    Since no messages may be posted or forwarded until a newsgroup is
+    created, this message is required before a newsgroup can be used.
+    The body of the message is expected to be a short paragraph
+    describing the intended use of the newsgroup.
+
+    If the second argument is present and it is the keyword moderated,
+    the group should be created moderated instead of the default of
+    unmoderated.  The newgroup message should be ignored unless there is
+    an "Approved" line in the same message header.
+
+3.4.  Rmgroup
+
+                            rmgroup 
+
+    This message removes a newsgroup with the given name.  Since the
+    newsgroup is removed from every host on the network, this command
+    should be used carefully by a responsible administrator.  The
+    rmgroup message should be ignored unless there is an "Approved:"
+    line in the same message header.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Horton & Adams                                                 [Page 13]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+3.5.  Sendsys
+                           sendsys (no arguments)
+
+    The sys file, listing all neighbors and the newsgroups to be sent to
+    each neighbor, will be mailed to the author of the control message
+    ("Reply-To", if present, otherwise "From").  This information is
+    considered public information, and it is a requirement of membership
+    in USENET that this information be provided on request, either
+    automatically in response to this control message, or manually, by
+    mailing the requested information to the author of the message.
+    This information is used to keep the map of USENET up to date, and
+    to determine where netnews is sent.
+
+    The format of the file mailed back to the author should be the same
+    as that of the sys file.  This format has one line per neighboring
+    host (plus one line for the local host), containing four colon
+    separated fields.  The first field has the host name of the
+    neighbor, the second field has a newsgroup pattern describing the
+    newsgroups sent to the neighbor.  The third and fourth fields are
+    not defined by this standard.  The sys file is not the same as the
+    UUCP L.sys file.  A sample response is:
+
+      From: cbosgd!mark  (Mark Horton)
+      Date: Sun, 27 Mar 83 20:39:37 -0500
+      Subject: response to your sendsys request
+      To: mark@cbosgd.ATT.COM
+
+      Responding-System: cbosgd.ATT.COM
+      cbosgd:osg,cb,btl,bell,world,comp,sci,rec,talk,misc,news,soc,to,
+            test
+      ucbvax:world,comp,to.ucbvax:L:
+      cbosg:world,comp,bell,btl,cb,osg,to.cbosg:F:/usr/spool/outnews
+            /cbosg
+      cbosgb:osg,to.cbosgb:F:/usr/spool/outnews/cbosgb
+      sescent:world,comp,bell,btl,cb,to.sescent:F:/usr/spool/outnews
+            /sescent
+      npois:world,comp,bell,btl,ug,to.npois:F:/usr/spool/outnews/npois
+      mhuxi:world,comp,bell,btl,ug,to.mhuxi:F:/usr/spool/outnews/mhuxi
+
+3.6.  Version
+
+                           version (no arguments)
+
+    The name and version of the software running on the local system is
+    to be mailed back to the author of the message ("Reply-to" if
+    present, otherwise "From").
+
+3.7.  Checkgroups
+
+
+
+Horton & Adams                                                 [Page 14]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    The message body is a list of "official" newsgroups and their
+    description, one group per line.  They are compared against the list
+    of active newsgroups on the current host.  The names of any obsolete
+    or new newsgroups are mailed to the user "usenet" and descriptions
+    of the new newsgroups are added to the help file used when posting
+    news.
+
+4.  Transmission Methods
+
+    USENET is not a physical network, but rather a logical network
+    resting on top of several existing physical networks.  These
+    networks include, but are not limited to, UUCP, the Internet, an
+    Ethernet, the BLICN network, an NSC Hyperchannel, and a BERKNET.
+    What is important is that two neighboring systems on USENET have
+    some method to get a new message, in the format listed here, from
+    one system to the other, and once on the receiving system, processed
+    by the netnews software on that system.  (On UNIX systems, this
+    usually means the rnews program being run with the message on the
+    standard input. <1>)
+
+    It is not a requirement that USENET hosts have mail systems capable
+    of understanding the Internet mail syntax, but it is strongly
+    recommended.  Since "From", "Reply-To", and "Sender" lines use the
+    Internet syntax, replies will be difficult or impossible without an
+    Internet mailer.  A host without an Internet mailer can attempt to
+    use the "Path" header line for replies, but this field is not
+    guaranteed to be a working path for replies.  In any event, any host
+    generating or forwarding news messages must have an Internet address
+    that allows them to receive mail from hosts with Internet mailers,
+    and they must include their Internet address on their From line.
+
+4.1.  Remote Execution
+
+    Some networks permit direct remote command execution.  On these
+    networks, news may be forwarded by spooling the rnews command with
+    the message on the standard input.  For example, if the remote
+    system is called remote, news would be sent over a UUCP link
+    with the command:
+
+                              uux - remote!rnews
+
+    and on a Berknet:
+
+                              net -mremote rnews
+
+
+
+
+
+
+
+Horton & Adams                                                 [Page 15]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    It is important that the message be sent via a reliable mechanism,
+    normally involving the possibility of spooling, rather than direct
+    real-time remote execution.  This is because, if the remote system
+    is down, a direct execution command will fail, and the message will
+    never be delivered.  If the message is spooled, it will eventually
+    be delivered when both systems are up.
+
+4.2.  Transfer by Mail
+
+    On some systems, direct remote spooled execution is not possible.
+    However, most systems support electronic mail, and a news message
+    can be sent as mail.  One approach is to send a mail message which
+    is identical to the news message: the mail headers are the news
+    headers, and the mail body is the news body.  By convention, this
+    mail is sent to the user newsmail on the remote machine.
+
+    One problem with this method is that it may not be possible to
+    convince the mail system that the "From" line of the message is
+    valid, since the mail message was generated by a program on a
+    system different from the source of the news message.  Another
+    problem is that error messages caused by the mail transmission
+    would be sent to the originator of the news message, who has no
+    control over news transmission between two cooperating hosts
+    and does not know whom to contact.  Transmission error messages
+    should be directed to a responsible contact person on the
+    sending machine.
+
+    A solution to this problem is to encapsulate the news message into a
+    mail message, such that the entire message (headers and body) are
+    part of the body of the mail message.  The convention here is that
+    such mail is sent to user rnews on the remote system.  A mail
+    message body is generated by prepending the letter N to each line of
+    the news message, and then attaching whatever mail headers are
+    convenient to generate.  The N's are attached to prevent any special
+    lines in the news message from interfering with mail transmission,
+    and to prevent any extra lines inserted by the mailer (headers,
+    blank lines, etc.) from becoming part of the news message.  A
+    program on the receiving machine receives mail to rnews, extracting
+    the message itself and invoking the rnews program.  An example in
+    this format might look like this:
+
+
+
+
+
+
+
+
+
+
+
+Horton & Adams                                                 [Page 16]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+                Date: Mon, 3 Jan 83 08:33:47 MST
+                From: news@cbosgd.ATT.COM
+                Subject: network news message
+                To: rnews@npois.ATT.COM
+
+                NPath: cbosgd!mhuxj!harpo!utah-cs!sask!derek
+                NFrom: derek@sask.UUCP (Derek Andrew)
+                NNewsgroups: misc.test
+                NSubject: necessary test
+                NMessage-ID: <176@sask.UUCP>
+                NDate: Mon, 3 Jan 83 00:59:15 MST
+                N
+                NThis really is a test.  If anyone out there more than 6
+                Nhops away would kindly confirm this note I would
+                Nappreciate it.  We suspect that our news postings
+                Nare not getting out into the world.
+                N
+
+    Using mail solves the spooling problem, since mail must always be
+    spooled if the destination host is down.  However, it adds more
+    overhead to the transmission process (to encapsulate and extract the
+    message) and makes it harder for software to give different
+    priorities to news and mail.
+
+4.3.  Batching
+
+    Since news messages are usually short, and since a large number of
+    messages are often sent between two hosts in a day, it may make
+    sense to batch news messages.  Several messages can be combined into
+    one large message, using conventions agreed upon in advance by the
+    two hosts.  One such batching scheme is described here; its use is
+    highly recommended.
+
+    News messages are combined into a script, separated by a header of
+    the form:
+
+
+                   #! rnews 1234
+
+    where 1234 is the length of the message in bytes.  Each such line is
+    followed by a message containing the given number of bytes.  (The
+    newline at the end of each line of the message is counted as one
+    byte, for purposes of this count, even if it is stored as .)  For example, a batch of message might look
+    like this:
+
+
+
+
+
+
+Horton & Adams                                                 [Page 17]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+                #! rnews 239
+                From: jerry@eagle.ATT.COM (Jerry Schwarz)
+                Path: cbosgd!mhuxj!mhuxt!eagle!jerry
+                Newsgroups: news.announce
+                Subject: Usenet Etiquette -- Please Read
+                Message-ID: <642@eagle.ATT.COM>
+                Date: Fri, 19 Nov 82 16:14:55 EST
+                Approved: mark@cbosgd.ATT.COM
+
+                Here is an important message about USENET Etiquette.
+                #! rnews 234
+                From: jerry@eagle.ATT.COM (Jerry Schwarz)
+                Path: cbosgd!mhuxj!mhuxt!eagle!jerry
+                Newsgroups: news.announce
+                Subject: Notes on Etiquette message
+                Message-ID: <643@eagle.ATT.COM>
+                Date: Fri, 19 Nov 82 17:24:12 EST
+                Approved: mark@cbosgd.ATT.COM
+
+                There was something I forgot to mention in the last
+                message.
+
+    Batched news is recognized because the first character in the
+    message is #.  The message is then passed to the unbatcher for
+    interpretation.
+
+    The second argument (in this example rnews) determines which
+    batching scheme is being used.  Cooperating hosts may use whatever
+    scheme is appropriate for them.
+
+5.  The News Propagation Algorithm
+
+    This section describes the overall scheme of USENET and the
+    algorithm followed by hosts in propagating news to the entire
+    logical network.  Since all hosts are affected by incorrectly
+    formatted messages and by propagation errors, it is important
+    for the method to be standardized.
+
+    USENET is a directed graph.  Each node in the graph is a host
+    computer, and each arc in the graph is a transmission path from
+    one host to another host.  Each arc is labeled with a newsgroup
+    pattern, specifying which newsgroup classes are forwarded along
+    that link.  Most arcs are bidirectional, that is, if host A
+    sends a class of newsgroups to host B, then host B usually sends
+    the same class of newsgroups to host A.  This bidirectionality
+    is not, however, required.
+
+    USENET is made up of many subnetworks.  Each subnet has a name, such
+
+
+
+Horton & Adams                                                 [Page 18]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    as comp or btl.  Each subnet is a connected graph, that is, a path
+    exists from every node to every other node in the subnet.  In
+    addition, the entire graph is (theoretically) connected.  (In
+    practice, some political considerations have caused some hosts to be
+    unable to post messages reaching the rest of the network.)
+
+    A message is posted on one machine to a list of newsgroups. That
+    machine accepts it locally, then forwards it to all its neighbors
+    that are interested in at least one of the newsgroups of the
+    message.  (Site A deems host B to be "interested" in a newsgroup if
+    the newsgroup matches the pattern on the arc from A to B.  This
+    pattern is stored in a file on the A machine.)  The hosts receiving
+    the incoming message examine it to make sure they really want the
+    message, accept it locally, and then in turn forward the message to
+    all their interested neighbors.  This process continues until the
+    entire network has seen the message.
+
+    An important part of the algorithm is the prevention of loops.  The
+    above process would cause a message to loop along a cycle forever.
+    In particular, when host A sends a message to host B, host B will
+    send it back to host A, which will send it to host B, and so on.
+    One solution to this is the history mechanism.  Each host keeps
+    track of all messages it has seen (by their Message-ID) and
+    whenever a message comes in that it has already seen, the incoming
+    message is discarded immediately.  This solution is sufficient to
+    prevent loops, but additional optimizations can be made to avoid
+    sending messages to hosts that will simply throw them away.
+
+    One optimization is that a message should never be sent to a machine
+    listed in the "Path" line of the header.  When a machine name is
+    in the "Path" line, the message is known to have passed through the
+    machine.  Another optimization is that, if the message originated
+    on host A, then host A has already seen the message.  Thus, if a
+    message is posted to newsgroup misc.misc, it will match the pattern
+    misc.all (where all is a metasymbol that matches any string), and
+    will be forwarded to all hosts that subscribe to misc.all (as
+    determined by what their neighbors send them).  These hosts make up
+    the misc subnetwork.  A message posted to btl.general will reach all
+    hosts receiving btl.all, but will not reach hosts that do not get
+    btl.all.  In effect, the messages reaches the btl subnetwork.  A
+    messages posted to newsgroups misc.misc,btl.general will reach all
+    hosts subscribing to either of the two classes.
+
+Notes
+
+    <1>  UNIX is a registered trademark of AT&T.
+
+
+
+
+
+Horton & Adams                                                 [Page 19]
+
+Back Go Back + + + + diff --git a/html/ftsc/fsc-0062.html b/html/ftsc/fsc-0062.html new file mode 100755 index 00000000..aacd685a --- /dev/null +++ b/html/ftsc/fsc-0062.html @@ -0,0 +1,363 @@ + + +A Proposed Nodelist flag indicating Online Times of a Node. + + + + +
+ | Document: FSC-0062
+ | Version:  003
+ | Date:     April 14, 1996
+ | Author:   David J. Thomas
+
+
+
+
+	  A Proposed Nodelist flag indicating Online Times of a Node
+                               David J. Thomas
+                            2:442/600@fidonet.org
+
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+  Note
+  ----
+
+  Changes in content between the previous edition of this document, and this
+  edition, are signified by bars (|) in the left margin, except where
+  otherwise specified. I have changed the format of the document slightly to
+  allow this. Where the format of the document has changed, but the actual
+  text has not, bars are not present.
+
+  Purpose
+  -------
+
+  There are currently several systems within FidoNet that offer file request
+  or mail holding capabilities but are not continuously online. The only time
+  during which these nodes can be contacted with reference to the nodelist is
+  currently the Zone Mail Hour of the zone to which the systems belong. In
+  theory, mailers can only use the zone mail hour(s) specified by the system
+  in question to contact these nodes, which does not provide for any method
+  of file requesting or calling for echomail that does not conflict with the
+  Policy requirement that no echomail or files be transferred during the zone
+  mail hour. This means that, in practice, if it is known that a particular
+  node is online for more time than ZMH alone, but less than 24 hours a day,
+  it is necessary to "kludge," or set this up as a special situation, in most
+  mailers whenever a node has to be contacted a number of times, whether
+  regularly or irregularly. The proposed flag would benefit the mailers in
+  such a way as to provide for them the online times that the node is usually
+  online for, thus cutting on the costs of calling a non-continuous mail
+  node, only to find that it is not available; and also, hopefully preventing
+  annoyance for a sysop whose mailer is being called whilst it is not online,
+  for example in the case of a voice/data shared line.
+
+  Compatibility
+  -------------
+
+  Since the current nodelist format is always being extended and nodelist
+  processors look only for the flags that they know about, there are no
+  expected compatibility problems with the suggestion outlined below.
+
+  Format of additional nodelist flag
+  ----------------------------------
+
+  The proposed nodelist flag has the following form:
+
+    Txy
+
+  where x represents the startup time, and y the end time, in the following
+  format:
+
+   +------+----+  +------+----+  +------+----+  +------+----+  +------+----+
+   |Letter|Time|  |Letter|Time|  |Letter|Time|  |Letter|Time|  |Letter|Time|
+   +------+----+  +------+----+  +------+----+  +------+----+  +------+----+
+   |   A  |0000|  |   F  |0500|  |   K  |1000|  |   P  |1500|  |   U  |2000|
+   |   a  |0030|  |   f  |0530|  |   k  |1030|  |   p  |1530|  |   u  |2030|
+   |   B  |0100|  |   G  |0600|  |   L  |1100|  |   Q  |1600|  |   V  |2100|
+   |   b  |0130|  |   g  |0630|  |   l  |1130|  |   q  |1630|  |   v  |2130|
+   |   C  |0200|  |   H  |0700|  |   M  |1200|  |   R  |1700|  |   W  |2200|
+   |   c  |0230|  |   h  |0730|  |   m  |1230|  |   r  |1730|  |   w  |2230|
+   |   D  |0300|  |   I  |0800|  |   N  |1300|  |   S  |1800|  |   X  |2300|
+   |   d  |0330|  |   i  |0830|  |   n  |1330|  |   s  |1830|  |   x  |2330|
+   |   E  |0400|  |   J  |0900|  |   O  |1400|  |   T  |1900|  |      |    |
+   |   e  |0430|  |   j  |0930|  |   o  |1430|  |   t  |1930|  |      |    |
+   +------+----+  +------+----+  +------+----+  +------+----+  +------+----+
+
+| This flag is not intended to be a user flag. The flag is intended to provide
+| information to computerised mailer processes, and is not easily read by
+| human beings (although they can of course interpret the meaning of the
+| flag); most mailers however do not attempt to interpret any information that
+| is specified as a user flag, assuming that it is there for the benefit of
+| human beings. Such mailers would not be able to make use of the information
+| provided, which is the purpose of the flag.
+
+| This flag is of course not specified in FTS-0005 at the time of writing, but
+| this is not regarded by FidoNet as a problem because other flags in current
+| use are not specified in FTS-0005.
+
+  The case of the letter could be relevant. Whereas the case is currently not
+  used by any flags in the document describing the current format of the
+  nodelist, there exists the potential for the case of a letter to have
+  relevant meaning. The case has to be correct for the CRC check calculation
+  to prove correct, and this would be a good use for the case of the letter.
+  If it is necessary to ignore the case, then the upper on-the-hour time
+  should be used, i.e. the time that is listed after the upper-case letter.
+
+| These times are expressed in UTC so that the flag is useful for systems all
+  around the world, without the need for specific time zone information to be
+  included in the nodelist. They do not adjust with daylight saving time for a
+  similar reason. Note the section on daylight saving time for information
+  about handling adjustments without changing the flag; this is important.
+
+  Where necessary, the times can wrap around midnight, so for example, for a
+| node that is online between the hours of 1800 and 0600 UTC, the flag TSG
+  would be a valid indication of this time.
+
+  This nodelist entry is not required by any node. It is supplementary to the
+  #01, #02, #08, #09, #18, #20 flags and their !xx counterparts, though its
+  meaning is different. It has been suggested to me about the possibility of
+  an additional flag with the same meaning, but having a W as the first
+  letter, indicating that the node is also available for all hours during
+  weekends; however, I believe that the simple inclusion of the single flag
+  indicated above will solve most problems, as it does indicate a period for
+  non-CM nodes during which the node is available, which is all that is
+  really required.
+
+  Daylight saving time
+  --------------------
+
+  If a node changes online times with respect to UTC when daylight saving
+  time becomes effective (which would be the case with most part time nodes),
+  then this is to be taken into account when assigning this flag. An online
+  times flag assigned to a node should not be altered for the specific
+  purpose of adjusting due to daylight saving time, since large difference
+  files (NODEDIFF's) would result if every node was allowed to do this, e.g.
+  my node used to be online from 2300 to 0800 in local time, which in winter
+| is UTC, but in the summer it becomes BST (British Summer Time). This is one
+| hour ahead of UTC, and the corresponding availability times of my node
+| during the summer period were 2200 to 0700 UTC. Therefore my online times
+  flag would have indicated availability between the hours of 2300 and 0700
+| UTC, the daily time period encompassing both times, so the flag would be
+  TXH.
+
+  Policy considerations
+  ---------------------
+
+  This is a technical document. However, since the flag could make for an
+  increase in the size of difference files, the author feels that the
+  following guidelines should be adopted concerning the use of the flag.
+
+  The online times flag does not replace the requirement for exclusivity of
+  zone mail hour to be maintained. It is still annoying behaviour to have
+  this flag and be unavailable during ZMH, just as it is annoying behaviour
+  to have the CM (continuous mail) flag in one's entry, and disregard ZMH.
+
+  Except for during ZMH, the sysop of a node using this flag finding that
+  they need to take their mailer offline during the specified times to
+  perform system maintenance, or for any other reason, would not be acting in
+  an annoying manner to do so, unless the practice is found to be continuous,
+  in which case the flag's times could be reduced, or the flag itself could
+  be removed from their node entry.
+
+  It should be noted that this flag is present for the benefit of mailers,
+  not human beings. This means that the flag should be used only to indicate
+  when a mailer is ready to receive calls. A system that uses a FidoNet-
+  technology mailer in ZMH, and a human-access only system during other
+  period(s) of the day that cannot receive mail, should not use this flag.
+  This flag does not explicitly specify online times of a public access BBS,
+  although for presumably most nodes with FidoNet-capable software, a public
+  access BBS will be available during the times indicated.
+
+  Where the flag is used, it should not often be changed. If a situation
+  exists, for example, where a node uses a certain set of times during the
+  first two weeks of a month, and a different set of times during the
+  remainder period, the flag should be set to a time during each day of the
+  month when the node is online. For example, if a node is online during
+  1800-0800 for the first two weeks, and then during 2200-1000 for the
+  remainder, the time flag should specify 2200-0800 only. If there is no such
+  time (other than ZMH) then no flag should be used. Of course, any permanent
+  changes, and any necessary reductions in the times, should be permitted at
+  any time, but changes owing only to daylight saving time should certainly
+  be expressly forbidden.
+
+  File requests and user access are of course permitted during the online
+  times indicated (except ZMH).
+
+  The above list may seem rather frightening! Please note that they are
+  guidelines rather than rules, unless FidoNet policy has included them as
+  rules. In the vast majority of situations where a node is online for a
+  fixed set of hours per day, the only thing to watch out for is that you get
+  the daylight saving time period right. Then you don't have to worry about
+  changing it at any time, except when your own online times change.
+
+  Example
+  -------
+
+  With regard to time zones now; this is a complicated topic, so I wish to
+  express an example. Imagine a node in Indiana, USA. It is online for the
+  time period beginning 6 o'clock pm (1800) and ending 8 o'clock am (0800).
+  This changes with daylight saving time, so the times expressed effectively
+| become an hour earlier with respect to UTC during daylight saving time.
+
+| Indiana is in the Central time zone, which is 6 hours behind UTC. Therefore,
+| the online times in UTC can be expressed as 0000-1400 UTC during winter.
+| During daylight saving time, however, the local time for Indiana is 5 hours
+| behind UTC. The online times during this period are 0100-1500 UTC. The
+| subset should be used, so that the online times flag for the node should
+| indicate availability between 0100 and 1400 UTC, which is indicated
+| by the flag TBO.
+
+| (Thanks to a few people for pointing out that the previous example was in
+| error; it assumed that Indiana was ahead of UTC, and not behind as is
+| actually the case.)
+
+  ANSI C routines to Calculate the Online Times Flag
+  --------------------------------------------------
+
+  These were not provided in the first edition. Change bars will not be used
+  here, since they would interfere with the syntax of the presented routines.
+
+  The first program calculates the online times flag from the user's entry of
+  the online times of a system, expressed in the local time zone, and the
+  offset to UTC used by the user's country. It takes into account that the
+  clock is put forward and back once a year by reducing the end time by one
+  hour. The program should work on any platform, and has been tested.
+
+=== start of code ===
+/* TIMEFLAG.C
+   Calculates FSC-0062 time flag requirement from user input */
+
+#include 
+
+char *onlineflag(char *on, char *off, int utc_diff);
+
+void main()
+{
+   char on[6], off[6]; int utc_diff;
+
+   printf("\nPlease specify the time you come online [HH:MM]: ");
+   scanf("%s", on);
+   printf("\nPlease specify the time you come offline [HH:MM]: ");
+   scanf("%s", off);
+   printf("\nSpecify the difference between your local time zone in winter\n"
+      "time and UTC (e.g. if your time zone is 6 hours behind UTC,\n"
+      "enter 6): ");
+   scanf("%d", &utc_diff);
+   printf("\nYour online time flag is %s\n\n",
+      onlineflag(on, off, utc_diff));
+}
+
+char *onlineflag(char *ontime, char *offtime, int utcdiff)
+{
+   int onhour, onmin, offhour, offmin;
+   static char flag[4]="T  ";
+
+   sscanf(ontime, "%d:%d", &onhour, &onmin);
+   sscanf(offtime, "%d:%d", &offhour, &offmin);
+
+   if(onmin>30) ++onhour;
+   --offhour; /* to correct for daylight saving time */
+   onhour = (onhour+24+utcdiff) % 24;
+   offhour = (offhour+24+utcdiff) % 24;
+
+   flag[1]='A'+onhour;
+   flag[2]='A'+offhour;
+
+   if(onmin>0 && onmin<31) flag[1] += 'a'-'A';
+   if(offmin>29) flag[2] += 'a'-'A';
+
+   return flag;
+}
+=== end of code ===
+
+  The second program calculates the online times from the time flag, input
+  as a pointer to char to the routine (this being of the format "Txy"). It
+  returns a pointer to a structure which contains the on- and off-times in
+  UTC. This is not a complete program; it is designed to be used by mailers
+  to determine the valid online times. It has also been tested.
+
+=== start of code ===
+/* INTFLAG.C
+   Interprets online time flags and converts them to a set of UTC times */
+
+struct TIMES {
+   int on_hour;
+   int on_min;
+   int off_hour;
+   int off_min;
+};
+
+struct TIMES *interpret_flag(char *time_flag);
+
+struct TIMES *interpret_flag(char *timeflag)
+{
+   static struct TIMES times;
+
+   times.on_min=0;
+   times.off_min=0;
+
+   times.on_hour=timeflag[1]-'A';
+   if(times.on_hour>23) {
+      times.on_hour -= 'a'-'A';
+      times.on_min=30;
+   }
+   times.off_hour=timeflag[2]-'A';
+   if(times.off_hour>23) {
+      times.off_hour -= 'a'-'A';
+      times.off_min=30;
+   }
+   return ×
+}
+=== end of code ===
+
+| The above routines can be copied and re-used as desired. I am now an
+| amazing C programmer, but I still make no guarantees about them! :-)
+
+  Summary
+  -------
+
+  I believe this to be a neat and compact solution to, what is in my opinion,
+  one of the gravest problems currently facing FidoNet. In FidoNet, most
+  nodes are continuous mail, but it is important for the growth and
+  popularity of FidoNet that non-CM nodes do not receive many mailer calls at
+  times when they are off line. Users are bad enough in this respect. It is
+  also useful for people wishing to contact hubs that are non-CM with mail
+  for a downlink, and for people wishing to file request from a node that is
+  not CM. There is no need for systems that are only online in zone mail hour
+  to adopt this flag; also, there is no need for CM systems to adopt this
+  flag.
+
+  Contacting the Author
+  ---------------------
+
+  My board is now online continuously, except for periods of down time during
+| which the board is maintained (few and far between now that Linux is used).
+  Netmail contact is therefore possible at any time. I went CM because of a
+  certain number of nodes calling at the wrong times, and also users. Users
+  weren't too bad, but I dislike 0600 am wake-up calls, repeated at regular
+  three-minute intervals for an hour, by mailers, rather intensely :-)
+
+End of document.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0070.html b/html/ftsc/fsc-0070.html new file mode 100755 index 00000000..a21682a1 --- /dev/null +++ b/html/ftsc/fsc-0070.html @@ -0,0 +1,122 @@ + + +Improving FidoNet/UseNet gating and Dupe Checking. + + + + +
+Document:   FSC-0070
+Date:       15-Jul-94
+Revision:   002
+
+              Improving Fidonet/Usenet gating and Dupe Checking
+                              
+                    Franck Arnaud, Fidonet 2:320/213.666
+
+
+
+  Status of this document
+  -----------------------
+
+ This FSC suggests a proposed standard for the FidoNet(r) community,
+ and invites discussion and suggestions for improvements. Distribution of
+ this document is unlimited.
+
+ Fido and FidoNet are registered marks of Tom Jennings and Fido Software.
+   
+
+  Introduction
+  ------------
+
+ The complexity of Usenet/Fidonet gating and the large number of gateways
+ has led to a non-negligible quantity of duplicates appearing regularly in 
+ both the Usenet and Fidonet worlds. This proposal defines a standard method 
+ for gateway software to deal with conversion of message identifiers between 
+ both worlds, so that we can improve the reliability of Usenet/Fidonet 
+ gateways.
+
+ In this document "^" means  (character 01h).
+
+
+  History
+  -------
+
+ Revision 002 adds details and makes the Fidonet to Usenet sheme FTS-0009
+ compliant.
+
+
+  Usenet To Fidonet Message Identifier Conversion
+  -----------------------------------------------
+
+ A major problem is preventing messages gated into Fidonet from RFC822 from
+ being gated back to Usenet at another gateway with a new message id. The
+ easy way to solve that is simply to store the RFC message ID in a kludge 
+ line. This kludge line could also allow identifying messages gated from 
+ Usenet (this could be used by message editors to allow private replies to 
+ the nearest uucp gateway for example).
+
+ It is proposed that the ^RFCID: kludge is used to store the RFC Message-ID:
+ in Fidonet messages. Of course, the use of the RFCID kludge doesn't replace
+ the standard fts-0009 Message-ID:.
+
+       (Usenet)  Message-ID: <92_feb_10_19192012901@prep.ai.mit.edu>
+    to (Fido)    ^MSGID: 2:300/400.5 6789fedc
+                 ^RFCID: 92_feb_10_19192012901@prep.ai.mit.edu
+
+ Note ^RFCID does not include the Message-ID enclosing "<" and ">".
+
+ Then if a gateway finds a ^RFCID line in a Fido message, it will use it in
+ the Usenet message ID, instead of converting the ^MSGID.
+
+
+  Fidonet to Usenet Message Identifiers Conversion
+  ------------------------------------------------
+
+ The dupe checking in Usenet is based on the message ID. Fidonet now has its
+ own standard message identification standard (fts-0009).
+
+ So it would be interesting if the same Fidonet message gated at different
+ gateways had the same ID in Usenet to help news processing programs in
+ stopping dupes.
+
+ The proposed fido ^MSGID: to RFC1036 Message-ID: conversion method is 
+ defined as below:
+
+ The ^MSGID: value (a string) is not parsed and converted as below to the ID
+ part of Usenet's Message-ID. The Message-ID domain is the fidonet domain,
+ "fidonet.org" if the gated echomail comes from the Fidonet(tm) network.
+
+ To convert the MSGID string, the following rules are applied:
+ - Alphanumeric (a-z,A-Z,0-9) characters are kept intact (case preserved).
+ - Non-alphanumeric characters - including the space beetwen the origin
+   address and the serial number - are converted to '-'.
+
+ Some examples:
+
+    (Fido)   ^MSGID: 2:300/400 12345AbC
+ to (Usenet) Message-ID: <2-300-400-12345AbC@fidonet.org>
+
+    (Fido)   ^MSGID: 15:300/400.50@somenet abcd6789
+ to (Usenet) Message-ID: <15-300-400-50-somenet-abcd6789@fidonet.org>
+
+    (Fido)   ^MSGID: Internet.Domain.org aBcD1234
+ to (Usenet) Message-ID: 
+
+    (Fido)   ^MSGID: "LZKkoe$1982 98a" 45678bcd
+ to (Usenet) Message-ID: <-LZKkoe-1982-98a--45678bcd@fidonet.org>
+
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0072.html b/html/ftsc/fsc-0072.html new file mode 100755 index 00000000..aff543f1 --- /dev/null +++ b/html/ftsc/fsc-0072.html @@ -0,0 +1,1925 @@ + + +The HYDRA file transfer protocol. + + + + +
+Document: FSC-0072
+Version:  001
+Date:     21-Feb-1993
+
+
+
+
+                    The HYDRA file transfer protocol
+
+               Joaquim H. Homrighausen and Arjen G. Lentz
+
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is subject to the restrictions listed
+     below.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+
+
+    ---------------------------------------------------------------------
+     Copyright 1991-1993 Joaquim H. Homrighausen. All rights reserved.
+     Copyright 1991-1993 Lentz Software Development. All rights reserved.
+    ---------------------------------------------------------------------
+
+
+    Restrictions
+    =====================================================================
+    You are granted a license to implement the HYDRA file transfer
+    protocol, HYDRA hereafter, in your own programs and/or use the sample
+    source code and adapt these to your particular situation and needs;
+    subject to the following conditions:
+
+    o You must refer to it as the HYDRA file transfer protocol, and you
+      must give credit to the authors of HYDRA in any information screens
+      or literature pertaining to your programs that contains other such
+      information (credits, your own copyrights, etc.).
+
+    o HYDRA will always remain backwards compatible with previous
+      revisions. HYDRA allows for expansion of its features without
+      interfering with previous revisions. It is, however, important that
+      different people do not expand the protocol in different directions.
+      We therefore ask you to contact us if you have any needs/ideas
+      regarding HYDRA, so development can be synchronized and beneficial
+      to all.
+
+    o If your implementation cannot converse with past or future revisions
+      as supplied by us, then you must refer to it as "HYDRA derived", or
+      as "a variation of HYDRA", or words to that effect.
+
+    Permission is hereby granted to the FTSC (FidoNet Technical Standards
+    Committee) and other technical organisations to republish this
+    document in its entirety. Librarians may change the title page and
+    page headers to match their library format as long as all copyrights
+    and body text remain unaltered. The original document name and source
+    must be mentioned in any republished versions of this document.
+
+    No organization, company, person, or other being may impose any fees
+    for any reason for providing this document. This document may not be
+    sold or otherwise transferred for personal or company gain under any
+    circumstances.
+
+
+    Disclaimer
+    =====================================================================
+    This information is provided "as is" and comes with no warranties of
+    any kind, either expressed or implied. There is no support available
+    for this package. It's intended to be used by programmers and
+    developers.
+
+    In no event shall the authors be liable to you or anyone else for any
+    damages, including any lost profits, lost savings or other incidental
+    or consequential damages arising out of the use or inability to use
+    this information.
+
+
+    Revision timestamps
+    =====================================================================
+    001                           0x2b1aab00                 Dec 01, 1992
+
+
+    Introduction
+    =====================================================================
+    This document will not attempt to convince the reader that HYDRA is
+    of value to him/her or that it is better than other file transfer
+    protocols, it will simply describe the protocol. Just to get it out
+    of the way, HYDRA is not the ultimate file transfer protocol.
+
+    The authors do, however, feel that it offers an significant
+    improvement over those file transfer protocols available today. HYDRA
+    is a bi-directional protocol with the ability to receive and send
+    files simultaneously. There are other bi-directional file transfer
+    protocols, but to the authors' knowledge no public specifications
+    exist.
+
+    HYDRA owes much to Zmodem and its designer, Chuck Forsberg as well as
+    to Janus, designed by Rick Huebner. We would like to think of HYDRA
+    as a combination of both with a few extra options installed.
+
+    The basic concept of a bi-directional file transfer protocol is
+    simple. Both data channels are utilized to transmit and receive files
+    simultaneously. I.e. two 100 kb files can be exchanged between two
+    parties in the time it takes a fully streaming uni-directional file
+    transfer protocol to transmit one of the files.
+
+
+    Protocol design
+    =====================================================================
+    The ultimate goal when designing HYDRA was to design a protocol that
+    is as simple and robust as possible; complexity increase the problem
+    of faulty implementations.
+
+    The obvious function of a file transfer protocol is to transport a
+    collection of data from its source to its destination as efficient
+    possible and without jeopardizing the integrity of the data.
+
+    The lack of data compression and lost packet management (as used in
+    Kermit and Super Kermit) is intentional. The authors feel that this
+    unnecessarily increases the complexity of the protocol.
+
+    While HYDRA performs to its best on full duplex links, it should be
+    possible to use it on links using proprietary protocols such as the
+    US Robotics HST protocol which features one 14.4 kbps data channel
+    and one 450 bps back channel.
+
+    The protocol design should be flexible enough for future enhancements
+    while maintaining backward compatibility.
+
+
+    Protocol requirements and restrictions
+    =====================================================================
+    HYDRA require that the link can handle ASCII character 24 (DLE) as
+    well as all ASCII characters in the range 32 through 126. All other
+    characters can be escaped or encoded by the protocol as required by
+    the link.
+
+    Capability of the computer to perform simultaneous serial I/O as well
+    as simultaneous serial I/O combined with disk access is preferred,
+    but can be circumvented by opting for windowed transmission instead
+    of full streaming.
+
+    HYDRA calls for the ability to check whether there is anything in the
+    serial input buffer (i.e. "peek-ahead"), but it doesn't mind if it
+    has to wait for a second if there is no data available (using for
+    instance the UNIX alarm() mechanism).
+
+    The protocol is extremely tolerant with timeouts (i.e. satellite or
+    network delays) while still maintaining maximum reliability,
+    robustness, and throughput.
+
+
+    Terms and definitions
+    =====================================================================
+    A BYTE                   An 8-bit unsigned character.
+    A WORD                   A 16-bit unsigned integer.
+    A DWORD                  A 32-bit unsigned integer.
+    A LONG                   A 32-bit SIGNED integer.
+    FILE OFFSETS (position)  A long.
+    NUL                      The ASCII character 0.
+    BS                       The ASCII character 8.
+    CR                       The ASCII character 13.
+    XOFF                     The ASCII character 17.
+    XON                      The ASCII character 19.
+    H_DLE                    The HYDRA link escape character, ASCII 24
+                             (^X).
+    SP or SPACE              The ASCII character 32.
+    UNIX timestamp           A specific time and date expressed as the
+                             number of seconds since midnight, January
+                             1st, 1970. All UNIX timestamps used in HYDRA
+                             are expressed in local time.
+
+    Multi-byte items are transmitted in "low-byte first" order, so big-
+    endian CPUs (like 680xx) need to do some byteswapping, depending on
+    the implementation.
+
+    Values preceded by '0x' are in hexadecimal notation (base 16, 0..9
+    a..f). All values transmitted in hexadecimal notation must be
+    converted to lowercase characters and left-padded to their full
+    size with '0' prior to transmission. E.g. a WORD with the value 255
+    (decimal) is expressed as 00ff. A LONG with the value 255 (decmial)
+    is expressed as 000000ff.
+
+    In formulas, "AND" means bitwise AND, "XOR" means bitwise Exclusive
+    OR, "NOT" is ones complement (i.e. all zeros become ones, all ones
+    become zeros). The ">>" is a shift operation to the right, "R >> 3"
+    means shift R three bits to the right.
+
+
+    General packet format
+    =====================================================================
+    All data exchange is done with framed packets protected by 16 or 32
+    bit CRC values appended to the packet data and packet type (low-
+    byte first). The only exception to this is the cancel sequence of 5
+    consecutive H_DLE characters.
+
+    All packets except those with the type DATA are followed by a CR
+    (ASCII 13) to help get through some buffered environments and aid
+    possible debugging and/or tracing. If requested by the other side in
+    its INIT packet, packets can also be prefixed by a specific data
+    string which can include NULs, delays or break signals. Refer to the
+    section on the INIT packet for more information.
+
+
+                          Format of unframed packet
+
+                +------------------------------------------+
+                ~ Zero or more bytes packet dependent data ~
+                +------------------------------------------+
+                | Packet type byte                         |
+                +------------------------------------------+
+                | CRC-16/32 of packet data and packet type |
+                +------------------------------------------+
+
+
+                            Table of packet types
+
+         +--------+---------+-----+--------------------------------+
+         |Name    |Character|ASCII|Description                     |
+         +--------+---------+-----+--------------------------------+
+         |START   |   'A'   |  65 |Startup sequence                |
+         |INIT    |   'B'   |  66 |Session initialisation          |
+         |INITACK |   'C'   |  67 |Response to INIT packet         |
+         |FINFO   |   'D'   |  68 |File information                |
+         |FINFOACK|   'E'   |  69 |Response to FINFO packet        |
+         |DATA    |   'F'   |  70 |File data packet                |
+         |DATAACK |   'G'   |  71 |File data position ACK packet   |
+         |RPOS    |   'H'   |  72 |Reposition request packet       |
+         |EOF     |   'I'   |  73 |End of file packet              |
+         |EOFACK  |   'J'   |  74 |Response to EOF packet          |
+         |END     |   'K'   |  75 |End of session                  |
+         |IDLE    |   'L'   |  76 |Idle (just saying I'm alive)    |
+         |DEVDATA |   'M'   |  77 |Data to specified device     (1)|
+         |DEVDACK |   'N'   |  78 |Response to DEVDATA packet   (1)|
+         +--------+---------+-----+--------------------------------+
+
+    (1) Support for DEVDATA and DEVDACK types is optional and indicated
+        in INIT state of a HYDRA session.
+
+
+                           Format of framed packet
+
+               +----------------------+--------------------+
+               |        H_DLE         |Packet format byte  |
+               +----------------------+--------------------+
+               ~               Encoded packet              ~
+               +----------------------+--------------------+
+               |        H_DLE         |End of framed packet|
+               +----------------------+--------------------+
+
+
+                            Table of packet formats
+
+           +----+---------+-----+--------------------------------+
+           |Name|Character|ASCII|Description                     |
+           +----+---------+-----+--------------------------------+
+           |END |   'a'   |  97 |End of framed packet            |
+           |BIN |   'b'   |  98 |Binary packet                   |
+           |HEX |   'c'   |  99 |Hex encoded packet              |
+           |ASC |   'd'   | 100 |Shifted 7-bit encoded packet (1)|
+           |UUE |   'e'   | 101 |UUencoded packet             (1)|
+           +----+---------+-----+--------------------------------+
+
+    (1) Support for ASC and/or UUE formats is optional and indicated in
+        the INIT state of a HYDRA session.
+
+
+    Packet sender and receiver state charts
+    ---------------------------------------------------------------------
+
+TXPKT (Sender)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|Begin   |1|pkttype == START or         |format = HEXPKT           |Format    |
+|        | |pkttype == INIT or          |                          |          |
+|        | |pkttype == INITACK or       |                          |          |
+|        | |pkttype == END or           |                          |          |
+|        | |pkttype == IDLE             |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Escape 8th bit (7 bit link) |                          |Coding    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (no spc.pkt, 8bit link)|format = BINPKT           |Format    |
++--------+-+----------------------------+--------------------------+----------+
+|Coding  |1|escape all control chars &  |format = UUEPKT           |Format    |
+|        | |UUENCODED packets allowed   |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|ASCII packets allowed       |format = ASCPKT           |Format    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|7 bit link &                |format = HEXPKT           |Format    |
+|        | |escape all control chars &  |                          |          |
+|        | |UUE/ASC pkts not allowed    |                          |          |
++--------+-+----------------------------+--------------------------+----------+
+|Format  |                              |Append format byte to data|CRC       |
++--------+-+----------------------------+--------------------------+----------+
+|CRC     |1|format != HEXPKT &          |Calc CRC-32 (data,pkttype)|Encode    |
+|        | |CRC-32 allowed              |Append one's complement of|          |
+|        | |                            |CRC to data, lowbyte first|          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (HEXPKT or no CRC-32)  |Calc CRC-16 (data,pkttype)|Encode    |
+|        | |                            |Append one's complement of|          |
+|        | |                            |CRC to data, lowbyte first|          |
++--------+-+----------------------------+--------------------------+----------+
+|Encode  |1|format == BINPKT            |BIN escape databuf        |Prefix    |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|format == HEXPKT            |HEX encode databuf        |Prefix    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|format == ASCPKT            |ASC encode/escape databuf |Prefix    |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|format == UUEPKT            |UUE encode databuf        |Prefix    |
++--------+-+----------------------------+--------------------------+----------+
+|Prefix  |1|No more prefix characters   |                          |Transmit  |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Prefix character ASCII 221  |Send 1 second break signal|          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Prefix character ASCII 222  |1 second delay            |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|Prefix character ASCII 223  |Transmit NUL (ASCII 0)    |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|else (any other character)  |Transmit character        |          |
++--------+-+----------------------------+--------------------------+----------+
+|Transmit|                              |Transmit H_DLE,format byte|Suffix    |
+|        |                              |Transmit encoded buffer   |          |
+|        |                              |Transmit H_DLE,pktend byte|          |
++--------+-+----------------------------+--------------------------+----------+
+|Suffix  |1|pkttype != DATA &           |Transmit CR,LF (ASC 13,10)|Done      |
+|        | |pktformat != BINPKT         |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (pkttype == DATA or    |                          |Done      |
+|        | |      pktformat == BINPKT)  |                          |          |
++--------+-+----------------------------+--------------------------+----------+
+
+
+RXPKT (Receiver)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Reset   |                              |rxdle = 0                 |NextByte  |
+|        |                              |format = 0                |          |
+|        |                              |pktlen = 0                |          |
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|User wishes to abort session|Report reason for abort   |Abort     |
+|        | |or carrier lost             |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Byte available in inputbuf  |                          |StripIn   |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|braintimer expired          |Report braindead situation|Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|Any other timer expired     |Tell responsible party    |          |
++--------+-+----------------------------+--------------------------+----------+
+|StripIn |1|Escape 8th bit (7 bit link) |c = c AND 0x7f (strip 8th)|StripC    |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (8 bit link)           |                          |StripC    |
++--------+-+----------------------------+--------------------------+----------+
+|StripC  |1|Escape ctlchars with 8th set|n = c AND 0x7f (strip 8th)|Process   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (let 8 bit ctl through)|n = c                     |Process   |
++--------+-+----------------------------+--------------------------+----------+
+|Process |1|c == H_DLE                  |increment rxdle           |DLE       |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Escape XON/XOFF &           |Eat these                 |NextByte  |
+|        | |n == XON or n == XOFF       |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Escape all control chars &  |Eat these                 |NextByte  |
+|        | |n < 32 or n == 127          |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxdle > 0                   |                          |Escape    |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|else (no eating or escaping)|                          |Store     |
++--------+-+----------------------------+--------------------------+----------+
+|DLE     |1|rxdle == 5                  |Report remote wants abort |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (rxdle < 5)            |                          |NextByte  |
++--------+-+----------------------------+--------------------------+----------+
+|Escape  |1|c == PKTEND                 |                          |PktEnd    |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|c == BINPKT                 |format = BINPKT           |PktStart  |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|c == HEXPKT                 |format = HEXPKT           |PktStart  |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|c == ASCPKT                 |format = ASCPKT           |PktStart  |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|c == UUEPKT                 |format = UUEPKT           |PktStart  |
+|        +-+----------------------------+--------------------------+----------+
+|        |6|else (normal escaped char)  |c = c XOR 0x40            |Store     |
+|        | |                            |rxdle = 0                 |Store     |
++--------+-+----------------------------+--------------------------+----------+
+|Store   |1|format == 0                 |Garbage                   |NextByte  |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|pktlen >= maximum           |Pkt too long / lost PKTEND|Reset     |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (fmt > 0 & len < max)  |Append c to databuffer    |NextByte  |
+|        | |                            |increment pktlen          |          |
++--------+-+----------------------------+--------------------------+----------+
+|PktStart|                              |rxdle = 0                 |NextByte  |
+|        |                              |pktlen = 0                |          |
++--------+-+----------------------------+--------------------------+----------+
+|PktEnd  |1|format == 0                 |End without start, garbage|Reset     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|format == BINPKT            |(No more decoding needed) |CalcCRC   |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|format == HEXPKT            |ok = Decode HEXPKT        |CheckDec  |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|format == ASCPKT            |ok = Decode ASCPKT        |CheckDec  |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|format == UUEPKT            |ok = Decode UUEPKT        |CheckDec  |
++--------+-+----------------------------+--------------------------+----------+
+|CheckDec|1|ok (no errors during decode)|                          |CalcCRC   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (errors in decoding)   |Bad encoding, ignore pkt  |Reset     |
++--------+-+----------------------------+--------------------------+----------+
+|CalcCRC |1|format != HEXPKT &          |Calc CRC-32 over databuf  |CheckCRC  |
+|        | |CRC-32 allowed              |ok = (crc == 0xdebb20e3)  |          |
+|        | |                            |pktlen = pktlen - 4       |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (HEXPKT or no CRC-32)  |Calc CRC-16 over databuf  |CheckCRC  |
+|        | |                            |ok = (crc == 0xf0b8)      |          |
+|        | |                            |pktlen = pktlen - 2       |          |
++--------+-+----------------------------+--------------------------+----------+
+|CheckCRC|1|ok (CRC matched magic)      |pkttype = last byte of buf|Reset     |
+|        | |                            |pktlen = pktlen - 1       |          |
+|        | |                            |Hand pkt to higher level  |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (CRC check failed)     |Bad CRC, ignore packet    |Reset     |
++--------+-+----------------------------+--------------------------+----------+
+
+
+
+    BIN packet format
+    ---------------------------------------------------------------------
+    The binary packet format require an 8-bit data channel. If requested
+    by either side, one or more sets of control characters are escaped.
+    In this case, when one of these characters appears in an unframed
+    packet, a H_DLE is sent followed by the character XOR 0x40. The H_DLE
+    character itself is always transmitted in this fashion. On the
+    receiver side, if the character after a H_DLE is not one of the
+    packet format bytes, this character is decoded using XOR 0x40 again.
+
+
+BINPKT Escaping
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |txlastc = 0               |NextByte  |
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Escape ctlchars with 8th set|n = c AND 0x7f (strip 8th)|Escape    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (let 8 bit ctl through)|n = c                     |Escape    |
++--------+-+----------------------------+--------------------------+----------+
+|Escape  |1|n == H_DLE                  |Output H_DLE              |Output    |
+|        | |                            |c = c XOR 0x40            |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Escape XON/XOFF &           |Output H_DLE              |Output    |
+|        | |n == XON or n == XOFF       |c = c XOR 0x40            |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Escape Telenet &            |Output H_DLE              |Output    |
+|        | |n == CR &                   |c = c XOR 0x40            |          |
+|        | |txlasc == '@'               |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|Escape all control chars &  |Output H_DLE              |Output    |
+|        | |n < 32 or n == 127          |c = c XOR 0x40            |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|else (any other character)  |                          |Output    |
++--------+-+----------------------------+--------------------------+----------+
+|Output  |                              |Store c                   |NextByte  |
+|        |                              |txlastc = c               |          |
++--------+------------------------------+--------------------------+----------+
+
+
+
+    HEX packet format
+    ---------------------------------------------------------------------
+    Supported by all implementations, this packet format is used in
+    worst-case situations and upon startup of a session when it is not
+    yet known what restrictions the line and the other side will place on
+    the link.
+
+    Packet types always transmitted in HEX format are: START, INIT,
+    INITACK, IDLE, END.
+
+    HEX format packets always use a 16-bit CRC.
+
+    HEX packets assume a 7-bit link, escaping all control characters and
+    filtering all control characters upon receipt.
+
+    ASCII characters in the range 128-255 (high bit set) are encoded by
+    first transmitting a backslash ('\') character (ASCII 92), followed
+    by the character in two lowercase hex-digits (bits 4-7 in first
+    digit, bits 0-3 in second).
+
+    Uppercase hex-digits are not permitted.
+
+    The backslash character itself is transmitted as two backslashes.
+
+    ASCII characters in the range 0-31 and 127 (all control characters)
+    are escaped with H_DLE in the same fashion as in binary (BIN)
+    packets.
+
+    Decoded  byte 1
+            +------+
+            76543210
+            +--++--+
+    Encoded  h1  h2
+
+
+HEXPKT Encoding/Escaping
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|High bit of c set           |Output \ (backslash)      |          |
+|        | |                            |Output hexdigit(c bit 4-7)|          |
+|        | |                            |Output hexdigit(c bit 0-3)|          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|c < 32 or c == 127          |Output H_DLE              |          |
+|        | |                            |Output (c XOR 0x40)       |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|c == \ (backslash)          |Output \ (backslash)      |          |
+|        | |                            |Output \ (backslash)      |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|else (any other character)  |Output c                  |          |
++--------+-+----------------------------+--------------------------+----------+
+
+
+HEXPKT Decoding
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Done OK   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|c == \ (backslash)          |                          |Escape    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (any other character)  |Output c                  |Escape    |
++--------+-+----------------------------+--------------------------+----------+
+|Escape  |1|No more bytes to process    |Premature end of data     |Error     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|c == \ (backslash)          |Output \ (backslash)      |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|c == lowercase hexdigit     |Save c, move ptr to next  |NextHex   |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|else (all other characters) |Invalid character         |Error     |
++--------+-+----------------------------+--------------------------+----------+
+|NextHex |1|No more bytes to process    |Premature end of data     |Error     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|c == lowercase hexdigit     |Output (1st << 4 OR 2nd)  |NextByte  |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (all other characters) |Invalid character         |Error     |
++--------+-+----------------------------+--------------------------+----------+
+
+
+    ASC packet format
+    ---------------------------------------------------------------------
+    Support of this packet format is optional and signalled in the INIT
+    packet with the ASC flag in the "Supported options" field. 8-bit data
+    is transformed into 7-bit data by a simple shift operation. Each byte
+    is inserted at the top of a shift register, the lower seven bits are
+    moved out. So seven 8-bit bytes are encoded into eight 7-bit
+    characters.
+
+    The end of the packet is padded by a maximum of six bits of 0 to make
+    the number of bits a multiple of seven and thereby creating
+    complete characters (so the receiver stops decoding when there are
+    less than seven bits left). The output can contain control
+    characters, so if escaping of these characters is required, this is
+    done as in BIN packets using the H_DLE method.
+
+
+    Decoded  byte 7  byte 6  byte 5  byte 4  byte 3  byte 2  byte 1
+            +------++------++------++------++------++------++------+
+            76543210765432107654321076543210765432107654321076543210
+            +-----++-----++-----++-----++-----++-----++-----++-----+
+    Encoded   c8     c7      c6    c5     c4     c3     c2     c1
+
+
+ASCPKT Encoding/Escaping
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Reset   |                              |n = 0 (16 bit wide!)      |NextByte  |
+|        |                              |bitshift = 0              |          |
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Flush     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (more bytes to process)|n = n OR (c << bitshift)  |Shift     |
+|        | |                            |BINPKT escape (n & 0x7f)  |          |
+|        | |                            |n = n >> 7                |          |
+|        | |                            |increment bitshift        |          |
++--------+-+----------------------------+--------------------------+----------+
+|Shift   |1|bitshift == 7               |BINPKT escape (n & 0x7f)  |Reset     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (bitshift < 7)         |                          |NextByte  |
++--------+-+----------------------------+--------------------------+----------+
+|Flush   |1|bitshift > 0                |BINPKT escape (n & 0x7f)  |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (bitshift == 0)        |                          |Done      |
++--------+-+----------------------------+--------------------------+----------+
+
+ASCPKT Decoding
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |n = 0 (16 bit wide!)      |NextByte  |
+|        |                              |bitshift = 0              |          |
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Done OK   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (more bytes to process)|c = c AND 0x7f            |Shift     |
+|        | |                            |n = n OR (c << bitshift)  |          |
+|        | |                            |bitshift = bitshift + 7   |          |
++--------+-+----------------------------+--------------------------+----------+
+|Shift   |1|bitshift >= 8               |Output (n AND 0xff)       |NextByte  |
+|        | |                            |n = n >> 8                |          |
+|        | |                            |bitshift = bitshift - 8   |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (bitshift < 8)         |                          |NextByte  |
++--------+-+----------------------------+--------------------------+----------+
+
+
+
+    UUE packet format
+    ---------------------------------------------------------------------
+    Support of this packet format is optional and signalled in the INIT
+    packet with the UUE flag in the "Supported options" field. The 8-bit
+    data is transformed into printable ASCII using the UUENCODE
+    algorithm. Three 8-bit bytes are encoded into four printable ASCII
+    characters. This done by taking the bottom six bits left and adding
+    '!' (ASCII 33) to move this character value into printable ASCII
+    range.
+
+    The end of the packet is padded by a maximum of five bits of 0 to
+    make the number of bits a multiple of six and thereby creating 
+    complete characters (so the receiver stops decoding when there are
+    less than six bits left). The output of this coding scheme does not
+    need any further escaping before transmission.
+
+    Decoded  byte 3  byte 2  byte 1
+            +------++------++------+
+            765432107654321076543210
+            +----++----++----++----+
+    Encoded   c4    c3    c2    c1
+
+
+UUEPKT Encoding
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|Less than three bytes left  |                          |Flush     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (three or more left)   |UUE(in[0]>>2)             |          |
+|        | |                            |UUE(in[0]<<4 OR in[1]>>4) |          |
+|        | |                            |UUE(in[1]<<2 OR in[2]>>6) |          |
+|        | |                            |UUE(in[2])                |          |
+|        | |                            |(UUE: (c AND 0x3f) + '!') |          |
++--------+-+----------------------------+--------------------------+----------+
+|Flush   |1|No more bytes left          |                          |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|One byte left               |UUE(in[0]>>2)             |Done      |
+|        | |                            |UUE(in[0]<<4)             |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Two bytes left              |UUE(in[0]>>2)             |Done      |
+|        | |                            |UUE(in[0]<<4 OR in[1]>>4) |          |
+|        | |                            |UUE(in[1]<<2)             |          |
++--------+-+----------------------------+--------------------------+----------+
+
+UUEPKT Decoding
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|Less than four bytes left   |                          |Flush     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (four or more left) &  |UD(i[0])<<2 OR UD(i[1])>>4|          |
+|        | |(c AND 0x7f) is in UUE range|UD(i[1])<<4 OR UD(i[2])>>2|          |
+|        | |                            |UD(i[2])<<6 OR UD(i[3])   |          |
+|        | |                            |(UD: (c - '!') AND 0x3f)  |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (all other characters) |Invalid character(s)      |Error     |
++--------+-+----------------------------+--------------------------+----------+
+|Flush   |1|No bytes left or            |                          |Done OK   |
+|        | |Less than two bytes left    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Two bytes left &            |UD(i[0])<<2 OR UD(i[1])>>4|Done OK   |
+|        | |(c AND 0x7f) is in UUE range|                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Three bytes left &          |UD(i[0])<<2 OR UD(i[1])>>4|Done OK   |
+|        | |(c AND 0x7f) is in UUE range|UD(i[1])<<4 OR UD(i[2])>>2|          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|else (all other characters) |Invalid character(s)      |Error     |
++--------+-+----------------------------+--------------------------+----------+
+
+
+
+    START packet                                             (HEX format)
+    ---------------------------------------------------------------------
+    This packet is sent to tell the remote to initiate a HYDRA session.
+
+    The complete framed packet as transmitted looks like:
+
+        ASCII values   24    99  65  92 102  53  92  97  51    24    97
+                    +-------+---+---+---+---+---+---+---+---+-------+---+
+        Characters  | H_DLE | c | A | \ | f | 5 | \ | a | 3 | H_DLE | a |
+                    +-------+---+---+---+---+---+---+---+---+-------+---+
+
+    Applications may scan for this sequence to automatically start HYDRA
+    when the remote transmits this packet (AutoStart). Prior to the START
+    packet, a special string is transmitted to enable remote starting
+    from a command prompt, hydra (the word hydra in lowercase):
+
+        ASCII values 104 121 100 114  97  13
+                    +---+---+---+---+---+----+
+        Characters  | h | y | d | r | a | CR |
+                    +---+---+---+---+---+----+
+
+    The special string combined with the START packet is transmitted at
+    five second intervals until either a START or INIT packet is received
+    from the remote, or the maximum number of retries is reached. Any
+    other packet types received in this stage must be ignored as they
+    could be remains of a previous session.
+
+
+    INIT packet                                              (HEX format)
+    ---------------------------------------------------------------------
+    The INIT packet contains file transfer session options. The remote
+    acknowledges this packet by returning an INITACK packet.
+
+
+                              INIT packet data
+
+                 +---------------------------------------+
+                 ~ Application ID string, NUL terminated ~
+                 +---------------------------------------+
+                 ~ Supported options, NUL terminated     ~
+                 +---------------------------------------+
+                 ~ Desired options, NUL terminated       ~
+                 +---------------------------------------+
+                 | Desired transmitter window size or 0  |
+                 +---------------------------------------+
+                 | Desired receiver window size or 0     |
+                 +---------------------------------------+
+                 ~ Other general options, NUL terminated ~
+                 +---------------------------------------+
+                 ~ Packet prefix string, NUL terminated  ~
+                 +---------------------------------------+
+
+    The application ID string contains a printable ASCII string with the
+    document revision date, product name, product revision number, and
+    optionally the product serial number. The format of the string is:
+
+        <,>[<,>]
+
+    RevDate is the UNIX timestamp (the hour, minute, and second portion
+    is assumed to be zero), in hexadecimal notation, of the HYDRA
+    document that the application is supposed to support. None of the
+    following three fields should exceed thirty characters in length and
+    must not contain any control characters (ASCII 0-31) or the comma
+    character (ASCII 44). The field separator is a comma (ASCII 44)
+    character.
+
+    Capability flags
+
+        XON        Escape  and  characters.
+        TLN        Escape the @ sequence (Telenet escape).
+        CTL        Escape ASCII characters 0-31 and 127.
+        HIC        Escape above three with high bit set.
+        HI8        Escape ASCII characters 128-255 and strip the high bit.
+        BRK        Can transmit a break signal.
+        ASC        Can handle ASC packets.
+        UUE        Can handle UUE packets.
+        C32        Can receive packets with 32-bit CRC error detection.
+        DEV        Can receive device packets.
+        FPT        Can receive filenames with paths.
+
+    Capability flags are always three characters long, in uppercase, and
+    seperated by a comma character (ASCII 44). Please note that the first
+    five flags must be supported by all applications that implement the
+    HYDRA specifications.
+
+    The "Supported options" string contain the capability flags of the
+    options that the application support. The "Desired options" string
+    contain the capability flags of the options that the application
+    would like to use/enable for the session. Some flags do not have to
+    be specified in both strings. E.g. if the C32 flag is present in the
+    "Supported options" string and the remote system indicates support
+    for the same flag, 32-bit CRC error detection will be used. An
+    application may not ask for an option it does not support.
+
+    Escaping certain characters or bits also means filtering any
+    occurrence of them in the incoming data stream. At the start of a
+    session, it is assumed that the first five capability flags are in
+    effect, i.e. the high bit is stripped off every received character
+    and all control characters are filtered out.
+
+    The "Desired transmitter/receiver window size" fields are long
+    integers expressed in hexadecimal notation. With these options each
+    side tells the other to use window management of the requested size
+    when transmitting file data, instead of using full streaming (0).
+    The window setting is completely seperate for both directions.
+    If one side requests a smaller window size than the other, that
+    smaller size will be used for that direction; also, a window of any
+    size takes precedence over no window (0).
+    Please note that the terms 'transmitter' and 'receiver' used for the
+    fields in the INIT packet are from the view of the side transmitting
+    that packet, so the other side should merge the 'transmitter' window
+    field from the received INIT packet with its own 'receiver' window
+    field.
+
+    The "General options" string currently has no other fields than
+    "Desired tx/rx window size"; the string is NUL terminated.
+
+    The packet prefix string is normally empty, but may be provided by
+    the remote if required. The maximum length of a packet prefix string
+    is 30 characters. All characters should be transmitted as specified,
+    with the following exceptions:
+
+    
+                Table of special packet prefix string chars
+
+               +-----+--------------------------------------+
+               |ASCII|Description                           |
+               +-----+--------------------------------------+
+               | 221 |Transmit a break signal for one second|
+               | 222 |Delay one second before next character|
+               | 223 |Transmit a NUL (ASCII 0) character    |
+               +-----+--------------------------------------+
+
+
+    INITACK packet                                           (HEX format)
+    ---------------------------------------------------------------------
+    The INITACK packet is used to acknowledge the receipt of the remote's
+    INIT packet.
+
+    Duplicate INIT packets should be acknowledged too, as the remote may
+    have missed previous INITACK packets; the reception of such a
+    duplicate packet should not however reset the braindead timer, as it
+    does not mean a change of state and is not actual file data.
+
+
+    FINFO packet
+    ---------------------------------------------------------------------
+    File information packet, sent to notify the remote that another file
+    is to be transmitted, or to signal end of batch. After the FINFO
+    packet has been transmitted, the timer is set to the normal timeout
+    value. The sender then waits for an FINFOACK packet from the remote
+    or for the timer to expire. In the event of a timeout, the transmit/
+    wait sequence is repeated with half the normal timeout value until
+    the maximum number of retries has been reached.
+
+
+                              FINFO packet data
+                   +-------------------------------------+
+                   ~ File information, NUL terminated    ~
+                   +-------------------------------------+
+
+
+                   File information        End of batch
+                  +-----------------+   +-----------------+
+                  | Timestamp or 0  |   |       NUL       | 
+                  +-----------------+   +-----------------+ 
+                  | Filesize or 0   |
+                  +-----------------+
+                  | Reserved (0)    |
+                  +-----------------+
+                  | Transaction #   |
+                  +-----------------+
+                  | File count or 0 |
+                  +-----------------+
+                  ~ Short filename  ~
+                  +-----------------+
+                  ~ Real filename   ~
+                  +-----------------+
+                  |     NUL         |
+                  +-----------------+
+                     
+    End of batch is signalled by an empty string (only the terminating
+    NUL).
+
+    The first five fields are long integers expressed in hexadecimal
+    notation.
+
+    Timestamp is a UNIX timestamp representing the creation time of the
+    file. If the creation time is not known, this is zero.
+
+    Filesize is the size of the file in bytes. If the size of the file is
+    not known, this is zero. This field should not be used as an exact
+    measure of the size of the file. It is safe to assume that you should
+    not receive less data than specified in this field, but the file may
+    grow while it is being transferred (e.g. the result of a background
+    process).
+
+    Transaction # is a unique number for each set of files being sent
+    during the session. This is primarily used to allow the receiving
+    application to group several files together and store them in
+    specific directories as a result of automated file requests. If the
+    file being sent is not a result of an automated file request, this
+    field must be set to zero.
+
+    File count is the session file counter. For the first file in a
+    session, this field contains the total number of files to be sent
+    during the session; for subsequent files, it contains the file number
+    in the session, starting with two (2). If the total number of files
+    is not known, this field contains zero for all files.
+
+    The first filename field must be specified in lowercase characters.
+    It must conform to MS-DOS filename conventions and not exceed 12
+    characters in length (excluding the terminating NUL character). The
+    second field, real filename, is the actual filename on the sending
+    system. If this field is not present, the short filename field is
+    used.
+
+    No directory paths may be specified in the short filename. Directory
+    paths may be specified in the real filename field if the "Desired
+    options" of the receiver contains FPT. If the real filename field
+    contains a path, it may include any ASCII character in the range 32
+    (0x20) through 255 (0xff) with \ characters translated to /. A drive
+    specifier may be present in the : (e.g. c:) format. If both
+    the short and real filename fields are present, they are separated
+    by a NUL character. There is never more than one NUL character
+    terminating the packet.
+    
+
+    FINFOACK packet
+    ---------------------------------------------------------------------
+    Sent in response to an FINFO packet. If the FINFO packet contained
+    file information, the FINFOACK packet is also used to instruct the
+    remote how to proceed with the transfer.
+
+
+                            FINFOACK packet data
+                 +---------------------------------------+
+                 | Long file offset, special code, or 0  |
+                 +---------------------------------------+
+
+    The only data in this packet is a long integer. In response to an
+    an end of batch FINFO packet, the file offset is set to zero (0). In
+    all other cases, file offset is one of the following:
+
+
+                       File offsets and special values
+           +------+----------------------------------------------+
+           |Offset|Description                                   |
+           +------+----------------------------------------------+
+           | >=0  |Seek to specified offset and start sending (1)|
+           |  -1  |Already have file                          (2)|
+           |  -2  |Send file during another batch (not now)      |
+           +------+----------------------------------------------+
+
+    (1) This can only be something other than zero if the FINFO packet
+        specified a filesize other than zero (i.e. the size of the file
+        is known to the receiver).
+
+    (2) The sending application should consider the file as having been
+        sent successfully. This is primarily used to prevent duplicate
+        files from being transmitted.
+
+
+    DATA packet
+    ---------------------------------------------------------------------
+    Packet containing actual file data.
+
+
+                                  DATA packet
+                  +-----------------------------------------+
+                  | Long file offset of file data block     |
+                  +-----------------------------------------+
+                  ~ Variable length data block 0-2048 bytes ~
+                  +-----------------------------------------+
+
+    If the file offset corresponds with what is expected by the receiver,
+    the data block is saved and the file position increased accordingly.
+    If the file offset is not correct, DATA packets may have been lost or
+    failed the CRC check. Bad packets are ignored because it is not
+    certain that the bad packet was an actual DATA packet and not some
+    other type of packet. The file offset comparison is therefore the
+    only way to find out about lost or bad data.
+
+    When a bad data packet is detected, an RPOS packet is transmitted by
+    the receiver to force the sender to seek to the desired file offset
+    and resume transmission from it. After transmitting the RPOS packet,
+    the receiver initializes a timer and continues to monitor received
+    DATA packets while comparing their file offset with its desired
+    offset.
+
+    If the offset of a newly received DATA packet is greater than the
+    offset received in the last DATA packet prior to transmitting the
+    RPOS packet, the sender has not yet seen the RPOS packet, or the
+    DATA packet was already in the data stream when the RPOS packet was
+    transmitted.
+
+    If the received offset matches the requested offset, the transfer is
+    resumed, otherwise, a new RPOS packet is transmitted by the receiver
+    and the timer restarted.
+
+    If the timer expires, another RPOS packet is transmitted by the
+    receiver. This is repeated until the maximum number of retries has
+    been reached.
+
+    If the receiver encounters more missing or invalid DATA packets at
+    the same offset than it finds acceptable and it is not the originator
+    of the session, it may decide to revert to a one-way transfer and
+    wait with sending the remainder of its own files until the remote has
+    transmitted its end of batch signal. It is possible that some hard-
+    ware is not capable or well suited for a bi-directional file transfer
+    involving large volumes of data (see description of the IDLE packet).
+
+
+    DATAACK packet
+    ---------------------------------------------------------------------
+    Transmitted by the receiver with its current file offset after
+    receiving a valid DATA packet.
+
+
+                              DATAACK packet data
+                          +------------------------+
+                          |    Long file offset    |
+                          +------------------------+
+
+    This packet is only transmitted if there is a window in operation
+    for that direction (selected in the INIT stage of the session), in
+    which case the sender uses the DATAACK file offsets to manage its
+    transmit window. If the sender's file offset is greater than or equal
+    to the last DATAACK offset received plus the window size, no more
+    data is transmitted by the sender until a DATAACK packet is received
+    which allows the sender to proceed without exceeding the window size.
+
+    While waiting for the DATAACK packet, the sender checks its timer
+    and retry counter. If the timer expires before a valid DATAACK packet
+    is received, the next DATA packet is transmitted, the retry counter
+    incremented, and the timer restarted with half the normal timeout.
+    This system ensures that the two sides do not end up waiting for
+    each other in case packets are lost; the receiver will respond with
+    either a DATAACK or RPOS packet. Receipt of a DATAACK packet does not
+    reset the braindead timer.
+
+    There are two windowing systems the receiver can use: sliding window
+    or segmented streaming.
+
+    If the receiver is capable of simultaneous serial and disk I/O, it
+    will transmit a DATAACK packet for every received DATA packet, or
+    every few DATA packets if it wants to be more economical with line
+    capacity.
+    Sliding window transmission is just a method of keeping the runahaid
+    of the transmitter within reasonable limits (for sattelite or network
+    links with long delays), thereby allowing for faster error recovery.
+    Because of Hydra's tolerancy to delays and method of error recovery,
+    sliding windows transmission is not normally required and full
+    streaming can be used.
+
+    If however the receiver is not capable of simultaneous serial and
+    disk I/O, it will will process received DATA packets until the window
+    size is reached (or slightly exceeded), write the received packets to
+    disk, and then transmit one DATAACK packet to signal that it can
+    receive the next segment of data.
+
+    If the sender cannot handle simultaneous serial and disk I/O, it can
+    apply the segmented streaming technique for reading data segments of
+    the negotiated window size from disk.
+
+
+    RPOS packet
+    ---------------------------------------------------------------------
+    Transmitted by the receiver to force the sender to seek to a specific
+    position in the file and resume the transfer (as described above).
+
+    The RPOS packet is also used by the receiver to skip a file once the
+    transfer has been initiated. This is done by transmitting a RPOS
+    packet with -2 as the desired offset and then waiting for a EOF
+    packet with the same offset (-2). Once the EOF packet is received,
+    the receiver responds to it by transmitting a EOFACK packet and then
+    proceeds to wait for the next FINFO packet.
+
+
+                          RPOS packet dependent data
+                  +----------------------------------------+
+                  | Long file offset                       |
+                  +----------------------------------------+
+                  | Desired datablock size (word, 64-2048) |
+                  +----------------------------------------+
+                  | Long RPOS packet ID                    |
+                  +----------------------------------------+
+
+
+                                 File offsets 
+             +------+-------------------------------------------+
+             |Offset|Description                                |
+             +------+-------------------------------------------+
+             | >=0  |Seek to specified offset and resume sending|
+             |  -2  |Send file during another batch (not now)   |
+             +------+-------------------------------------------+
+
+    The desired data blocksize field tells the sender what blocksize
+    to use when it resumes transmitting from the specified file offset.
+
+    Each new RPOS packet should be given a different packet ID. This
+    allows the sender to identify and ignore duplicate RPOS packets.
+    The ID need not be sequential, but it must not have the same value as
+    any other RPOS packet sent during the transmission of the same file.
+    A RPOS ID value of zero (0) is not permitted. The same ID value is
+    only used when sending multiple RPOS packets due to an expired RPOS
+    packet timer as described above (DATA packet).
+
+
+    EOF packet
+    ---------------------------------------------------------------------
+    Indicates that the end of the file has been reached by the sender.
+    The packet is transmitted after the last DATA packet with file data.
+    The EOF packet only contains one field which holds the current file
+    offset of the sender (i.e. the actual size of the file).
+
+    After the EOF packet has been transmitted, the timer is set to the
+    normal timeout value. The sender then waits for an EOFACK packet
+    from the remote or for the timer to expire. In the event of a
+    timeout, the transmit/wait sequence is repeated with half the normal
+    timeout value until the maximum number of retries has been reached.
+
+    In the event that the receiver requests to skip the file by
+    transmitting a RPOS(-2) packet (see RPOS packet), the EOF packet
+    contains the same value (-2). If the sender wants to skip the file
+    currently being transmitted, it issues an EOF packet with -2 as the
+    offset value.
+
+    EOF packets with an incorrect offset should be treated by the
+    receiver as if it was an incorrect DATA packet (i.e. transmitting an
+    RPOS packet). Accepted EOF packets are acknowledged by transmitting
+    an EOFACK packet.
+
+
+                                EOF packet data
+                     +----------------------------------+
+                     | Long file offset or special code |
+                     +----------------------------------+
+
+
+                         File offsets and special value
+               +------+----------------------------------------+
+               |Offset|Description                             |
+               +------+----------------------------------------+
+               | >=0  |Final offset in file (size of file)     |
+               |  -2  |Send file during another batch (not now)|
+               +------+----------------------------------------+
+
+
+    EOFACK packet
+    ---------------------------------------------------------------------
+    Transmitted in response to an accepted EOF packet. After transmitting
+    this packet, the receiver waits for the FINFO packet of the next file
+    or end of batch.
+
+
+    END packet                                               (HEX format)
+    ---------------------------------------------------------------------
+    Once all files have been transmitted by both sides and no device
+    packets remain to be transmitted, the end of session sequence is
+    initiated. END packets are always sent in HEX format.
+
+    Two END packets are transmitted and the transmit timer set to half
+    the normal timeout. The application then waits for an END packet from
+    the remote or for the transmit timer to expire. In the event of a
+    timeout, the transmit/wait sequence is repeated until the maximum
+    number of retries has been reached. At this point, the HYDRA session
+    may be considered to be successful as both batches were completed.
+
+    If an END packet is received before timeout, another three (3) END
+    packets are transmitted and the protocol exits. Both sides need to
+    transmit END packets and receive at least one from the remote.
+
+
+    IDLE packet                                              (HEX format)
+    ---------------------------------------------------------------------
+    The IDLE packet is used to let the remote know that the application
+    is still alive. This is only applicable in uni-directional transfer
+    mode to let the remote know that your application is still alive when
+    it is receiving files, and after having transmitted an end of batch
+    signal to the remote and not having any more files to send for the
+    remainder of the session.
+
+    When applicable, the IDLE packet is transmitted every 20 seconds. The
+    remote resets its braindead timer upon receipt of an IDLE packet. If
+    an application receives an IDLE packet while it is in a state where
+    it is transmitting IDLE packets to the remote, something is wrong.
+    This could occur if both sides have accidentally switched to one-way
+    mode waiting for the remote to finish its batch. In this situation,
+    one-way should be disabled to prevent a complete deadlock. Note that
+    if both sides have finished their batch, the end of session sequence
+    (see END packet) should be initiated.
+
+
+    DEVDATA packet
+    ---------------------------------------------------------------------
+    Support for the DEVDATA and DEVDACK packets is optional and indicated
+    in the INIT packet with the DEV flag in the "Supported options"
+    field. The ID value is a long, different for each new device data
+    packet sent. A value of zero (0) is not permitted.
+
+    Only one DEVDATA packet may be transmitted at a time; the side
+    issuing it then waits either for a timeout of the device transmit
+    timer, or for a DEVDACK packet with the correct ID value to be
+    received from the remote. If the timer expires before a correct
+    DEVDACK packet is received, the DEVDATA packet is again transmitted,
+    and the nnumber of device transmit retries incremented. If the
+    maximum number of retries is reached, the HYDRA session is aborted;
+    apparently the other is not functioning properly, or data is not
+    getting through. In either case, the normal operation of the
+    protocol (transferring files) will also fail.
+
+    The name of the device to which the data is addressed is transmitted
+    as an uppercase fixed-length three character NUL terminated string.
+    There are two pre-defined device names as described below. If an
+    unknown device name is specified, or a duplicate DEVDATA packet is
+    received (one with the same ID value as a previously received and
+    acknowledged DEVDATA packet), the packet is simply discarded after
+    transmitting a DEVDACK packet with the corresponding ID value.
+
+    DEVDATA and DEVDACK packets do not reset the braindead timer. They
+    operate independently from the normal protocol. Device packets may
+    only be transmitted after the initialization sequence, and before
+    both sides have completed their batch. If a DEVDATA packet has not
+    yet been acknowledged, the end of session sequence is delayed until
+    a DEVDACK packet has been sent in response.
+
+
+                       DEVDATA packet dependent data
+           +--------------------------------------------------+
+           | Long DEVDATA packet ID value                     |
+           +--------------------------------------------------+
+           | 3 character uppercase device name, NUL terminated|
+           +--------------------------------------------------+
+           ~ Variable length device data block (0-2048)       ~
+           +--------------------------------------------------+
+
+
+                           Predefined device names
+                +---+-------------------------------------+
+                |Dev|Description                          |
+                +---+-------------------------------------+
+                |MSG|Print data in protocol message window|
+                |CON|Print data to user console           |
+                +---+-------------------------------------+
+
+    The MSG device may be used to notify the remote of protocol-specific
+    issues, i.e. "One-way transfer mode". Such messages may be logged,
+    but should not be considered to be machine-readable.
+
+    The CON device may be used to implement a "chat" or conversation
+    feature. This is a special case in which a session *can* be prolonged
+    after end of batch, but not against the remote's will.
+    While chat is enabled, there is no transition from the REND to the
+    END transmitter state. When a CON device packet is transmitted in
+    chat mode and the txstate is REND, the own braindead timer is reset.
+    If the other side does initiate the end sequence by sending an END
+    packet, the chat mode is immediately terminated and the session ended
+    in a clean manner. If one side does not want to (continue) chat, and
+    the other side does not comply, the one side will abort after a
+    braindead timeout, so this chat system does not mean a security flaw.
+    Each side is responsible for keeping the session going on his end
+    until its own user has finished chatting. It is suggested that the
+    software apply a timeout of say 1 minute to keyboard input, ending
+    the chat automatically if the user stops typing but does not exit
+    chat mode. Also, the chat mode should be initiated with a special key
+    so that it can not erronously be started or prolonged.
+
+
+    DEVDACK packet
+    ---------------------------------------------------------------------
+    Transmitted in response to a DEVDATA packet. The device data ID value
+    must correspond to the ID of the previously received DEVDATA packet.
+
+
+                              DEVDACK packet data
+                         +---------------------------+
+                         | Long device data ID value |
+                         +---------------------------+
+
+
+
+DEVICE sender (devtxstate HTD_...)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |devtxid = 0               |DONE      |
+|        |                              |reset devtxtimer          |          |
++--------+-+----------------------------+--------------------------+----------+
+|DONE    |1|wish to send device data &  |increase devtxid          |DATA      |
+|        | |other side allows DEV pkts  |devtxretries = 0          |          |
+|        | |                            |reset devtxtimer          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|wish to send device data &  |Tell calling function     |          |
+|        | |other doesn't allow DEV pkts|it's not on...            |          |
++--------+-+----------------------------+--------------------------+----------+
+|DATA    |1|devtxretries == 10          |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (devtxretries < 10)    |txpkt DEVDATA(id,dev,data)|DACK      |
+|        | |                            |devtxtimer = timeout      |          |
++--------+-+----------------------------+--------------------------+----------+
+|DACK    |1|rxpkt DACK &                |reset devtxtimer          |DONE      |
+|        | |DACK(id) == devtxid         |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|devtxtimer expired          |Report devtx timeout      |DATA      |
+|        | |                            |increase devtxretries     |          |
++--------+-+----------------------------+--------------------------+----------+
+ 
+DEVICE RECEIVER
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |devrxid = 0               |DONE      |
++--------+-+----------------------------+--------------------------+----------+
+|DONE    |1|rxpkt DEVDATA               |txpkt DEVDACK(id)         |CheckID   |
++--------+-+----------------------------+--------------------------+----------+
+|CheckID |1|DEVDATA(id) != devrxid      |devrxid = DEVDATA(id)     |Process   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (apparent duplicate)   |                          |DONE      |
++--------+-+----------------------------+--------------------------+----------+
+|Process |1|DEVDATA(dev) == MSG         |Print protocol message    |DONE      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|DEVDATA(dev) == CON         |Output to user console    |DONE      |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|DEVDATA(dev) == known&ok    |Call processing routine   |DONE      |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|else (unknown/not-ok device)|One-way into bitbucket    |DONE      |
++--------+-+----------------------------+--------------------------+----------+
+
+ 
+    Packet length and data block size
+    ---------------------------------------------------------------------
+    The maximum length of a source data block (i.e. raw, non processed
+    input file or device data) is 2048 bytes. The maximum allowed length
+    of the packet data is 2048 + 8 = 2056 bytes. The eight bytes are to
+    provide sufficient room for the additional fields in the DATA and
+    DEVDATA packets. Packetizing adds an additional three to five bytes.
+    The maximum length of a framed packet being transmitted can be three
+    times the size of its source data depending on what type of encoding
+    scheme is used (ASC, HEX, UUE, BIN). The minimum length of a data
+    block is 64 bytes.
+
+    The block size of DATA packets is based on the physical (DCE) link
+    speed and is established as follows:
+
+            +---------+------------------+-------------------+
+            |DCE speed|Maximum block size|Starting block size|
+            +---------+------------------+-------------------+
+            |  300 bps|     256 bytes    |     256 bytes     |
+            | 1200 bps|     512 bytes    |     256 bytes     |
+            | 2400 bps|    1024 bytes    |     512 bytes     |
+            |>2400 bps|    2048 bytes    |     512 bytes     |
+            +---------+------------------+-------------------+
+
+    The blocksize is initialized to the starting blocksize when a session
+    is first started. After each kilobyte of file data transmitted, the
+    blocksize is doubled until it reaches the maximum allowed blocksize.
+
+    When the maximum allowed blocksize has been reached, the variable
+    keeping track of how many bytes are needed to increase the blocksize
+    is reset to zero.
+
+    If a request for retransmission (RPOS packet) is received from the
+    receiver, the blocksize is immediately set to that specified in the
+    retransmission request. Every time this occurs, the number of bytes
+    needed to double the blocksize is increased by 1024 with a maximum of
+    of 8192 bytes. The end result is that more data has to be
+    successfully transmitted before the blocksize is increased for each
+    error that occurs.
+
+    The length of a data block is dynamic and always in the range 0-2048
+    bytes. A data block is never padded. If there is insufficient data
+    to fill a block of the current blocksize, the blocksize is adjusted
+    to the amount of remaining data.
+
+    The blocksize logic is not reset between files in a session.
+
+
+    Timers and retry counters
+    =====================================================================
+    Each process in the protocol (transmit, receive and device transmit)
+    has its own timer and retry counter, and there is one overall
+    braindead timer. Allowed are 10 tries, the braindead timeout is 120
+    seconds, and the other timeouts are based on the speed of the line
+    and the state of the protocol. It can be calculated as (40960/DCE
+    rate), with a minimum of 10 seconds and a maximum of 60 seconds.
+
+                     +---------+----------+----------+
+                     |DCE speed|Timeout   |Half      |
+                     +---------+----------+----------+
+                     |  300 bps|60 seconds|30 seconds|
+                     | 1200 bps|34 seconds|17 seconds|
+                     | 2400 bps|17 seconds| 8 seconds|
+                     |>2400 bps|10 seconds| 5 seconds|
+                     +---------+----------+----------+
+
+    If the output buffer is empty, the timeout value is halved. In
+    general, this is the case if the number of tries is greater than zero
+    and during the init and end sequences. These timeouts are not fatal
+    situations, they just give the remote a reasonable amount of time to
+    receive and respond to a packet before a retry occurs. Duplicate
+    packets are always identified and ignored. A retry counter is reset
+    if there is a change of state, or a reposition different from the
+    previous file offset occurs.
+
+    The braindead timer monitors useful data from the other side: a first
+    response to a transmitted supervisiory packet, or a received packet
+    with file data at the correct offset. Device packets and packets that
+    do not signify any progress of the protocol do not affect the
+    braindead timer.
+
+    No other timers (such as one between characters in a packet) are
+    necessary.
+
+
+    Aborting a session
+    =====================================================================
+    A session is aborted with five consequetive CAN (^X or ASCII 24)
+    characters. Whenever a state table mentions "Abort", the following
+    procedure is to be followed:
+
+    Clear the output buffer and transmit eight CAN characters followed by
+    ten BS (^H or ASCII 8) characters; wait a few seconds for the data to
+    be transmitted to the remote, purge the input buffer and exit the
+    protocol code.
+
+
+GENERAL sender (txstate HTX_...)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |txretries = 0             |START     |
+|        |                              |reset txtimer             |          |
+|        |                              |blksize = startblksize    |          |
+|        |                              |goodbytes = 0             |          |
+|        |                              |goodneeded = 1024         |          |
+|        |                              |braintimer = 120          |          |
++--------+-+----------------------------+--------------------------+----------+
+|START   |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (txretries < 10)       |txstr AutoStart           |SWAIT     |
+|        | |                            |txpkt START               |          |
+|        | |                            |txtimer = 5               |          |
++--------+-+----------------------------+--------------------------+----------+
+|SWAIT   |1|rxpkt START or              |txretries = 0             |INIT      |
+|        | |rxpkt INIT                  |reset txtimer             |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txtimer expired             |Report tx timeout         |START     |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+|INIT    |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (txretries < 10)       |txpkt INIT(linkinfo)      |INITACK   |
+|        | |                            |txtimer = timeout/2       |          |
++--------+-+----------------------------+--------------------------+----------+
+|INITACK |1|rxpkt INITACK               |txretries = 0             |RINIT     |
+|        | |                            |reset txtimer             |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txtimer expired             |Report tx timeout         |INIT      |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+|RINIT   |1|rxstate != INIT             |                          |NextFile  |
++--------+-+----------------------------+--------------------------+----------+
+|NextFile|1|No files left?              |Report end of batch       |ToFName   |
+|        | |                            |Set NULL fileinfo         |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Can access next file?       |Set up fileinfo           |ToFName   |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Can't access file?          |Report access failure     |NextFile  |
++--------+-+----------------------------+--------------------------+----------+
+|ToFName |                              |txsyncid = 0              |FINFO     |
+|        |                              |txretries = 0             |          |
+|        |                              |reset txtimer             |          |
++--------+-+----------------------------+--------------------------+----------+
+|FINFO   |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txretries > 0               |txpkt FINFO(fileinfo)     |FINFOACK  |
+|        | |                            |txtimer = timeout/2       |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (txretries == 0)       |txpkt FINFO(fileinfo)     |FINFOACK  |
+|        | |                            |txtimer = timeout         |          |
++--------+-+----------------------------+--------------------------+----------+
+|FINFOACK|1|NULL fname (end of batch) & |txtimer = idletimeout     |REND      |
+|        | |rxpkt FINFOACK              |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt FINFOACK &            |txpos = FINFOACK(pos)     |DATA      |
+|        | |FINFOACK(pos) >= 0          |txretries = 0             |          |
+|        | |                            |txlastack = 0             |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt FINFOACK &            |They already have file    |NextFile  |
+|        | |FINFOACK(pos) == -1)        |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt FINFOACK &            |Skip this file for now    |NextFile  |
+|        | |FINFOACK(pos) == -2)        |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|txtimer expired             |Report tx timeout         |FINFO     |
+|        | |                            |inrease txretries         |          |
++--------+-+----------------------------+--------------------------+----------+
+|DATA    |1|rxstate != Done &           |txtimer = idletimeout     |XWAIT     |
+|        | |hdxlink == True             |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATAACK &             |txlastack = DATAACK(pos)  |          |
+|        | |DATAACK(pos) > txlastack    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt RPOS &                |Skip this file for now    |SkipFile  |
+|        | |RPOS(pos) < 0               |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt RPOS &                |Report too many errors    |Abort     |
+|        | |RPOS(id) == txsyncid &      |                          |          |
+|        | |inc txretries == 10         |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|rxpkt RPOS &                |txpos = RPOS(pos)         |          |
+|        | |RPOS(id) != txsyncid &      |txsyncid = RPOS(id)       |          |
+|        | |RPOS(pos) >= 0              |txretries = 1             |          |
+|        | |                            |blksize = RPOS(blksize)   |          |
+|        | |                            |goodbytes = 0             |          |
+|        | |                            |inc goodneeded + 1024     |          |
+|        | |                            |if (goodneeded > 8192)    |          |
+|        | |                            |   goodneeded = 8192      |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |6|File seek/read error or     |Skip this file for now    |SkipFile  |
+|        | |user wishes to skip file    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |7|txwindow &                  |if (txretries > 0)        |DATAACK   |
+|        | |txpos >= txlastack+txwindow |   txtimer = timeout/2    |          |
+|        | |                            |else                      |          |
+|        | |                            |   txtimer = timeout      |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |8|Enough room in output &     |txpkt DATA(pos,data)      |          |
+|        | |more filedata(blksize) to go|txpos += datalen          |          |
+|        | |                            |inc goodbytes + datalen   |          |
+|        | |                            |if goodbytes > goodneeded |          |
+|        | |                            |   Store txpos,blksize    |          |
+|        | |                            |   blksize * 2 (max.2048) |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |9|End of filedata reached     |                          |EOF       |
++--------+-+----------------------------+--------------------------+----------+
+|SkipFile|                              |txpos = -1                |EOF       |
+|        |                              |txretries = 0             |          |
++--------+-+----------------------------+--------------------------+----------+
+|DATAACK |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATAACK &             |txlastack = DATAACK(pos)  |DATA      |
+|        | |DATAACK(pos) > txlastack &  |txretries = 0             |          |
+|        | |txpos < DATAACK(pos) + txwin|reset txtimer             |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt RPOS                  |Handle RPOS in state DATA |          |
+|        | |                            |but stay in this state    |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|txtimer expired             |Report tx timeout         |DATA      |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+|XWAIT   |1|rxstate == Done             |reset txtimer             |DATA      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATAACK &             |txlastack = DATAACK(pos)  |          |
+|        | |DATAACK(pos) > txlastack    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt RPOS                  |Handle RPOS in state DATA |          |
+|        | |                            |but stay in this state    |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt IDLE                  |hdxlink = False           |DATA      |
+|        | |                            |reset txtimer             |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|txtimer expired             |txpkt IDLE                |          |
+|        | |                            |txtimer = idletimeout     |          |
++--------+-+----------------------------+--------------------------+----------+
+|EOF     |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txretries > 0               |txpkt EOF(txpos)          |EOFACK    |
+|        | |                            |txtimer = timeout/2       |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (txretries == 0)       |txpkt EOF(txpos)          |EOFACK    |
+|        | |                            |txtimer = timeout         |          |
++--------+-+----------------------------+--------------------------+----------+
+|EOFACK  |1|rxpkt EOFACK                |braintimer = 120          |NextFile  |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATAACK &             |txlastack = DATAACK(pos)  |          |
+|        | |DATAACK(pos) > txlastack    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt RPOS &                |rxpos == -2               |EOF       |
+|        | |RPOS(pos) == -2 &           |                          |          |
+|        | |rxpos != -2                 |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt RPOS &                |Handle as in state DATA   |DATA      |
+|        | |RPOS(pos) >= 0              |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|txtimer expired             |Report tx timeout         |EOF       |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+|REND    |1|rxstate == DONE &           |txretries = 0             |END       |
+|        | |devtxstate == DONE          |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txtimer expired             |txpkt IDLE                |          |
+|        | |                            |txtimer = idletimeout     |          |
++--------+-+----------------------------+--------------------------+----------+
+|END     |1|txretries == 10             |                          |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (txretries < 10)       |txpkt END (twice)         |ENDACK    |
+|        | |                            |txtimer = timeout/2       |          |
++--------+-+----------------------------+--------------------------+----------+
+|ENDACK  |1|rxpkt END                   |txpkt END (thrice)        |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txtimer expired             |Report tx timeout         |END       |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+
+ 
+ 
+GENERAL RECEIVER (rxstate HRX_...)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |reset rxtimer             |START     |
+|        |                              |lastrxdlen = startblksize |          |
+|        |                              |(tx handles braintimer)   |          |
++--------+-+----------------------------+--------------------------+----------+
+|INIT    |1|rxpkt INIT &                |txpkt INITACK             |FINFO     |
+|        | |INIT(options) are compatible|Set options               |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|INIT(options) not compatible|Report link failure       |Abort     |
++--------+-+----------------------------+--------------------------+----------+
+|FINFO   |1|rxpkt INIT (apparent dup)   |txpkt INITACK             |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt FINFO &               |Report end of batch       |          |
+|        | |FINFO(fileinfo) == Empty    |txpkt FINFOACK            |DONE      |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt FINFO &               |do not want this file     |          |
+|        | |we already have file        |txpkt FINFOACK(-1)        |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt FINFO &               |Skip this file for now    |          |
+|        | |open/diskspace error        |txpkt FINFOACK(-2)        |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|rxpkt FINFO &               |rxpos = resume offset     |ToData    |
+|        | |file we want to resume      |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |6|rxpkt FINFO &               |rxpos = 0                 |ToData    |
+|        | |new file for us             |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |7|rxpkt EOF (apparent dup)    |txpkt EOFACK              |          |
++--------+-+----------------------------+--------------------------+----------+
+|ToData  |                              |txpkt FINFOACK(rxpos)     |DATA      |
+|        |                              |rxsyncid = 0              |          |
+|        |                              |rxlastsync = 0;           |          |
+|        |                              |rxretries = 0             |          |
+|        |                              |reset rxtimer             |          |
+|        |                              |braintimer = 120          |          |
++--------+-+----------------------------+--------------------------+----------+
+|DATA    |1|rxpkt FINFO (apparent dup)  |txpkt FINFOACK(rxpos)     |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATA &                |Store data                |          |
+|        | |DATA(pos) == rxpos          |rxpos += datalen          |          |
+|        | |                            |rxretries = 0             |          |
+|        | |                            |rxlastsync = rxpos        |          |
+|        | |                            |reset rxtimer             |          |
+|        | |                            |braintimer = 120          |          |
+|        | |                            |if (rxwindow)             |          |
+|        | |                            |   txpkt DATAACK(rxpos)   |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt DATA &                |Report bad rxpos          |BadPos    |
+|        | |DATA(pos) != rxpos          |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt EOF &                 |Close file, received ok   |OkEOF     |
+|        | |EOF(pos) == rxpos           |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|rxpkt EOF &                 |Close, save for resume    |OkEOF     |
+|        | |EOF(pos) == -2              |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |6|rxpkt EOF &                 |Report bad EOF            |BadPos    |
+|        | |EOF(pos) != rxpos           |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |7|File write error or         |Close, save for resume    |          |
+|        | |user wishes to skip file    |rxpos = -2                |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |8|rxpkt IDLE &                |braintimer = 120          |          |
+|        | |hdxlink == False            |                          |          |
++--------+-+----------------------------+--------------------------+----------+
+|BadPos  |1|DATA/EOF(pos) <= rxlastsync |rxretries = 0             |Timer     |
+|        | |                            |reset rxtimer             |          |
+|        | |                            |rxlastsync = pos          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|DATA/EOF(pos) > rxlastsync  |rxlastsync = pos          |Timer     |
++--------+-+----------------------------+--------------------------+----------+
+|Timer   |1|rxtimer expired             |                          |HdxLink   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (rxtimer not expired)  |                          |DATA      |
++--------+-+----------------------------+--------------------------+----------+
+|HdxLink |1|rxretries > 4 &             |hdxlink = True            |Retries   |
+|        | |txstate < REND &            |rxretries = 0             |          |
+|        | |originator == False &       |                          |          |
+|        | |hdxlink == False            |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (above not the case)   |                          |Retries   |
++--------+-+----------------------------+--------------------------+----------+
+|Retries |1|inc rxretries == 10         |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxretries == 1              |increase rxsyncid         |RPos      |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (rxretries > 1)        |                          |RPos      |
++--------+-+----------------------------+--------------------------+----------+
+|RPos    |                              |lastrxdatalen/=2 (min.64) |DATA      |
+|        |                              |txpkt RPOS (rxpos,        |          |
+|        |                              |   lastrxdatalen,rxsyncid)|          |
+|        |                              |rxtimer = timeout         |          |
++--------+------------------------------+--------------------------+----------+
+|OkEOF   |                              |txpkt EOFACK              |FINFO     |
+|        |                              |reset rxtimer             |          |
+|        |                              |braintimer = 120          |          |
++--------+-+----------------------------+--------------------------+----------+
+|DONE    |1|rxpkt FINFO (apparent dup)  |txpkt FINFOACK(-2)        |          |
++--------+-+----------------------------+--------------------------+----------+
+
+
+    HYDRA in FidoNet technology mailers
+    =====================================================================
+    HYDRA is suitable for use in FidoNet mailers. It can be implemented
+    for EMSI and FTS-6 mail sessions. The FTS-6 (YooHoo) capability bit
+    for HYDRA is 0x0020 (DOES_HYDRA). The EMSI and IEMSI protocol
+    capability flag is HYD.
+
+    When utilizing HYDRA in a mail session, two complete batches are
+    always performed. Little else differs from a normal FTS-6 ZedZap mail
+    session. The first batch is used to transmit all mail, files, and
+    file requests by both sides. The second batch is always performed,
+    sending nothing if there are no file requests to honor. The data
+    buffers are not purged between the two batches since HYDRA ignores
+    any leftovers from the previous batch (END packets, etc.).
+
+    To integrate HYDRA into an existing mailer, the same code used for
+    the ZedZap session flow can be used, but instead of one transmit and
+    one receive session, two transmit sessions (or batches) are used.
+    When the HYDRA end of batch is initiated it will not be terminated
+    until an end of batch has been received from the remote and the end
+    of session sequence has been finished.
+
+    Fido and FidoNet are registered marks of Tom Jennings and Fido
+    Software.
+
+
+    Error detection using CRCs
+    =====================================================================
+    CRC (Cyclic Redundancy Check) values only provide their promised
+    maximum error detection capability when properly applied, which
+    involves calculating and transmitting low-bit first, presetting the
+    CRC with all ones, and transmitting the ones' complement of the
+    result. The receiver also initializes to all ones, processes all of
+    the data AND the following CRC, and the result should match a "magic
+    value" which is 0xf0b8 for the 16-bit CRC and 0xdebb20e3 for the
+    32-bit CRC.
+
+    The easiest and fastest way to perform CRC calculations is by using a
+    table that does the algorithm's shift-operations in 8-bits at a time.
+
+
+    CRC-16 error detection
+    ---------------------------------------------------------------------
+    16-bit CRC using the CCITT CRC-16 polynomial. This is the default at
+    startup, and always used for HEX packets even if both sides are
+    capable of handling 32-bit CRCs.
+
+    This CRC-16 is not identical to the one used by the Xmodem and Zmodem
+    file transfer protocols. The polynomial is the same
+    (X^16+X^12+X^5+X^0 or 0x8408) but the bit-ordering is the opposite,
+    and preconditioning and postconditioning is used as in 32-bit CRCs.
+    This method is also used by the European version of X.25.
+
+    The 16-bit CRC table is created as follows (pseudocode, the variable
+    CRC16 and the table of 256 entries are 16-bit unsigned integers):
+
+        FOR (i=0 TO 255)
+            {
+            CRC16=i
+            FOR (N=1 TO 8)
+                {
+                IF (CRC16 AND 1)
+                    CRC16=(CRC16 >> 1) XOR 0x8408
+                ELSE
+                    CRC16=CRC16 >> 1
+                }
+            CRC16TAB[i]=CRC16;
+            }
+
+    When processing data, each byte is run through the CRC calculation
+    routine as follows (variable CRC stores the 16-bit CRC value/result,
+    C is the next 8-bit char):
+
+        CRC=CRC16TAB[(CRC XOR C) AND 0xff] XOR ((CRC>>8) AND 0x00ff)
+
+
+    CRC-32 error detection
+    ---------------------------------------------------------------------
+    32-bit CRC using the CCITT CRC-32 polynomial. Support of CRC-32 is
+    optional and signalled in the INIT packet.
+
+    If both sides indicate they can handle CRC-32, all packets except
+    those transmitted in HEX format use this algorithm instead of CRC-16
+    to improve error detection.
+
+    This CRC-32 is identical to the one used by the Zmodem protocol.
+    The polynomial is (0xedb88320):
+
+    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
+
+    The principal method of calculation, transmission, and checking is
+    identical to CRC-16 as described above, but the "magic value" for
+    32-bit CRC is 0xdebb20e3.
+
+    The CRC-32 table is created as follows (pseudocode, the variable
+    CRC32 and the table of 256 entries are 32-bit unsigned integers):
+
+    FOR (i=0 TO 255)
+        {
+        CRC32=i
+        FOR (N=1 TO 8)
+            {
+            IF (CRC32 AND 1)
+                CRC32 = (CRC32 >> 1) XOR 0xedb88320
+            ELSE
+                CRC32 = CRC32 >> 1
+            }
+        CRC32TAB[i] = CRC32;
+        }
+
+    When processing data, each byte is run through the CRC calculation
+    routine as follows (variable CRC stores the 32-bit CRC value/result,
+    C is the next 8-bit character):
+
+        CRC=CRC32TAB[(CRC XOR C) AND 0xFF] XOR ((CRC>>8) AND 0x00ffffff)
+
+
+    The authors
+    =====================================================================
+    The authors can be reached at the following addresses:
+
+    Joaquim H. Homrighausen                    Arjen G. Lentz
+    389, route d'Arlon                         Lentz Software Development
+    L-8011 Strassen                            Langegracht 7B
+    Luxembourg                                 3811 BT Amersfoort
+                                               The Netherlands
+	joho@ae.lu
+    FidoNet 2:270/17                           aglentz@fido.lu
+                                               FidoNet 2:283/512
+
+
+    The name HYDRA
+    =====================================================================
+    Hydra is a greek mythological creature (the watersnake). Like the
+    Nemeic lion, Hydra is the daughter of the giant Typhon and the snake
+    Echidna.
+
+    She grew up in the marshes of Lerna near/in Argolis (Argos). There
+    she ate entire herds of cattle and destroyed large cropfields. Later,
+    she lived in caves on a hill near the spring of Amymone.
+
+    Hydra is a monstrous large snake with nine heads: eight mortal ones,
+    and one (the middle one) immortal. She was defeated and killed by
+    Heracles (Hercules) - son of Zeus and Alcemene, grandson of Perseus -
+    as the second of his twelve tasks, with the help of his cousin
+    Iolaos. Every time he cut of one of the heads with his sword, two new
+    heads grew in its place. So Iolaos scorched the wound of each cut off
+    head with burning branches so the head couldn't grow on again.
+
+    Heracles buried the last and immortal head under a stone nearby. He
+    also dipped his arrows in Hydra's poisonous blood, thereafter the
+    wounds caused by those arrows were incurable.
+
+
+    Also star constellation (sign of the watersnake) in the equatorial
+    zone.
+
+
+    Also a type of sweetwater polip (the Hydroidea Thin, tubeshaped body
+    can be full contracted, just like the six (or more) tentacles. There
+    is no generation change, the gender-products grow directly on the
+    body.
+
+    The animals catch their prey with nettlecells, and are very verocious.
+    They can be found in various stilstanding and flowing water and were
+    first described by Anthonie van Leeuwenhoek in the year 1704.
+
+
+    Also small island (spelled Idhra in modern Greek) of the Sargonic
+    group in the Aegean Sea, just of the eastern tip of the Argolis
+    peninsula of the Peloponesus (Attika). Its length (NE/SW) is 21 km,
+    with a total area of 49,6 square km. Its highest point is 597 meters
+    above sea level. Population of 2794 (latest census: 1981). Only one
+    real city with the same name as the island. Once quite wooded and
+    well watered, now denuded and dry, with almost no arable land
+    (infertile limestone). Certain times of the year the people have to
+    ship in water from the main land. Its Turkish name is Camliza which
+    means "Place of Pines".
+
+    References:
+         Dutch:  Oosthoeks Encyclopedie
+                 Grote Winklerprins Encyclopedie
+       English:  Encyclopaedia Brittannica
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0087.html b/html/ftsc/fsc-0087.html new file mode 100755 index 00000000..714a8ac7 --- /dev/null +++ b/html/ftsc/fsc-0087.html @@ -0,0 +1,305 @@ + + +File Forwarding in Fidonet Technology Networks. + + + + +
+  | Document: FSC-0087
+  | Version:  001
+  | Date:     31 October, 1995
+  |
+  | Robert Williamson FidoNet#1:167/104.0
+
+    File Forwarding in Fidonet Technology Networks
+    Robert Williamson FidoNet#1:167/104.0  robert@ecs.mtlnet.org
+
+    Purpose: 
+        To  document  current practices in File Forwarding and the minimum
+    requirements and known extensions of the TIC file format.
+
+    Acknowledgements:
+        The  TIC  file  format  was introduced by Barry Geller, in the MSDOS
+    File Forwarder, Tick.  Useful extensions to this format were introduced
+    by Harald Helms, in the MSDOS FileForwarder, AllFix.
+    
+    Terminology:
+    FTN - Fidonet Technolgy Network, such as FIDONET, AMIGANET or IBMNET.
+          Sometimes used interchangably with the term DOMAIN.
+
+    FNC - FileName Conversion, process of converting filenames to msdos 8.3
+          format for transmission.
+
+    FQFA - Fully Qualified FTN Address, the format is
+              FTN#Zone:Net/Node.Point
+
+    CRC - Cyclic Redundancy Check, method to determine whether some data
+          has been altered. CRC-32 is used in File Forwarding.
+
+    TIC - a file that contains control information for the File Forwarding
+        system.   These  files  are  named  xxSTAMP.TIC,  where  xx  is  an
+        abbreviation  representing  the  File  Forwarding  program name and
+        stamp  is  a  unixdate  stamp  truncated  to 6 characters.  
+
+    UTC  -  Universal  Time  Coordinated,  the  time  at  the  0o  meridian
+        (Greenwich); previously called GMT
+
+
+    forwarding  -  the  process  of  creating and sending tic files and the
+                   associated  file to one's downlinks.
+
+    ticking - the processing of reading and verifying a tic file and it's
+              associated file.
+
+    hatching - the process of introducing a new file into a fileecho
+
+    cross-hatching - the process of forwarding a file from one fileecho
+                     (ususally restricted) to another
+
+    Associated File - The file listed in the FILE field of the TIC file.
+
+
+        Note that use of UPPERCASE on tic file keywords in this document in
+        for display purposes only.
+
+  Format of a TIC file:
+
+    Addressing:
+        In  a  tic  file  any form of FTN address representation from 3d to
+        FQFA  may  be  used.   All  File  Forwarders  must  understand  the
+        following formats:
+          zone:net/node                 - 3D 
+          zone:net/node.point           - 4D
+          zone:net/node@ftn             - 5D - point 0 assumed
+          zone:net/node.point@ftn       - 5D 
+          ftn#zone:net/node.point       - fqfa
+
+        File Forwarders should have configurable options per site as to the
+        type of addressing each of it's downlinks can understand.
+
+    Dates:
+        All dates are expressed in UTC.
+
+    TimeDateStamps:
+        All  TimeDateStamps are unix TimeDateStamps (# of seconds since Jan
+        1, 1960) in UTC and expressed in hexadecimal notation.
+
+    Case Insensitivity:
+        the  format is completely case-insensitive.  It is general practice
+        that  the  first  letter  of a keyword is uppercase.  This is not a
+        requirement.
+
+    Order Dependancy:
+        keywords are not order dependant.
+        Order  dependancy  is required in some groupings of a keyword, such
+        as PATH, VIA, DESC and APP.
+
+    Modification of address fields on PassThrough:
+        The  forwarding  site may modify the addresses in any keyword field
+        to  make  them  compliant  with  the addressing limitations of each
+        downlink.  
+
+    Stripping of SeenBys:
+        The  forwarding site may strip seenbys to current FTN, ZONE or NET,
+        when not forwarding outside of current FTN, ZONE or NET.  This does
+        not imply nor permit the stripping of of a direct downlink which is
+        outside the current strip filter.
+
+
+    Keywords:
+      There are no colons on keywords.
+
+      Each keyword line is terminated with CR LF pair.
+
+      The maximum length of a keyword line is 256 characters, including the
+      CRLF termination. Some keyword lines may have a shorter limit.
+
+      Keywords  are  separated from their data by a single space.  There is
+      no space if there is no data associated with the keyword.
+        eg:  ReturnReceipt
+
+      Keywords are case-insensitive and order independant.
+
+      Keywords not understood are to be passed-though.
+
+      Known Keywords that are blank should not be passed though.
+        For  example,  an  empty  AREADESC,  could be either dropped or the
+        blank  replaced with the proper description.
+
+      Most Keywords are passed through when processing.
+        There  are  exceptions.  In some cases, a site-specific replacement
+        may be created.
+        Keywords marked with a ^ should not be passed-through.
+
+      Keywords marked with a * are REQUIRED when processing a TIC file.
+        If  any  of these are missing, the tic file should be considered as
+        BAD and the associated file not forwarded to downlinks.
+
+      Keywords marked with a # are CREATED when hatching or forwarding.
+
+
+    *#  AREA [AreaName]
+          the TagName of the file area.
+
+        AREADESC [description of area]                    OPTIONAL
+          a  short  (80 chars) description of the file area.  This could be
+          the description found in FileBone.NA
+
+    *#  FILE [File being sent]
+          the name of the file being sent, no path
+          the filename must conform to msdos 8.3 format, unless it is known
+          that the receiving site can handle longer filenames.
+     
+    ^#  FULLNAME [original filename before FNC]           OPTIONAL FNC only
+          the original filename (no path) before FileName Conversion    
+
+    *#  CRC [CRC-32 in hex]
+          crc of the file being sent, 8 hexadecimal characters
+
+    ^   MAGIC [MagicName]               OPTIONAL
+          Name  under  which the file can be FREQed from the site listed in
+          FROM.   This  is  NOT  passed  though when forwarding, unless the
+          MAGIC  name  is  the  same  on  the  forwarding  site.  It can be
+          replaced by the appropriate name.
+
+        REPLACES [FileName]               OPTIONAL
+          Filename  (no  path)  of  a  file  hatched  in  the AREA that the
+          associated file replaces.  If the site expects FNC files, and the
+          filename  does  not confrom to msdos 8.3 convention, the REPLACES
+          name should also be FNC.
+
+     #  DESC [Description]
+          Description of the file, limited to 80 characters per line,
+          including CRLF termination.
+          If  multiple LDESC lines are used, the DESC line must provide the
+          maximum information.  No File Forwadrer is required to passthough
+          or make use of any extra DESC line after the first.
+
+     # LDESC [multiple lines]
+          A  long description of the file.  LDESC does NOT replace DESC, it
+          is  used IN ADDITION to the short description.  No File Forwarder
+          is required make use of LESC lines.
+
+     #  SIZE [Bytes]              OPTIONAL, SHOULD be required
+          Length of the file in bytes
+
+        DATE [TimeDateStamp]
+          TimeDateStamp of the file. Can be date of creation of archive.
+
+       RELEASE [TimeDateStamp]
+          Date  when file is TO BE released.  Usually used by SDS, but can
+          be used by ADS as well.
+
+       AUTHOR [name]
+          Name  of  the author of the software package being hatched.  This
+          field  is  obviously not applicable to Newsletters, Nodelists and
+          Diffs and the like.
+
+       SOURCE [authors_address]
+          FTN  address of the Author of the software package being hatched.
+          Not  necessary  the same as the ORIGIN hatch site.  Does not have
+          to be an FTN address.
+
+     ^ APP [program] [Application Specific Information]
+          The  APP  keyword  is  a  keyword  known  to programs of the name
+          indicated.  APP'S are order dependent and must be passed though.
+  
+    *#  ORIGIN [Address]
+          Site where file entered the fileecho
+
+    *^# FROM [Address] [Pwd]
+          Site  that  is  forwarding  the  file  to  the next site.  Pwd is
+          optional and rarely used, IF AT ALL.  Pwd is NEVER passed through.
+
+    ^   TO [Address]                        OPTIONAL
+          Site  to  which  this TIC and the assocaited file are being sent.
+          This keyword is included in the .TIC file when:
+            a)  the file is being routed via another system which permits
+                such routing.  
+            b)  the  platform  in  use  does  not  have  any  FTN  software
+                independant   method   of   associating   a  file  nd  it's
+                destination.   eg.   platforms  that  do not have filenotes
+                that   could  contain  this  information  as  part  of  the
+                filesystem.
+
+          If  the address in the TO line is that of the receiving site, the
+          field  is  not passed through when forwarding.  If the address in
+          the  TO  lines  IS  NOT  that of the receiving site, it should be
+          forwarded to the TO site, if a routing agreement is in place with
+          the sending site.
+
+    *^# CREATED [by] [Program Banner]
+          File  Forwarder which created the TIC file.  This is generally in
+          the form:  
+            Created [by] program_name version [copyright_info]
+
+        VIA [FROM CREATED]                  OPTIONAL (tracking)
+          Copy  of  CREATED  line of FROM, with 'Created [by]' stripped and
+          FROM  prepended.   Always passed though.  The VIA is only created
+          by the receiving site when forwarding. It is never created by the
+          hatching  site.  Therefore, in any TIC file, the addresses in the
+          FROM and VIA should never be the same.
+          examples:
+          Via 1:167/100 ALLFIX+ 4.31 Copyright (C) 1992,95 Harald Harms (2:281/910)
+          Via FIDONET#1:167/104.0 XTick 3 Copyright (c) 1995 Robert Williamson FIDONET#1:167/104.0
+
+    *#  PATH [Address] [TimeDateStamp] [date and time]
+          Address  of  Site  which  has forwarded the file.  TimeDateStamp,
+          date and time is that of when the Site received and Processed the
+          file.
+
+    * # SEENBY [Address]
+          Site  which  has  received the file.  There are multiple lines of
+          Seenby and they are unordered.
+
+    *   PW [password]
+          Site or Area password.  This is case-insensitive and should be at
+          least 5 characters in length. 
+
+        PGP [signature]
+          PrettyGoodPrivacy signature. To be discussed. 
+
+    ^    ReceiptRequest -no data-               OPTIONAL
+          A  request  to the receiving system to generate a IsReturnReceipt
+          (attribute  word bit 13) messsage, in the same manner it would if
+          it  had  received  a message with the FileAttach an ReturnReceipt
+          attributes and a subject of the filename.
+          There  is  NO  requirement  to recognize this keyword.  It should
+          never be passed through.
+
+  Transmission of Files:
+
+    The  associated file, that is, the file Listed in the FILE field of the
+  TIC  file, should always be sent FIRST.  In the case of a failed session,
+  sending  the  FILE  first  prevents  the  orphaning  of  the file that is
+  normally caused by the deletion or movement of the TIC file to BAD. 
+
+    File  Forwarders should not move or delete orphaned TIC files, but this
+  can neither be relied upon nor mandated.
+
+    File  Forwaders  should  be  transparent  to  the  renaming  of file by
+  mailers.   This  means  that  if  the  mailer renames a duplicate file by
+  renaming  or  bumpinmg  a numeric extension, the File Forwarder should be
+  able  to  use  the  size  and  crc fields of the TIC to find and properly
+  rename the associated file referred to in the TIC.
+
+  File  Forwaders  should  always  delete and dequeue unsent TIC files when
+  re-hatching  the  same  or  updated  version  of an associated file.  The
+  implementor  may  wish  to  allow  exceptions  for  periodicals  such  as
+  nodediffs and newsletters.
+
+ -to be continued-
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0088.html b/html/ftsc/fsc-0088.html new file mode 100755 index 00000000..8231eaf1 --- /dev/null +++ b/html/ftsc/fsc-0088.html @@ -0,0 +1,326 @@ + + +Compatibility and Link Qualifier Extensions for EMSI Sessions + + + + +
+  | Document: FSC-0088
+  | Version:  001
+  | Date:     31 October, 1995
+  |
+  | Robert Williamson FidoNet#1:167/104.0
+
+    Compatibility and Link Qualifier Extensions for EMSI Sessions
+    Robert Williamson FidoNet#1:167/104.0  robert@ecs.mtlnet.org
+
+    Purpose:
+
+    The  basic  purpose of this document is to start discussions which will
+    hopefully result in an improved handshake negotiation protocol.
+
+    Scope:
+
+    Relation of flags to Types of files transferred:
+
+    The  FSC-0056  EMSI  specification  (hereafter  referred  to as EMSI-I)
+    makes  little  distinction  between  ARCmail/packets and other types of
+    files,  such  as  files attached and TIC'ed files.  In EMSI-I, the term
+    'Mail'  when  not  used  in  conjunction with the term 'compressed', is
+    interpreted to mean ANY file.
+
+    This  extension  (hereafter  referred to as EMSI-II) makes reference to
+    and  allows control of types of files in addition to 'compressed mail'.
+    References  to  'Mail'  are  changed to 'File' where common practice so
+    indicates.   The  additional qualifier flags described provide for more
+    control as to the types of files a system is prepared to receive.
+
+
+    Relation of flags to presented addresses:
+
+    The  EMSI-I  specification does not allow qualification for any address
+    other than the PRIMARY address.  This means that Link flags are limited
+    in  application  to  either  all  presented addresses or to the primary
+    presented address only.
+
+    This  extension  also  allows  application  of  Link  flags to specific
+    addresses other than the primary.
+
+
+    Distinctions between Calling and Answering System:
+
+    In  the EMSI-I spec, the type of flags that may be presented is limited
+    by  the  status  of the site.  Certain flags may only be presented when
+    the  site  is the caller and other flags may only be presented when the
+    site   is   the   answerer.    This  proposed  extension  removes  this
+    distinction.
+
+    In the EMSI-I spec, certain Link and Capability (a.k.a:  Compatibility)
+    flags  are  caller-driven, while others are controlled by the answering
+    system.  This specification attempts to harmonize these discrepancies.
+
+    A  attempt  is made to remain somewhat backwards compatible and to have
+    new  flags  follow the original flag naming convention.  However, IMHO,
+    it  would  be preferable to harmonize the flags; reducing the number of
+    them  while retaining the fine type control, so that the same codes are
+    used in all sessions.
+
+    Under  both  EMSI-I and EMSI-II, any flags that are not understood, are
+    to  be  ignored.   Therfore,  if  a site presents it's flags in EMSI-II
+    format  and  the  other site does not do EMSI-II, it is permissable for
+    that site to interpret all flags according to EMSI-I specifications.
+
+
+    Specifics:
+
+    Compatibility flags:
+
+    Compatibility  flags  consist of a string of codes that specify the
+    PROTOCOL CAPABILITIES and ENABLED FEATURES of the mailer.
+
+    ARC, XMA
+    These  EMSI-I  compatibility  flags  have  no  meaning  relavant to the
+    transfer  of  files  and  are  not  to  be presented under EMSI-II.  If
+    received, they are to be ignored.
+
+
+    FNC    
+    The FNC EMSI-I compatibility flag has been identified as a 'mistake' by
+    the  author  of EMSI-I.  This is agreeable as that specification called
+    for   the   creation   of   a   filename   that  was  ALWAYS  8.3,  not
+    up-to-8.up-to-3.
+    It   is   not  to  be  presented  under  EMSI-II.   If  received  as  a
+    compatibility flag, it is to be ignored.
+
+
+    Protocol Selection:
+
+    In  the EMSI-I spec, a requirement is placed upon the calling system to
+    present  it's  available  protocols  in  order  of preference.  A quote
+    follows:
+
+        The calling system must list supported protocols first and
+        descending order of preference (the most desirable protocol
+        should be listed first).
+        The answering system should only present one protocol and it
+        should be the first item in the compatibility_codes field.
+
+    Some mailer authors have interpreted 'the compatibility_codes field' in
+    the  second  sentence  to  mean  that  of the answering system, thereby
+    making  protocol  selection RECEIVER-PREFS driven.  This interpretation
+    makes  unnecessary  the  'decending  order' requirement placed upon the
+    calling   system,   so  shall  be  considered  in  conflict  with  that
+    requirement.
+
+     Most   mailer  authors  have  interpreted  that  phrase  to  mean  the
+    'compatibility_codes  field'  OF  THE  CALLER,  thereby making protocol
+    selection  CALLER-PREFS  driven.   Since  EMSI-I  was intended to be "a
+    clear  protocol  definition  for  state-of-the-art  E-Mail  systems  to
+    follow",  they  cannot  be  faulted  for  interpretation.  Caller-prefs
+    driven  selection  is state-of-the-art, receiver-prefs driven selection
+    is older technolgy, such as Wazoo.
+
+    This   specification   requires   that   the   second  interpretation,
+    CALLER-PREFS driven, be mandatory.
+
+
+    New Compatibilty Flags:
+    ----------------------
+
+    EII
+    Indicates   that   the   system   will   interpret   flags  under  this
+    specification, if other end also presents this flag.  IF either or both
+    systems  do  not  present  this  flag,  all  interpretations  are  done
+    according to EMSI-I.
+
+    DFB
+    Indicates  that  the  system  presenting  is  capabable of fall-back to
+    FTS1/WAZOO  negotiation  in the case of failure of EMSI handshake or no
+    common  protocol.   Since  ZMO  is  the  minimum required protocol, NCP
+    should  only  occur  if  the  answering  system  presents more than one
+    protocol..  (ie. it's broken)
+
+    FRQ
+    Indicates  that  the  system  will  accept  and  process  file requests
+    received  during  outbound  calls.   In other words, the calling system
+    will  do a second turnaround for uni-directional protocols, to send the
+    files requested, at his cost.
+
+    NRQ
+    NRQ should be presented ONLY IF the mailer does not have a file request
+    server, task or function and cannot accept requests..  It should NOT be
+    used to indicate that the  function  is  temporarly disabled. 
+
+    When  examined,  No  requests will be sent.  It would be advisable that
+    the  mailer  alert  the  system  operator  of this occurance to prevent
+    continued polling of the remote site.
+
+
+    Protocol Capabilities:
+
+    Protocol   capability   flags  are  presented  in  decending  order  of
+    preference  by  the  caller.  The answering system selects and presents
+    the  FIRST  protocol  from  the  callers  list  that  it supports.  The
+    answering system must present only ONE protocol.
+
+    HYD  Hydra bi-directional    (link flags define parameters)
+    JAN  Janus bi-directional
+    TZA  DirectZap               (TrapDoor DirectZap varient)
+    DZA  DirectZap               (Zmodem variant, reduced escape set)
+    ZAP  ZedZap                  (Zmodem variant, upe 8K blocks)
+    ZMO  Zmodem w/1,024 packets  (Wazoo ZedZip)
+    SLK  SeaLink                 (no TYSNC, No MDM7, No TeLink)
+                                 (8-32k window/ReSync/OverDrive/LongNames)
+
+    NCP
+    This  is  presented  if  no compatible protocol can be negotiated under
+    EMSI.   Since  in  most  FTN  networks,  a  common protocol DOES exist,
+    fallback   to  WaZoo  and  FTS1  negotiation  is  expected.   If  these
+    negotiation methods are not available, the session is terminated.
+
+    This  condition  should  never  occur  under  normal circumstances.  It
+    should  be  considered as a problem with the design or configuration of
+    one of the mailers involved.
+
+    Link flags:
+    ----------
+
+    Link  flags  consist  of a string of codes that specify DESIRED CONNECT
+    CONDITIONS.   They  apply  to  the CURRENT SESSION ONLY.  Under EMSI-I,
+    there are four TYPES of link flags:  communications parameters, session
+    parameters, pickup options and hold options.  Under EMSI-II, only three
+    types  are  used,  the communications parameters type is REMOVED, as it
+    serves no purpose whatsoever in FTN operations.
+
+
+    Link Session options:
+
+    FNC
+    If  either  system  presents  this  flag,  it is an indication that the
+    presenting   system   requires   filename   conversion   to  cp/m-msdos
+    conventions.  The other system will convert filenames to cp/m cpm/msdos
+    8.3 conventions before sending. 
+    The   convention   is   defined   as   a  filename  consisting  of  two
+    parts,  the  filepart  and  extension.   The filepart and extension are
+    separated  by a period ".".  The filepart may be from 1 to 8 characters
+    in  length  and  the  extension  may  be  from  0 to 3 characters.  The
+    character set shall be any uppercase character in the range A-Z and any
+    numeric  character  in  the  range  0-9.   If  the extension is of zero
+    length, the period may or may not be present.
+
+
+    RMA
+    Indicates that the presenting site is able to send and process multiple
+    file  requests.   If both sites present this flag, the caller will send
+    any REQ files found for each AKA presented by the answering system.
+    The answering system will process each received REQ.
+
+    RH1
+    Indicates  that  under  the  Hydra  protocol,  batch  one contains file
+    requests only, while batch 2 is reserved for all other files.
+    
+
+    (others to be defined)
+
+    Pickup and Hold Flags:
+
+    Under  the  EMSI-I  specification, Link Pickup flags are only presented
+    when  calling (an Outbound Session) and are examined and processed only
+    when  answering  (an  Inbound  Session)  and  Link  Hold flags are only
+    presented  when  answering  (an  Inbound  Session) and are examined and
+    processed only when calling (an Outbound Session).
+
+    With  EMSI-II,  BOTH  Pickup and Hold flags are presented by both sites
+    during  a  session.   This  allows  more control for those systems, for
+    example,  which  cannot  modify  addresses  presented or rotate akas to
+    change  the  primary  address  presented  on  a per-session or per-site
+    basis.
+
+
+    Link Pickup and Hold:
+
+    Each  system can present one of three (or more) Link options related to
+    application of addresses.  If neither of these flags are presented, PUA
+    is to be assumed.
+
+    Neither  PUA  nor  PUP  is  to  be  presented  if  only one address was
+    presented.
+
+             PUP     Pickup FILES for primary address only
+          /  PUA     Pickup FILES for all presented addresses
+         /   PUn     Pickup FILES for address number n in AKA list
+ one of |
+         \
+          \  NPU     No FILE pickup desired. (calling system)
+             HAT     Hold all FILES          (answering system)    
+             HAn     Hold all FILES for address number n in AKA list
+
+
+    Qualifiers:
+
+    Qualifiers  are  processed  in  the  order presented, with any conflict
+    being  resolved  by  subsequent  qualifiers overridding any conflicting
+    previous qualifier in the list.
+
+    Qualifiers may be not be presented with either NPU or HAT and should be
+    ignored if received with NPU or HAT.
+
+    PickUp:
+
+        PMO     PickUp Mail (ARCmail and Packets) ONLY 
+        PMn     PickUp Mail ONLY for address number n in AKA list
+
+        NFE     No TIC'S, associated files or files 
+                attachs desired
+        NFn     No TIC'S, associated files or file attaches, 
+                for address number n in AKA list
+
+        NXP     No compressed mail pickup desired 
+        NXn     No compressed mail pickup desired, 
+                for address number n in AKA list
+
+        NRQ     File requests not accepted by caller
+                This  flag is presented if file request processing
+                is disabled TEMPORARILY for any reason
+        NRn     File requests not accepted by caller
+                for address number n in AKA list
+
+     Note that NFE,NPX,NRQ != NPU
+
+    Hold:
+
+        HNM     Hold all traffic EXCEPT Mail (ARCmail and Packets)
+        HNn     Hold all traffic EXCEPT Mail (ARCmail and Packets)
+                for address number n in AKA list
+
+        HXT     Hold compressed mail traffic.
+        HXn     Hold compressed mail traffic.
+                for address number n in AKA list
+
+        HFE     Hold tic's and associated files
+                and file attaches other than mail 
+        HFn     Hold tic's and associated files
+                and file attaches other than mail 
+                for address number n in AKA list
+
+        HRQ     Hold file requests (not processed at this time)
+                This  flag is presented if file request processing
+                is disabled TEMPORARILY for any reason
+        HRn     Hold file requests (not processed at this time)
+                for address number n in AKA list
+
+     Note that HXT,HRQ,HFE == HAT
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0091.html b/html/ftsc/fsc-0091.html new file mode 100755 index 00000000..7be686be --- /dev/null +++ b/html/ftsc/fsc-0091.html @@ -0,0 +1,60 @@ + + +ISDN nodelist flags (rev.002). + + + + +
+ | Document: fsc-0091
+ | Version:  001
+ | Date:     01 Jun 1996
+ | Arjen Lentz, 2:283/512
+
+ISDN nodelist flags (rev.002)                   Arjen Lentz (agl@bitbike.com)
+addendum to FTS-0005                                        FidoNet 2:283/512
+superceding FSC-0075                                       October 30th, 1995
+
+Input from Michael Buenter, Jan Ceuleers, Chris Lueders, and others. Thanks!
+
+The proposed new information text in nodelist trailer is as follows:
+
+   Nodelist  Specification of minimal support required for this flag;
+   flag      any additional support to be arranged via agreement between users
+   ========  =================================================================
+   V110L     ITU-T V.110 19k2 async ('low').
+   V110H     ITU-T V.110 38k4 async ('high').
+   V120L     ITU-T V.120 56k async, layer 2 framesize 259, window 7, modulo 8.
+   V120H     ITU-T V.120 64k async, layer 2 framesize 259, window 7, modulo 8.
+   X75       ITU-T X.75 SLP (single link procedure) with 64kbit/s B channel;
+               layer 2 max.framesize 2048, window 2, non-ext.mode (modulo 8);
+               layer 3 transparent (no packet layer).
+   ISDN      Other configurations. Use *only* if none of the above fits.
+   ===========================================================================
+   NOTE: No flag implies another. Each capability MUST be specifically listed.
+   If no modem connects are support, the nodelist speed field should be 300.
+
+   Conversion from old to new ISDN capability flags:
+   - Nodes in the USA currently use the 'ISDN' flag.
+     Most will be able to change to V120H (64k lines).
+     Also many to V120L,V120H (64k lines) with autodetecting equipment.
+     Some to only V120L (still with 56k lines).
+   - Nodes in Europe currently use the ISDNA, ISDNB and ISDNC flags.
+     A simple translation will do the trick here.
+     ISDNA -> V110L
+     ISDNB -> V110H
+     ISDNC -> X75
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0092.html b/html/ftsc/fsc-0092.html new file mode 100755 index 00000000..74462c06 --- /dev/null +++ b/html/ftsc/fsc-0092.html @@ -0,0 +1,243 @@ + + +New control lines for forwarded messages. + + + + +
+ | Document: FSC-0092
+ | Version:  001
+ | Date:     September 12th 1996
+ | Author:   Michael Hohner
+
+
+                                 New control lines
+                              for forwarded messages
+
+                                        by
+                                  Michael Hohner
+                                  2:2490/2520.17
+
+                                  September 1996
+
+   Status of this document:
+
+         This document proposes a standard for the Fidonet(tm) community
+         and for other networks using Fido technology. It may be freely
+         distributed if unchanged.
+
+         You can reach the author at one of the addresses listed at the end
+         of the document.
+
+
+   Abstract:
+
+         Most fidonet message editors offer a "forward" function. Using
+         this function a user A can sort of "redirect" a message from user B
+         to another user C, maybe because A is not the correct recipient or
+         because C is a better person to answer the message. The name and
+         address of B are usually included in the forward in free-text format.
+         The message text is included in non-quoted format.
+
+         A problem arises when the final recipient C wants to reply to sender B
+         of the forwarded message. The forward contains the intermediate user A
+         as the sender. So user C must insert the name and address of B
+         manually, using the information contained in the message text. The
+         message editor of C can't do this automatically because of the
+         free-text format. The editor will also use incorrect quote initials,
+         which is at least irritating.
+
+         This document introduces 6 new control lines which contain the header
+         information of the original message. With these control lines the
+         message editor can use the original header information automatically.
+
+
+   Specifications:
+
+         There are 7 new control lines: FWDFROM, FWDTO, FWDORIG, FWDDEST,
+         FWDSUBJ, FWDAREA, FWDMSGID. As all control lines they start with an
+         ASCII 01 character followed by the control line name followed by
+         whitespace followed by the control line's content followed by ASCII 13.
+
+         Please note that all these control lines do not have a colon (like the
+         control lines in FTS-0001). This would be just waste of space.
+
+         FWDFROM
+         -------
+
+         This control line contains the name of the original sender as found in
+         the FROM field of the original message. Leading and trailing
+         whitespace should be removed. This control line should be omitted
+         altogether if the FROM field is empty.
+
+         FWDTO
+         -----
+
+         This control line contains the name of the original recipient as found
+         in the TO field of the original message. Leading and trailing
+         whitespace should be removed. This control line should be omitted
+         altogether if the TO field is empty.
+
+         FWDORIG
+         -------
+
+         This control line contains the address of the original sender as found
+         in the ORIG field of the original message. The usual 5D ASCII notation
+         (zone:net/node.point@domain) should be used. This control line should
+         be omitted altogether if the address is not known.
+
+         FWDDEST
+         -------
+
+         This control line contains the address of the original recipient as
+         found in the DEST field of the original message. The usual 5D ASCII
+         notation (zone:net/node.point@domain) should be used. This control line
+         should be omitted altogether if the address is not known or unsure
+         (as it is the case with forwarded echomail messages).
+
+         FWDSUBJ
+         -------
+
+         This control line contains the subject line of the original message.
+         This control line should be omitted altogether if the SUBJ field is
+         empty.
+         This control line should by made optional for security reasons. Echo
+         manager passwords are too easily revealed with it.
+
+
+         FWDAREA
+         -------
+
+         This control line contains the name of the echomail area where the
+         original message was forwarded from. It should be omitted altogether
+         if the original message was not forwarded from an echomail area.
+
+         FWDMSGID
+         --------
+
+         This control line contains the MSGID control line of the original
+         message. It should be omitted altogether if a MSGID control line is not
+         present in the original message.
+
+
+   Usage:
+
+         When the "forward" function of the message editor is invoked, the
+         editor program should generate the proposed control lines from the
+         header of the original message. If the original message already was
+         a forwarded one (indicated by the presence of at least a FWDORIG
+         control line), the editor should keep all FWD* control lines and should
+         not add any FWD* control lines. This preserves the FWD* control lines
+         of the first forwarder, containing the header data of the author of
+         the original message.
+
+         The editor should not generate FWD* control lines, if the message isn't
+         to be forwarded. A mail forwarding robot may also generate these
+         control lines, if it not just readdresses the message.
+
+         When the "reply" function of the editor is invoked the program should
+         use the control lines' contents instead of the header information. The
+         control lines should not be included in the reply.
+
+         Since it may not be immediately clear whether the user wants to reply
+         to the forwarder or to the original sender, the editor should offer a
+         means to ignore the proposed control lines and start a "normal" reply
+         instead, e.g. by two distinct functions, user preference or dialog.
+
+
+         Pseudo code:
+
+         forwarding_message:
+            if is_forwarded_message then
+               don't change FWD* control lines
+            else
+               add FWD* control lines
+
+         quoting_message:
+            if is_forwarded_message then
+               if reply_to_forwarder then
+                  use header data (normal quoting)
+               else
+                  use FWD* control lines
+               remove FWD* control lines from reply
+            else
+               use header data (normal quoting)
+
+         other_functions:
+            remove/ignore FWD* control lines
+
+
+   Example:
+
+         Message from Joe User to my boss node:
+
+            From: Joe User 1:234/567
+            To:   Harry Herrmannsdoerfer 2:2490/2520
+            Subj: Some questions
+            @MSGID: 1:234/567 12345678
+            Text: Hello Harry!
+                  ...
+
+         Harry forwards the message to me:
+
+            From: Harry Herrmannsdoerfer 2:2490/2520
+            To:   Michael Hohner 2:2490/2520.17
+            Subj: Joe's message
+            @FWDFROM Joe User
+            @FWDORIG 1:234/567
+            @FWDTO   Harry Herrmannsdoerfer
+            @FWDDEST 2:2490/2520
+            @FWDSUBJ Some questions
+            @FWDMSGID 1:234/567 12345678
+            Text: Hi Michael!
+                  ...
+
+         My answer using the new control lines:
+
+            From: Michael Hohner 2:2490/2520.17
+            To:   Joe User 1:234/567
+            Subj: Some questions
+            @REPLY: 1:234/567 12345678
+            Text: Hi Joe!
+
+                  JU> ...
+                  ...
+
+
+   Compatiblity:
+
+         Editor programs which are not prepared for the proposed control lines
+         usually just ignore them and remove them from a reply. A reply goes
+         to the forwarder. Nothing gained and nothing lost.
+
+
+   Implementations:
+
+         This proposal is implemented in the author's Fidonet editor
+         "FleetStreet for OS/2" (versions 1.17 and above).
+
+
+   Contacting the author:
+
+         The author may be contacted electronically at the following addresses:
+
+         Fidonet:    2:2490/2520.17
+         Internet:   miho@osn.de
+         CompuServe: 100425,1754
+
+         Suggestions, comments and corrections are always welcome.
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0093.html b/html/ftsc/fsc-0093.html new file mode 100755 index 00000000..ea3f2302 --- /dev/null +++ b/html/ftsc/fsc-0093.html @@ -0,0 +1,156 @@ + + +Reduced seen-by lines. + + + + +
+ | Document: FSC-0093
+ | Version:  001
+ | Date:     13 September, 1996
+ | Title:    Reduced seen-by lines
+ | Author:   Frank Ellermann, 2:240/5815.1
+
+
+  Reduced seen-by lines
+  Frank Ellermann, 2:240/5815.1
+
+
+  Abstract
+  --------
+  A way to save great amounts (estimated 10 %) of echo mail traffic by
+  reducing "seen by" informations, compatible with existing echo mail
+  tossers conforming to FTS-0004.
+
+
+  Definitions
+  -----------
+  A thorough understanding of FTS-0004 is required, the reader should
+  be familiar with PATH and SEEN-BY lines in echo mail, illegal and
+  legal echo mail distribution topologies, i.e. dup-rings, as well
+  as with some pre-requisite knowledge of zones, 4D and 2D addresses,
+  and the "sticky" 2D notation in PATH and SEEN-BY lines.
+
+  PATH: path lines as specified in FTS-0004
+  FSB:  full seen-by informations as specified in FTS-0004
+  TSB:  tiny seen-by informations as mentioned in FTS-0004, see below
+  RSB:  reduced seen-by informations specified below
+  dupe: multiple arrival of the same echo mail (e.g. different paths)
+
+
+  Examples of echo mail distribution topologies
+  ---------------------------------------------
+  In all examples a) to d) echo mail entered at system 1 is sent to
+  systems 2 and 3 with FSB 1 2 3. Therefore system 2 (3) knows, that
+  system 3 (2) already got this mail, topology a) is perfectly legal.
+
+  a) 1 - 3  b) 1 - 3  c) 1 - 3  d) 1 - 2
+     | /       |   |     | / |     | X |
+     2         2 - 4     2 - 4     2 - 4
+
+  In the exanmples b) and c) both systems 2 and 3 forward all mails
+  from system 1 to system 4, these topologies contain a dup-ring and
+  are therefore illegal following FTS-0004.
+
+  The examples a) and d) show fully connected polygons with three or
+  four nodes. In example d) a mail entered at system 1 is sent to
+  systems 2, 3, and 4 with FSB 1 2 3 4. The topologies a) and d) are
+  perfectly legal, there are no dupes caused by distribution.
+
+  In example b) each mail entered at system 1 reaching system 4 via
+  system 2 carries FSB 1 2 3 4, therefore system 4 will not forward
+  such mails to 3. Using TSB at system 2 the same mails would carry
+  TSB 2 4, therefore system 4 would forward them to 3 as dupes.
+
+  Note that illegal topologies as in example b) and c) cause dupes
+  with either FSB or TSB. The real problem with TSB is example b),
+  as it allows for loop mails on the dup-ring 1 - 2 - 3 - 4 - ...
+  and vice versa, if no additional checks for dupes are employed.
+
+  With RSB (specified below) systems contained in the PATH are not
+  stripped from the seen-by informations, therefore RSB avoid loop
+  mail much like FSB.
+
+
+  FSB algorithm
+  -------------
+  1) add own system to the PATH.
+  2) all area links not contained in the FSB qualify as recipients.
+  3) add own address(es) to the FSB set if not already contained.
+  4) add recipients to FSB, sort FSB, forward mail to recipients.
+
+
+  TSB algorithm
+  -------------
+  1) add own system to the PATH.
+  2) all area links not contained in the TSB qualify as recipients.
+  3) strip old TSB and start new TSB with own address(es).
+  4) add recipients to TSB, sort TSB and forward mail to recipients.
+
+
+  RSB algorithm
+  -------------
+  1) add own system to the PATH.
+  2) all area links not contained in the RSB qualify as recipients.
+  3) strip RSB addresses not matching an address in the PATH, then
+     add own address(es) to the RSB set if not already contained.
+  4) add recipients to RSB, sort RSB and forward mail to recipients.
+
+
+  PATH considerations
+  -------------------
+  There are 2 problems with the PATH kludge as specified in FTS-0004:
+
+  First like in the FSB the addresses in the PATH are 2D, and having
+  the same 2D address in different zones is possible. Therefore zone
+  gates are required to use the TSB algorithm. Unfortunately the PATH
+  is forwarded without regarding zone gating, therefore detection of
+  loop mail based solely on the PATH could be erroneous.
+
+  Further FTS-0004 (written 1989) expects future echo mail tossers to
+  implement PATH support, but doesn't require this support from old
+  implementations. Strictly spoken the PATH is still only an option.
+
+  In some areas of FidoNet (e.g. in zone 2) at least all non-terminal
+  nodes are required to fully support the PATH line, therefore this
+  problem will probably not show up in praxis. Of course any tosser
+  implementing the RSB feature is required to fully support the PATH.
+
+
+  Summary
+  -------
+  To show the benfits of RSB compared with FSB assume the following:
+
+  An echo mail travels from node to echo hub, host, major star, echo
+  host, hub, and finally arrives at a recipient. Each routing system
+  has 10 links, i.e. FSB at the recipient contain 51 addresses, about
+  400 characters, but RSB only 15 addresses in about 150 characters.
+
+  Therefore in an echo mail with 2500 characters about 10 % of its
+  size can be reduced using RSB in favour of FSB. If this estimation
+  is applicable on world wide FidoNet echo mail traffic, RSB can save
+  us an immense amount of costs.
+
+  This document can be adopted by the FTSC as FTS, in this case it
+  has to be regarded as an addition to FTS-0004 with the extension,
+  that all non-terminal nodes are required to support PATH lines as
+  specified in FTS-0004.
+
+  For additional informations (e.g. aspects of zone gating) feel free
+  to send mails to Frank Ellermann 2:240/5815 or leo@bfispc.hanse.de
+
+- eof -
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1001.html b/html/ftsc/fsp-1001.html new file mode 100755 index 00000000..9faa08a6 --- /dev/null +++ b/html/ftsc/fsp-1001.html @@ -0,0 +1,210 @@ + + +Timezone information in FTN messages. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1001
+Revision:       2
+Title:          Timezone information in FTN messages
+Author:         Odinn Sorensen, 2:236/77
+Revision Date:  27 September 1997
+Expiry Date:    13 September 1999
+----------------------------------------------------------------------
+Contents:
+                1. Scope
+                2. Current practice
+                3. Kludge specification
+                4. Timezone table
+                5. Examples
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  Current practice for Fidonet Technology Network (FTN) messages is to
+  store dates in local time. Timezone information (if known) is
+  usually lost. This document specifies a standard for storage of
+  timezone information in FTN messages, in the form of a kludge named
+  TZUTC.
+
+
+1. Scope
+--------
+
+  This standard is specified for FTN messages in any form where
+  timezone information is not integrated in the message storage or
+  transport format. Specifically any form where the information would
+  be lost if not stored in a kludge, such as in FTS-1 stored messages
+  or packets.
+
+
+2. Current practice
+-------------------
+
+  Some kludges already exist to specify the timezone of messages,
+  notably "TZUTC" and "TZUTCINFO". Other kludges may exist.
+
+  To the authors knowledge, no official specification exists for any
+  of these kludges.
+
+  From observations of these kludges in actual messages, TZUTC and
+  TZUTCINFO are identical except for the name. TZUTCINFO is probably
+  named after the JAM msgbase subfield of the same name.
+
+  This document adopts and documents the TZUTC kludge because it is
+  the shortest of them.
+
+
+3. Kludge specification
+-----------------------
+
+  Messages which conform to this specification must add the kludge:
+
+    ^aTZUTC: 
+
+  The offset has the format <[-]hhmm>, where hhmm is the number of
+  hours and minutes that local time is offset from UTC. If local time
+  is WEST of UTC (Greenwich), then the offset is NEGATIVE. See the
+  table below for typical offsets.
+
+  Note that the hh in a timezone offset is not limited to a maximum of
+  12. This is because the International Date Line does not run exactly
+  along the boundary between zone -1200 and +1200. The minutes part is
+  00 for most timezones.
+
+  All four digits must be present. If the offset is negative, there
+  must be a minus ('-', ASCII 45, 2Dh) in front of the offset.
+
+  Implementations must NOT put a plus ('+', ASCII 43, 2Bh) in front of
+  the offset for positive numbers, but robust implementations should
+  be prepared to find (and ignore) a plus if it exists.
+
+  If local time changes as a result of, for example, daylight savings
+  time, then the offset in TZUTC need to be changed to reflect this.
+
+  When this kludge is present in a message, the "date written" field
+  in the stored message is guaranteed to be in local time for the
+  given timezone. Note that this specification does not specify the
+  timezone for any other date fields. Other date fields (such as "date
+  received, arrived, processed, etc.") are usually in local time for
+  the system on which the messages are stored.
+
+
+4. Timezone table
+-----------------
+
+  This table gives examples of typical timezones.
+
+  -1000   Alaska-Hawaii Standard Time
+  -0900   Hawaii Daylight Time
+  -0800   Pacific Standard Time
+  -0700   Pacific Daylight Time
+  -0700   Mountain Standard Time
+  -0600   Mountain Daylight Time
+  -0600   Central Standard Time
+  -0500   Central Daylight Time
+  -0500   Eastern Standard Time
+  -0400   Eastern Daylight Time
+  -0400   Atlantic Standard Time
+  -0330   Newfoundland Standard Time
+  -0300   Atlantic Daylight Time
+  -0100   West Africa Time
+   0000   Greenwich Mean Time
+   0100   Central European Time
+   0100   British Summer Time
+   0200   Central European Summer Time
+   0200   Eastern European Time
+   0800   Australian Western Time
+   0800   China Coast Time
+   0900   Japan Standard Time
+   0900   Australian Western Daylight Time
+   0930   Australian Central Standard Time
+   1000   Australian Eastern Standard Time
+   1030   Australian Central Daylight Time
+   1100   Australian Eastern Daylight Time
+   1200   New Zealand Standard Time
+   1300   New Zealand Daylight Time
+
+
+5. Examples
+-----------
+
+  ^aTZUTC: 0000
+  ^aTZUTC: 0200
+  ^aTZUTC: -0700
+
+
+6. Redundancy
+-------------
+
+  If the TZUTC data duplicates a field in a storage format in such a
+  way that no information is lost in conversion to or from the field,
+  then it is recommended that the kludge is not stored in the message.
+  However, implementations are allowed to store the TZUTC even when
+  redundant.
+
+
+A. References
+-------------
+
+  [FTS-1] "A Basic FidoNet(r) Technical Standard Revision 16", Randy
+  Bush. September 1995.
+
+  [JAM] "The JAM message base proposal", Joaquim Homrighausen, Andrew
+  Milner, Mats Birch and Mats Wallin. July 1993.
+
+
+B. Author contact data
+----------------------
+
+  Odinn Sorensen
+  Fidonet: 2:236/77
+  E-mail:  odinn@goldware.dk
+  WWW:     http://www.goldware.dk
+
+
+C. History
+----------
+
+  Rev.1, 970913: First release.
+  Rev.2, 970927: Updated the timezone table. Added section about
+                 redundancy. Clarified what happens when local time
+                 changes. Clarified some of what the specification
+                 doesn't cover.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1002.html b/html/ftsc/fsp-1002.html new file mode 100755 index 00000000..808b7da2 --- /dev/null +++ b/html/ftsc/fsp-1002.html @@ -0,0 +1,140 @@ + + +Numeric reply indication in FTN subject lines. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1002
+Revision:       2
+Title:          Numeric reply indication in FTN subject lines
+Author:         Odinn Sorensen, 2:236/77
+Revision Date:  19 October 1997
+Expiry Date:    11 October 1999
+----------------------------------------------------------------------
+Contents:
+                1. Scope
+                2. Format
+                3. Reply procedure
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  When making a reply to a message, there are currently three common
+  ways to handle the subject line:
+
+  1. Don't change it.
+  2. Insert the string "Re: " in front of it.
+  3. Insert the string "Re^n: " in front of it, where 'n' is increased
+     by one if the original subject was already a reply.
+
+  This document concerns itself with specifying the third variant.
+
+
+1. Scope
+--------
+
+  This standard is specified for all FTN messages. Implementations
+  will typically be message editors and other software that creates
+  replies to messages.
+
+
+2. Format
+---------
+
+  The format is "Re^n: ", where n is an unsigned integer number with
+  one or more digits. The range of the number must be at least 0 to
+  255. Negative numbers are not allowed. Note that there must be a
+  space after the colon. The letters are not case sensitive, but
+  uppercase 'R' and lowercase 'e' is recommended.
+
+
+3. Reply procedure
+------------------
+
+  When making a reply that conforms to this specification, this
+  procedure, or a functionally identical one, must be followed:
+
+  1. If the original subject does not have a leading "Re: " or
+     "Re^n: ", put the string "Re: " in front of it. Don't use a
+     number here.
+
+     Example:   "Hello world"  ->  "Re: Hello world"
+
+  2. If the original subject has a leading "Re: ", put the string
+     "Re^2: " in front of the subject.
+
+     Example:   "Re: Hello world"  ->  "Re^2: Hello world"
+
+  3. If the original subject has a leading "Re^n: ", increase the
+     number 'n' by one and modify the subject accordingly.
+
+     Example:   "Re^4: Hello world"  ->  "Re^5: Hello world"
+
+  Notes:
+
+  * The numbers 0 and 1 should not occur in the "Re^n: " string under
+    normal circumstances, but a robust implementation should just
+    increase the number in any case.
+
+  * The number should not be increased beyond the range of the number
+    type used in the implementation, or in other words, it should not
+    roll around to zero. If it can't be increased, leave it alone.
+
+  * When inserting the "Re: " or "Re^n: " string in front of the
+    subject, information from the end might be lost, because the
+    message storage or packet formats use fixed length subject fields.
+    Intelligent subject-based reply linking software should be aware
+    of this and try to link correctly anyway.
+
+
+A. Author contact data
+----------------------
+
+  Odinn Sorensen
+  Fidonet: 2:236/77
+  E-mail:  odinn@goldware.dk
+  WWW:     http://www.goldware.dk
+
+
+B. History
+----------
+
+  Rev.1, 971011: First release.
+  Rev.2, 971019: Added note that "Re" is not case sensitive.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1003.html b/html/ftsc/fsp-1003.html new file mode 100755 index 00000000..f7ed6040 --- /dev/null +++ b/html/ftsc/fsp-1003.html @@ -0,0 +1,116 @@ + + +Suggested use of Nodelist Fields. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1003
+Revision:       1
+Title:          Suggested use of Nodelist Fields
+Author:         Lee Kindness
+Revision Date:  15 May 1997
+Expiry Date:    15 May 1999
+----------------------------------------------------------------------
+Contents:
+                1. Field 3, Node Name
+                2. Field 4, Location
+                3. Field 5, Sysop Name
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Introduction
+------------
+
+  This document makes recommendations on the use of various fields in
+  the distribution nodelist (St. Louis nodelist format", fts-0005).
+  Naturally it is the choice of the *C's if they want to use them.
+  Remember the fts-0005 requirements should still be adhered to.
+
+
+1. Field 3, Node Name
+---------------------
+
+  The node name field should be no more than 20 characters long. For
+  comparison in nodelist.122'1997 the minimum entry was 1, maximum 51!
+  and the average was 14.
+
+  For zone entries this field should contain a description of the
+  zones area, (eg North America, Europe). For region entries it should
+  contain the country/state, for host entries the local area name and
+  for hub entries a description of the area the hub serves.
+
+
+2. Field 4, Location
+--------------------
+
+  This field contains the location of the node. It should usually be
+  expressed as the primary local location (town, suburb, city, etc.)
+  plus an identifier of the regional geopolitical administrative
+  district (state, province, department, county, etc.). Wherever
+  possible, standard postal abbreviations for the major regional
+  district should be used (IL, BC, NSW, UK, etc.).
+
+  For zone and region entries this field should also have the julian
+  day of segment creation appended to it (eg "Somearea_(122)") to aid
+  checks on the validity of the nodelist.
+
+
+3. Field 5, Sysop Name
+----------------------
+
+  This field contains the name of the system operator. Entries such as
+  "postmaster" and "uucp" should not be used. Aliases should not be
+  permitted in this field (as they give Fidonet a 'less respectable'
+  image).
+
+
+A. Author contact data
+----------------------
+
+  Lee Kindness
+  Fidonet: n/a
+  E-mail:  wangi@earthling.net
+  WWW:     http://www.scms.rgu.ac.uk/students/cs_yr94/lk/fido.html
+
+
+B. History
+----------
+
+  Rev.1, 971101: First release as FSP, based on the Fidonews 14/20
+                 article. Transformed into FSP document by Odinn
+                 Sorensen.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1004.html b/html/ftsc/fsp-1004.html new file mode 100755 index 00000000..df485037 --- /dev/null +++ b/html/ftsc/fsp-1004.html @@ -0,0 +1,257 @@ + + +Standard FidoNet Addressing. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1004
+Revision:       1
+Title:          Standard Fidonet Addressing
+Author:         Lee Kindness
+Revision Date:  15 May 1997
+Expiry Date:    15 May 1999
+----------------------------------------------------------------------
+Contents:
+                1. Standard Fidonet Addressing
+                2. Internet Gateway Addressing
+                3. Routing Address Syntax
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Introduction
+------------
+
+  This document describes the standard form of addressing in Fidonet
+  today along with the common method of addressing via internet
+  gateways. In addition it proposes an extended addressing syntax,
+  useful for routing purposes. This is a draft for comments and
+  suggestions.
+
+
+1. Standard Fidonet Addressing
+------------------------------
+
+  Fidonet addressing uses the following format:
+
+    ZZ:NN/FF.PP@DO
+
+  where the fields refer to...
+
+  ZZ - Zone Number:  The zone the node is part of.
+                     Min: 1 Max: 32767
+                     If 'ZZ:' is missing then assume 1 as the zone.
+
+  NN - Net Number:   The network the node is a member of.
+                     Min: 1 Max: 32767
+                     Must be present.
+
+  FF - Node Number:  The actual node number.
+                     Min: -1 Max: 32767
+                     Must be present.
+
+  PP - Point Number: If the system is a point rather than a node then
+                     this is their point number off the node.
+                     Min: 0 Max: 32767
+                     If '.PP' is missing then assume 0 (ie not a
+                     point) as the point number.
+
+  DO - Domain:       The name of the 'Fidonet Technology Network'.
+                     Maximum length of 8 characters. The domain
+                     should not include periods, thus 'fidonet.org'
+                     is invalid (should be fidonet).
+                     If '@DO' is missing then fidonet can be assumed.
+
+  The following are all valid examples:
+      1:234/5.6@fidonet  (a '5D' address)   => 1:234/5.6@fidonet
+      2:34/6.78          (a '4D' address)   => 2:34/6.78@fidonet
+      4:610/34           (a '3D' address)   => 4:610/34.0@fidonet
+      123/45             (a '2D' address)   => 1:123/45.0@fidonet
+      955:95/2@othernet  (another FTN)      => 955:95/2.0@othernet
+      2:259/-1           (node application) => 2:259/-1.0@fidonet
+
+  The limits on each various part of the address are a result of
+  fts-0005 (zone, net, node, point), fsc-0045 (domain) and Policy 4
+  (-1 node address for node application).
+
+
+2. Internet Gateway Addressing
+------------------------------
+
+  An internet user can send email/netmail to a fidonet user via one of
+  the fidonet->internet gateway systems (it's out-with the scope of
+  this document to describe the semantics of posting). The internet
+  user would send an email to a Fidonet user by using an email address
+  of the following syntax:
+
+    user.name@pPP.fFF.nNN.zZZ.gateway.domain
+
+  where the fields refer to...
+
+  user.name - Name:         Name of the user the email is being sent
+                            to, spaces replaced by periods.
+
+  PP        - Point Number: As Fidonet address (FA)
+                            If '.pPP' is missing 0 is assumed.
+
+  FF        - Node Number:  As FA
+                            Must be present.
+
+  NN        - Net Number:   As FA
+                            Must be present.
+
+  ZZ        - Zone Number:  As FA
+                            Must be present.
+
+  gate.way  - Gateway:      Internet domain of the gateway, for
+                            example 'fidonet.org'.
+                            Must be present.
+
+  The following are all valid examples (assuming 'fidonet.org' is an
+  internet gateway):
+
+    joe.bloggs@p6.f5.n234.z1.fidonet.org  => 1:234/5.6@fidonet
+    harry.cat@p78.f6.n34.z2.fidonet.org   => 2:34/6.78@fidonet
+    i.be.jolly@f34.n610.z4.fidonet.org    => 4:610/34.0@fidonet
+
+  and if 'foo.bar.org.uk' is a gateway for 'othernet':
+
+    louise.hat@f2.n95.z955.foo.bar.org.uk => 955:95/2.0@othernet
+
+
+3. Routing Address Syntax
+-------------------------
+
+  The two previous address types (Fidonet and Internet->Fidonet
+  gateway) are common practice, this however is a suggested standard
+  of addressing for routing tables. The routing address has the
+  following syntax:
+
+    DD:ZZ:RR:NN:HH:FF:PP
+
+  where the fields refer to:
+
+  DD - Domain:        As FA
+                      Must be present, even if blank (ie a leading
+                      ':') to ensure we always have 6 ':'s in an
+                      address to aid pattern matching.
+
+  ZZ - Zone Number:   As FA
+                      Must be present.
+
+  RR - Region Number: The region (from fts-0005 nodelist) that the
+                      following network is in.
+                      Min: 1 Max: 32767
+                      Must be present.
+
+  NN - Net Number:    As FA
+                      Must be present.
+
+  HH - Hub:           The hub (from fts-0005 nodelist) that the node
+                      is under, or 0 (host hub).
+                      Min: 1 Max: 32767
+                      Must be present.
+
+  FF - Node Number:   As FA
+                      Must be present.
+
+  PP - Point Number:  As FA
+                      Must be present.
+
+  ':' has been chosen as the separator as it is not a POSIX regular
+  expression character or globing character (where as '.' is) and thus
+  always easy use of wildcards on the address. The following points
+  should be noted:
+
+    1. All addresses have 6 ':'s
+    2. The domain is at the front, the address gets more specific to
+       the right
+    3. Nodes have 0 as their point number
+    4. A zone net has identical zone, region and net fields
+    5. A region net has identical region and net fields
+
+  Example fidonet addresses converted to routing addresses:
+
+    fidonet:2:25:259:0:7:0 => 2:259/7.0@fidonet, region 25, hub 0
+    fidonet:1:1:1:0:23:0   => 1:1/23.0@fidonet, zone 1 net
+    :955:9551:95:300:45:0  => 955:95/45.0, region 9551, hub 300
+    fidonet:2:25:25:0:0:0  => 2:25/0.0@fidonet, R25C
+    cnet:12:34:341:100:1:7 => 12:341/1.7@cnet, region 34, hub 100
+    :2:25:259:300:300:0    => 2:259/300.0, region 25, hub 300
+
+  Example POSIX regular expression patterns on routing addresses:
+
+    [a-z]*:[0-9]+:[0-9]+:[0-9]+:[0-9]+:[0-9]+:[0-9]+ (any address)
+    [a-z]*(:[0-9]+)+                                 (any address)
+    fidonet:2:25:[0-9]+:[0-9]+:[0-9]+:[0-9]+      (region 25 node)
+    fidonet:2:25(:[0-9]+)+                        (region 25 node)
+    fidonet:1:12:125(:[0-9]+)+               (all net 1:125 nodes)
+    fidonet:1:12:125:200(:[0-9]+)+   (all hub 1:125/200 downlinks)
+    fidonet:1:12:125:200:2:[0-9]+             (all 1:125/2 points)
+    fidonet:1:12:125:[0-9]+:(25|34|56):0
+                     (nodes 1:125/25.0, 1:125/34.0 and 1:125/56.0)
+
+  Example 'DOS style' patterns on routing addresses:
+
+    *:*:*:*:*:*:*                                    (any address)
+    fidonet:2:25:*:*:*:*                          (region 25 node)
+    fidonet:1:12:125:*:*:*                   (all net 1:125 nodes)
+    fidonet:1:12:125:200:*:*         (all hub 1:125/200 downlinks)
+    fidonet:1:12:125:200:2:*                  (all 1:125/2 points)
+    fidonet:1:12:125:*:3*:0  (any net 1:125 nodes starting with 3)
+    fidonet:1:12:125:*:3?:0           (net 1:125 nodes 30 thru 39)
+
+  The standard doesn't define which standard of pattern matching to
+  use, only the format of the addresses. These routing addresses would
+  be used in routing tables and configurations.
+
+
+A. Author contact data
+----------------------
+
+  Lee Kindness
+  Fidonet: n/a
+  E-mail:  wangi@earthling.net
+  WWW:     http://www.scms.rgu.ac.uk/students/cs_yr94/lk/fido.html
+
+
+B. History
+----------
+
+  Rev.1, 971101: First release as FSP, based on the Fidonews 14/20
+                 article. Transformed into FSP document by Odinn
+                 Sorensen.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1005.html b/html/ftsc/fsp-1005.html new file mode 100755 index 00000000..5c035533 --- /dev/null +++ b/html/ftsc/fsp-1005.html @@ -0,0 +1,450 @@ + + +Zone 2 nodelist flags. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1005
+Revision:       6
+Title:          Zone 2 nodelist flags
+Author:         Frank Ellermann, 2:240/5815.1
+Revision Date:  27 November 1997
+Expiry Date:    27 November 1999
+---------------------------------------------------------------------
+Contents:
+                1. Introduction
+                2. FTS-0005 flags
+                3. User flags
+                4. Approved zone 2 user flags
+                5. Flag implications
+                6. Invalid combinations
+                7. Baud rate field
+                8. Thanks to...
+---------------------------------------------------------------------
+
+
+1. Introduction
+---------------
+   This document informs about known differences of FidoNet zone 2
+   nodelist flags from FTS-0005.003.  The ultimate sources for these
+   informations are the current Z2 nodelist epilogue and the setup
+   for flag corrections at Z2C, but it may be difficult to get these
+   sources for readers in other zones.
+
+|  All changes since version 5 are marked by a bar at the left edge.
+   It is (again) possible to list V32b and V42b in zone 2, upper case
+   V32B or V42B is not more enforced.  Currently new flags needed for
+   IP-connectivity are under test in zone 2 (only internally), e.g.
+
+   ->   VM      VModem, default port  3141, dummy country code 000-
+   ->   IFC     IFCico, default port 60179, dummy country code 000-
+   ->   BND     BinkP,  default port 24544, dummy country code 000-
+   ->   IP      general IP connectivity,    dummy country code 000-
+   ->   TELN    Telnet                      dummy country code 000-
+
+
+2. FTS-0005 flags
+-----------------
+   The following flags are used as specified in FTS-0005.003:
+
+        CM      Continuous Mail, node accepts mail 24 hours a day
+        MO      Mailer Only (no BBS)
+        LO      Listed Only, node accepts calls only from listed
+                node numbers in the current FidoNet nodelist
+
+   ->   V21     ITU-T V21      300 bps full duplex (obsolete)
+        V22     ITU-T V22     1200 bps full duplex (obsolescent)
+
+|  In zone 2 the value 1200 in the baud rate field implies V22.  Only
+|  two nodes not supporting at least V22bis, ISDN, or IP still exist
+|  in the zone 2 segment.  Flag V22 is almost obsolete, and V21 is
+|  already removed in Z2.  Both flags should be dropped from the next
+|  FTS-0005 version.
+
+        V29     ITU-T V29     9600 bps half duplex (obsolescent)
+   ->   V33     ITU-T V33    14400 bps half duplex (obsolete)
+
+   V33 cannot be used in connecting FidoNet nodes over public dial-up
+   lines and is most probably a historical error in FTS-0005.  A very
+   similar argument is applicable on V29, all nodes flying this flag
+   support at least V32.  Today only one node in Z2 still flies V29,
+   and V33 is already removed in Z2.  Both flags should be dropped in
+   the next FTS-0005 version.
+
+        V32     ITU-T V32     9600 bps full duplex
+        V32b    ITU-T V32bis 14400 bps full duplex (implies V32)
+|       V34     ITU-T V34    28800 bps full duplex (33600 bps option)
+
+   FTS-0005 specifies V32b and V42b (capital V and small b), current
+   nodelist practice in FidoNet shows all combinations of small and
+   capital letters for flags.  This was no problem before FSC-0062
+   introduced case-sensitive flags.  The best solution is to stick to
+   the current practice and treat all old flags as case-insensitive.
+
+        H96     Hayes V9600
+        HST     USR Courier HST up to 9600  (implies MNP)
+        H14     USR Courier HST up to 14400 (implies HST)
+   ->   H16     USR Courier HST up to 16800 (implies H14 and V42b)
+        MAX     Microcom AX/96xx series (almost obsolete)
+        PEP     Packet Ensemble Protocol
+        CSP     Compucom Speedmodem
+   ->   ZYX     Zyxel series 16800 bps (implies V32b and V42b)
+   ->   V32T    V.32 Terbo   19200 bps (implies V32b)
+        VFC     V.Fast Class 28800 bps (should imply V32b and V42b)
+
+   If a flag directly or indirectly implies other flags, then these
+   other flags are not shown in a nodelist entry, because this would
+   be redundant.  Unfortunately the rules for redundancies in zone 2
+   and FTS-0005 are different.  Zone 2 continued to avoid redundancy
+   with most "new" flags, but FTS-0005.003 specified no redundancies
+   for "new" flags like ZYX, H16, V32T, or VFC.  "New" flags in this
+   context are flags approved by FidoNet International Coordinators
+   since 1989, when FTS-0005.TXT, the predecesssor of FTS-0005.003,
+   was published.
+
+   For details see the chapter "implications" below, for now only
+   note, that in zone 2 H16 implies V42b, ZYX implies V32b and V42b,
+   and V32T implies V32b.
+
+   Zone 1 and zone 2 have introduced a user flag Z19 approved by the
+   corresponding Zone Coordinator.  User flags are discussed later,
+   for now only note, that in zone 2 ZYX is specified as Zyxel 16k8,
+   while FTS-0005.003 not knowing Z19 specifies ZYX as generic flag
+   for all Zyxel protocol speeds.
+
+   Today only one node in FidoNet still really flies MAX, this flag
+   is obsolete and should be dropped from FTS-0005.  The flags CSP
+   (7 nodes worldwide) and H96 should be marked as obsolescent.
+
+|       MNP     Microcom Networking Protocol 2-4 error correction
+|       V42     ITU-T LAP-M error correction w/ fallback to MNP 2-4
+|       V42b    ITU-T V.42bis BTLZ data compression over V.42 LAP-M
+
+   The next version of FTS-0005 should adopt the better V42b and
+   MNP definitions of the zone 3 nodelist epilogue.  FTS-0005.003
+   specifies an implication of V42 by V42b, but the exact meaning of
+   the flag MNP is unclear.  Most probably this flag was meant to
+|  indicate support of MNP 2-4, and in this sense V42 implies MNP.
+
+|  Note the difference between the flag V42b (implying V42) and the
+|  standard V.42bis (not necessarily based on LAP-M as data link
+|  layer protocol), without this difference the flag V42b would be
+|  ambiguous for combined modem and ISDN node entries.
+
+        MN      No compression supported in insecure inbound
+
+        XA      Bark and WaZOO file/update requests
+        XB      Bark file/update requests, WaZOO file requests
+        XC      Bark file requests, WaZOO file/update requests
+        XP      Bark file/update requests
+        XR      Bark and WaZOO file requests
+        XW      WaZOO file requests
+        XX      WaZOO file/update requests
+
+   These flags are equivalent in FTS-0005 and in the zone 2 segment.
+
+        Gx..x   Gateway to domain 'x..x'
+
+   Valid values for this flag are assigned by the Fido International
+   Coordinator, FTS-0005.003 explicitly mentions GUUCP.  In zone 2
+   only GUUCP gateways are flagged.
+
+        #01     Zone 5 mail hour (01:00 - 02:00 UTC) w/ Bell 212A
+        #02     Zone 2 mail hour (02:30 - 03:30 UTC) w/ Bell 212A
+   ->   #08     Zone 4 mail hour (08:00 - 09:00 UTC) w/ Bell 212A
+        #09     Zone 1 mail hour (09:00 - 10:00 UTC) w/ Bell 212A
+        #18     Zone 3 mail hour (18:00 - 19:00 UTC) w/ Bell 212A
+        #20     Zone 6 mail hour (20:00 - 21:00 UTC) w/ Bell 212A
+
+   The variants !01, !02, !08, !09, !18, and !20 indicate missing
+   Bell 212A support.  In zone 2 #02 or !02 would be obviously
+   redundant.
+
+   Today less than four 1200 modems (V22 or Bell 212A) are listed.
+   A future version of FTS-0005 should drop !mn variants together
+   with V21 and V22 flags.
+
+   Further most non-CM systems flagging #mn or !mn today probably
+   want to show additional online times instead of additional mail
+   hours.  As soon as FSC-0062 flags have been approved by the IC
+   or adopted as FTS by the FTSC, the following version of FTS-0005
+   should mark #mn as obsolescent and recommend the more flexible
+   FSC-0062 flags (see below).
+
+
+3. User flags
+-------------
+   An example for one of several problems in zone 2 with user flags:
+
+        ...,U,Z19,V110H,V120L,V120H,X75,ENC,NEC
+
+   These flags indicate a modern Zyxel ISDN-modem and two additional
+   user flags ENC and NEC.  This possible user flags string contains
+   34 characters, but at most 32 characters are allowed in FTS-0005.
+
+        ...,U,Z19,V110L,V110H,X75,ISDNA,ISDNB,ISDNC
+
+   During the period for the replacement of old by new ISDN flags
+   (several months !) many nodes listed both old and new flags for
+   maximal compatibility, and no problems with nodelist compilers
+   or mailers caused by too long user flags strings were reported.
+
+   Therefore the length limit in FTS-0005 is probably unnecessary
+   and at least inconsequent:  Other nodelist fields like the system
+   name are unlimited, so why only restrict the user flags string ?
+   To help developpers an upper limit of e.g. 255 characters for a
+   nodelist line and 63 characters for fields 3 to 6 would be more
+   useful.
+
+   The next problem with user flag strings as specified in FTS-0005
+   is their introduction by the letter U with no comma following:
+
+   Nodelist compilers could parse ...,UISDN,USR in user flags ISDN
+   and USR.  But USR cannot be approved as "real" flag, because the
+   combination ...,USR,UISDN would then be parsed in SR and UISDN.
+
+   Other side effects of the FTS-0005 specification are additional
+   difficulties in finding flags.  Almost all flags are separated
+   by a comma, only the first user flag can be an exception to this
+   simple rule.  If the order of user flags has no meaning, then...
+
+        ...,UV120L,V120H
+        ...,UV120H,V120L
+
+   ... are equivalent.  A "simple" solution of this problem could be
+   to treat UV120L as synonym for V120L, and UV120H as synonym for
+   V120H.  Similar problems show up, if user flags are counted, etc.
+
+   Obviously a nodelist compiler looking for user flags has always
+   to consider the case "user flag separated by comma".  In zone 2
+   this idea was simply extended to the first user flag:
+
+   All flags are separated by commas.  Flags not yet approved by the
+   International Coordinator or the FTSC (i.e. user flags only used
+   experimentally or locally) are separated by a new pseudo flag U.
+
+   ->   U       pseudo flag to the left of at least one user flag
+
+   All flags following this pseudo flag U are user flags, all flags
+   before this pseudo flag are "real" flags specified in FTS-0005 or
+   approved by the International Coordinator.
+
+   Because this definition should be compatible with any reasonable
+   software implementation based on FTS-0005.003, and simplifies the
+   handling of user flags significantly, a future FTS-0005 version
+   will hopefully adopt it.
+
+
+4. Approved zone 2 user flags
+-----------------------------
+   In zone 2 user flags have to be approved by the Zone Coordinator.
+   Currently the following zone 2 user flags exist:
+
+   ->   V110L   ITU-T V.110 19k2 async 'Low'    (former ISDNA)
+   ->   V110H   ITU-T V.110 38k4 async 'High'   (former ISDNB)
+   ->   V120L   ITU-T V.120 56k6 async, N1 = 259, W = 7, modulo 8
+   ->   V120H   ITU-T V.120 64k  async, N1 = 259, W = 7, modulo 8
+   ->   X75     ITU-T X.75 SLP (single link procedure),
+                64kbit/s B channel; layer 2 max. framesize N1 = 2048,
+                window size W = 2, frame numbering modulo 8;
+                layer 3 transparent (no packet layer)
+   ->   ISDN    Other configuration, used only if none of above fits
+
+   These ISDN flags follow the specification in FSC-0091.
+
+   ->   Tyz     Online time flags as specified in FSC-0062
+
+   The flag Tyz is used by non-CM nodes online not only during ZMH,
+   y is a letter indicating the start and z a letter indicating the
+   end of the online period as defined below (times in UTC):
+
+        A  0:00,  a  0:30,   B  1:00,  b  1:30,   C  2:00,  c  2:30,
+        D  3:00,  d  3:30,   E  4:00,  e  4:30,   F  5:00,  f  5:30,
+        G  6:00,  g  6:30,   H  7:00,  h  7:30,   I  8:00,  i  8:30,
+        J  9:00,  j  9:30,   K 10:00,  k 10:30,   L 11:00,  l 11:30,
+        M 12:00,  m 12:30,   N 13:00,  n 13:30,   O 14:00,  o 14:30,
+        P 15:00,  p 15:30,   Q 16:00,  q 16:30,   R 17:00,  r 17:30,
+        S 18:00,  s 18:30,   T 19:00,  t 19:30,   U 20:00,  u 20:30,
+        V 21:00,  v 21:30,   W 20:00,  w 20:30,   X 23:00,  x 23:30.
+
+   For example TuB shows an online period from 20:30 until 1:00 UTC.
+
+   ->   Z19     Zyxel series 19200 bps (implies ZYX)
+   ->   X2C     x2 client w/ 56000 bps (should imply V34 and V42b)
+   ->   X2S     x2 server w/ 64000 bps (should imply V34 and V42b)
+
+   ->   K12     Systems offering all educational K12-conferences
+   ->   ENC     The node accepts inbound encrypted mail
+
+   ->   NC      Network Coordinator (only if the NC is not the host)
+   ->   NEC     Net Echomail Coordinator    (at most one per net)
+   ->   REC     Region Echomail Coordinator (at most one per region)
+
+   Redundant AKAs used to indicate echomail coordination in zone 2
+   are no longer permitted.  One *EC flag is valid for all AKAs of
+   a given sysop.
+
+
+5. Flag implications
+--------------------
+   Flag implications directly or indirectly specified in FTS-0005:
+
+        HST     => MNP
+        H14     => MNP HST
+        H16     => MNP HST H14
+        V42b    => V42 (MNP ?)
+        V32b    => V32
+
+   Flag implications specified in the zone 2 nodelist epilogue:
+
+        HST     => MNP
+        H14     => HST MNP
+   ->   H16     => V42 MNP V42b H14 HST
+   ->   V42b    => V42 MNP
+   ->   ZYX     => V42 MNP V42b V32 V32b
+   ->   Z19     => V42 MNP V42b V32 V32b ZYX
+        V32b    => V32
+   ->   V32T    => V32 V32b
+
+   ->   V110L   => ISDN
+   ->   V110H   => ISDN
+   ->   V120L   => ISDN
+   ->   V120H   => ISDN
+   ->   X75     => ISDN
+
+   The latter ISDN flag redundancies are a consequence of FSC-0091.
+   Maybe some of the following implications could be added in zone 2:
+
+        VFC     => V32 V32b MNP V42 V42b
+        X2C     => V34 MNP V42 V42b
+        X2S     => V34 MNP V42 V42b
+
+   Flag implications (i.e. not listing redundant flags) have several
+   advantages:  Some old nodelist tools are unable to handle too long
+   lines.  Old flags like HST, MNP, V42, or V32 vanish automatically,
+   if they are implied by H16, V42b, V32b, or better.  Redundancies
+   defined globally for the whole nodelist help to avoid flag errors.
+
+
+6. Invalid combinations
+-----------------------
+   All file request flags exclude each other (at most 1 is possible):
+   XA, XB, XC, XP, XR, XW, and XX.  For flag checkers only supporting
+   implications a good approximation based on FTS-0005 definitions is
+
+|       XA      => XW XR XP XB XC XX,
+|       XB      => XW XR XP,
+|       XC      => XW XR XX,
+|       XR      => XW,
+|       XX      => XW.
+
+   Further X2C cannot be combined with X2S, and FSC-62 Tyz-flags are
+   not possible with CM.  Also Tyz with y = z is of course incorrect.
+
+   Some modem protocols are "proprietary" in a sense, that all today
+   known modems can fly at most one of the corresponding modem flags:
+   MAX, CSP, H96, PEP, HST, H14, H16, ZYX, and Z19.
+
+   A few "old" modem protocol flags are known to be invalid if used
+   together with "new" protocol flags, i.e. each "old" flag excludes
+   all "new" flags and vice versa:
+
+   "Old" in this sense are MAX, CSP, H96, HST, H14, V32, and PEP.
+   "New" in this sense are X2S, X2C, V34, VFC, V32T, and H16.
+
+   For Z2 add ZYX as "old" and Z19 as "new".  A simple REXX script to
+   test some known inconsistencies is available as NLSCHECK.REX at
+   the site of the author.  While erroneously listing redundant flags
+   causes no harm, other errors like combining V34 with HST or Z19
+   with H16 indicate serious problems, which can result in connection
+   failures or other damage.
+
+
+7. Baud rate field
+------------------
+   The baud rate field 7 in the nodelist as specified in FTS-0005 is
+   nearly useless today:  Except from a few remaining 1200 and 2400
+   nodes almost all nodelist entries show either 9600 for all modem
+   protocols better than V22bis or 300 for ISDN (or IP) only nodes.
+   No more V21 or Bell 103 modems are listed for more than 2 years.
+
+   The baud rate values 19200 and 38400 specified in FTS-0005.003
+   have not been used in the FidoNet nodelist.  So all a reasonable
+   nodelist compiler can do today, is treat 300 as indicator for
+   ISDN or IP only, and treat unknown or missing values in field 7
+   like 9600.
+
+   A new meaning for field 7 as speed field could be really useful.
+   An example is ZYX, if we would have 16800, 19200, 28800, and 33600
+   as speed values, then their combination with ZYX is all we need
+   technically, Z19 would be unnecessary.  Another example is HST,
+   flags H14 and H16 are unnecessary, if HST is combined with 9600,
+   14400, 16800, 28800, or better.  Variants of PEP could be shown in
+   the speed field without new flags.  "Enhanced V32.terbo" could be
+   shown by 21600.
+
+   Most important:  V34 may have the famous bug not allowing connects
+   from new "V34+", unless the caller disabled symbol rate 3429.  If
+   "V34+" is indicated by speed 33600 or better, then an appropriate
+   setup for all kinds of V34 connects is possible.
+
+   A future version of FTS-0005 hopefully allows the following speed
+   values in field 7:
+
+          300   reserved for ISDN or IP only (for historical reasons)
+         1200   obsolete (either V.22 in Z2 / Z3, or Bell 212A in Z1)
+         2400   implies V22bis, qualifies as least common denominator
+         9600   default, used with PEP, V32, HST, H96, (CSP), (MAX)
+        12000   rare variant of V32
+        14400   used with V32b or HST (obsoleting H14)
+        16800   used with ZYX  or HST (obsoleting H16)
+        19200   used with V32T or ZYX (obsoleting Z19)
+        21600   rare variant of V32T (no "H21" needed)
+        28800   used with VFC or V34
+        33600   used with V34 (no V34+ or V34b needed)
+|       56000   used with X2C, X2S, or V.PCM
+
+   Allowing more than 12 speed values or allowing speed values above
+   64000 could break existing software (MakeNL, V7).  Therefore the
+   next step in FidoNet could be, to add 12000, 14400, 16800, 19200,
+   21600, 28800, 33600, and 56000, where 19200 is already specified
+   in FTS-5 since 1989.
+
+
+8. Thanks to...
+---------------
+   Ben Baker            St. Louis nodelist format
+   Rick Moore           FTS-0005.TXT
+   David Nugent         FTS-0005.003 and NLTOOLS
+   Jonny Bergdahl       ERRFLAGS 2.6
+   Ward Dossche         Zone 2 nodelist epilogue
+   David J. Thomas      FSC-0062.003 (FRL-0062)
+   Jan Ceuleers         FSC-0075.001 (FRL-0075)
+   Arjen Lentz          FSC-0091.001 (FRL-0091)
+   Leonard Erickson     CHECKNL 2.14 and many discussions in NET_DEV
+   Jim Barchuk          LNDL 2.7
+   Marius Ellen         FASTV7 2.04
+|  Jan Vermeulen, Ian Smith, Gisbert Rudolph, Carlos Fernandez Sanz,
+|  Tom Schlangen, Craig Ford, Pedro Lima, and many others...
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1006.html b/html/ftsc/fsp-1006.html new file mode 100755 index 00000000..ac3bb301 --- /dev/null +++ b/html/ftsc/fsp-1006.html @@ -0,0 +1,159 @@ + + +Kludge for specifying addition e-mail reply addresses. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1006
+Revision:       1
+Title:          Kludge for specifying addition e-mail reply addresses
+Author:         Ramon van der Winkel, 1:320/42.46
+                ramon@wsd.wline.se
+Revision Date:  12 December 1997
+Expiry Date:    12 December 1999
+----------------------------------------------------------------------
+Contents:
+                1. Scope
+                2. Background
+                3. Format
+                4. Implementation notes
+                5. Example
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  An Internet message can have several reply addresses. After gating
+  to FidoNet, the recipient is only presented with one of the reply
+  addresses. The others are lost. This is a suggestion for an
+  additional kludge to FSC-0035 to change that.
+
+
+1. Scope
+--------
+
+  This standard is specified for FTN netmail messages sent by a
+  FidoNet-to-Internet gateway to a recipient. Message editors will
+  have to support this to allow the user to select the reply address
+  to use.
+
+
+2. Background
+-------------
+
+  An Internet message has three headers to indicate where to send a
+  reply. These are, in order of priority, Reply-To:, Sender: and
+  From:. When a message is distributed by a mailing list, then one of
+  the headers could contain the e-mail address of the poster and one
+  of the other headers the address of the mailing list.
+
+  When the message is gated to FidoNet, the gateway currently selects
+  of the reply addresses and creates the message so that a reply will
+  return at the gateway and sent to this one address. The other
+  addresses are lost.
+
+  The FSC-0035 kludges REPLYTO and REPLYADDR allow for one return
+  address only. This is a proposal for an additional kludge inserted
+  by the gateway to specify an addtional reply address. The message
+  editor used by the recipient will present a list of all reply
+  addresses and allows the user to select the appropriate address.
+
+  This way, the user can send a message back to the mailing list (for
+  distribution), or to the e-mail address of the poster only.
+
+
+3. Format
+---------
+
+  Following the REPLYTO and REPLYADDR kludges, one or more kludges
+  with the name REPLYALSO can be inserted, each listing one possible
+  reply address.
+
+  @REPLYALSO 
+
+  Where  is in the form of
+
+     ramon@wsd.wline.se
+  or
+     wsd.wline.se!ramon
+
+  Each line MUST contain one address only.
+
+
+4. Implementation notes
+-----------------------
+
+  Gateways supporting the REPLYALSO kludge MUST put the the reply
+  address with the highest priority in the REPLYADDR kludge. The order
+  of priority is Reply-To:, Sender: and From: header. The other
+  addresses may be listed in any priority.
+
+
+5. Example
+----------
+
+  From: odinn@goldware.dk, 1:320/42
+  To:   Ramon van der Winkel, 1:320/42.46
+  Subj: Another test
+  ---------------------------------------
+  @INTL 1:320/42 1:320/42
+  @TOPT 46
+  @MSGID: wgmid$<123455@goldware.dk> 45AB23CD
+  @REPLYTO UUCP 1:320/42
+  @REPLYADDR odinn@goldware.dk
+  @REPLYALSO newftsc-l@brazerko.com
+  This message was distributed by the mailing list "New FTSC"
+  at brazerko.com.
+
+  ...
+
+
+A. Author contact data
+----------------------
+
+  Ramon van der Winkel
+  Fidonet: 1:320/42.46
+  E-mail:  ramon@wsd.wline.se
+  WWW:     http://www2.sbbs.se/hp/ramon
+
+
+B. History
+----------
+
+  Rev.1, 971212: First release.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1007.html b/html/ftsc/fsp-1007.html new file mode 100755 index 00000000..2b2e8fb0 --- /dev/null +++ b/html/ftsc/fsp-1007.html @@ -0,0 +1,162 @@ + + +Multiple recipient address specification to gateway. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1007
+Revision:       1
+Title:          Multiple recipient address specification to gateway
+Author:         Ramon van der Winkel, 1:320/42.46
+                ramon@wsd.wline.se
+Revision Date:  12 December 1997
+Expiry Date:    12 December 1999
+----------------------------------------------------------------------
+Contents:
+                1. Scope
+                2. Background
+                3. Format
+                4. Implementation notes for gateways
+                5. Example
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  Private messages within FidoNet only have one recipient address.
+  Multiple copies of the same message have to be sent to a FidoNet-
+  to-Internet gateway in order to address multiple recipients. This is
+  a proposal to indicate the addresses of multiple recipients in the
+  body of the message sent to the gateway.
+
+
+1. Scope
+--------
+
+  This standard is specified for FTN netmail messages sent to a
+  FidoNet-to-Internet gateway. Users are able to add this information
+  manually, although message editors could support this and make it
+  transparent to the user.
+
+
+2. Background
+-------------
+
+  Three types of recipient addresses can be specified on the Internet
+  and are reflected in this suggestion: To, Cc and Bcc. "To" are the
+  primary recipient(s) of the message. "Cc" is short for Carbon Copy
+  and lists the recipients that are intended to receive the message as
+  "informational". The last option "Bcc" is short for Blind Carbon
+  Copy. Recipients lists as Bcc recipients will not show up in the
+  headers of the Internet message, but get a copy anyway.
+
+
+3. Format
+---------
+
+  Immediately following the kludge lines, one or more of the following
+  lines can be inserted in the message. If a To: line is present, then
+  these lines follow the To: line.
+
+  GW-To: [,[...]]
+  GW-Cc: [,[...]]
+  GW-Bcc: [,[...]]
+
+  Where  is in the form of
+
+     ramon@wsd.wline.se
+  or
+     wsd.wline.se!ramon
+
+  Multiple addresses can be specified on the same line, separated by a
+  comma with optionally spaces around the comma. There is no limit
+  regarding the length of the line. The line must be terminated by a
+  single carriage return.
+
+  The GW-To: line replaces the To: lines.
+
+  The reason for GW-Cc is that "Cc:" by itself is expanded by some
+  editors and used to generate multiple copies of a message.
+
+
+4. Implementation notes for gateways
+------------------------------------
+
+  Gateways supporting this format add the e-mail addresses mentioned
+  in any of these three headers to the envelope file and create on
+  outbound (probably UUCP or SMTP) body text message. Rules for the
+  maximum length of envelope files (if any) apply.
+
+  The headers section of the RFC822 message will list the e-mail
+  addresses under the To: and Cc: headers. A Bcc: header must not be
+  added!
+
+
+5. Example
+----------
+
+  From: Ramon van der Winkel, 1:320/42.46
+  To:   UUCP, 1:320/42
+  Subj: New header test
+  ---------------------------------------
+  @INTL 1:320/42 1:320/42
+  @FMPT 46
+  GW-To: groupElist@newftsc.org
+  GW-Cc: odinn@goldware.dk
+  GW-Bcc: groupAadmin@newftsc.org
+  Hi!
+
+  This is a test
+
+  Ramon
+
+
+A. Author contact data
+----------------------
+
+  Ramon van der Winkel
+  Fidonet: 1:320/42.46
+  E-mail:  ramon@wsd.wline.se
+  WWW:     http://www2.sbbs.se/hp/ramon
+
+
+B. History
+----------
+
+  Rev.1, 971212: First release.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1008.html b/html/ftsc/fsp-1008.html new file mode 100755 index 00000000..ba98118d --- /dev/null +++ b/html/ftsc/fsp-1008.html @@ -0,0 +1,275 @@ + + +New control lines for forwarding messages. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1008
+Revision:       2
+Title:          New control lines for forwarded messages
+Author:         Michael Hohner, 2:2490/2520.17
+Revision Date:  29 December 1997
+Expiry Date:    29 December 1999
+----------------------------------------------------------------------
+Contents:
+                1. Specifications
+                2. Usage
+                3. Compatiblity
+                4. Known implementations
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+  This revision is an update to FRL-0092.001. The basic specifications
+  are unchanged.
+
+
+Abstract
+--------
+
+  Most fidonet message editors offer a "forward" function. Using this
+  function a user A ("forwarder") can sort of "redirect" a message
+  from user B ("author") to another user C ("final recipient"), maybe
+  because the forwarder is not the correct recipient, or because the
+  final recipient is a better person to answer the message. The name
+  and address of the author are usually included in the forward in
+  free-text format. The message text is included in non-quoted format.
+
+  A problem arises when the final recipient wants to reply to the
+  author of the forwarded message. The forward contains the forwarder
+  as the sender. So the final recipient must insert the name and
+  address of the author manually, using the information contained in
+  the message text. The message editor of the final recipient can't do
+  this automatically because of the free-text format. The editor will
+  also use incorrect quote initials, which is at least irritating.
+
+  This document introduces 7 new control lines which contain the
+  header information of the original message. With these control lines
+  the message editor can use the original header information
+  automatically.
+
+
+1. Specifications
+-----------------
+
+  There are 7 new control lines: FWDFROM, FWDTO, FWDORIG, FWDDEST,
+  FWDSUBJ, FWDAREA, FWDMSGID. As all control lines they start with an
+  ASCII 01 character (SOH) followed by the control line name followed
+  by whitespace followed by the control line's content followed by
+  ASCII 13 (CR).
+
+  Please note that all these control lines do not have a colon (like
+  the control lines in FTS-0001). This would be just waste of space.
+
+  FWDFROM
+  -------
+
+  This control line contains the name of the original sender as found
+  in the FROM field of the original message. Leading and trailing
+  whitespace should be removed. This control line should be omitted
+  altogether if the FROM field is empty.
+
+  FWDTO
+  -----
+
+  This control line contains the name of the original recipient as
+  found in the TO field of the original message. Leading and trailing
+  whitespace should be removed. This control line should be omitted
+  altogether if the TO field is empty.
+
+  FWDORIG
+  -------
+
+  This control line contains the address of the original sender as
+  found in the ORIG field of the original message. The usual 5D ASCII
+  notation (zone:net/node.point@domain) should be used. This control
+  line should be omitted altogether if the address is not known.
+
+  FWDDEST
+  -------
+
+  This control line contains the address of the original recipient as
+  found in the DEST field of the original message. The usual 5D ASCII
+  notation (zone:net/node.point@domain) should be used. This control
+  line should be omitted altogether if the address is not known or
+  unsure (as it is the case with forwarded echomail messages).
+
+  FWDSUBJ
+  -------
+
+  This control line contains the subject line of the original message.
+  This control line should be omitted altogether if the SUBJ field is
+  empty.
+
+  This control line should by made optional for security reasons. Echo
+  manager passwords are too easily revealed with it.
+
+  FWDAREA
+  -------
+
+  This control line contains the name of the echomail area where the
+  original message was forwarded from. It should be omitted altogether
+  if the original message was not forwarded from an echomail area.
+
+  FWDMSGID
+  --------
+
+  This control line contains the MSGID control line of the original
+  message. It should be omitted altogether if a MSGID control line is
+  not present in the original message.
+
+
+2. Usage
+--------
+
+  When the "forward" function of the message editor is invoked, the
+  editor program should generate the proposed control lines from the
+  header of the original message. If the original message already was
+  a forwarded one (indicated by the presence of at least a FWDORIG
+  control line), the editor should keep all FWD* control lines and
+  should not add any FWD* control lines. This preserves the FWD*
+  control lines of the first forwarder, containing the header data of
+  the author of the original message.
+
+  The editor should not generate FWD* control lines, if the message
+  isn't to be forwarded. A mail forwarding robot may also generate
+  these control lines, if it not just readdresses the message.
+
+  When the "reply" function of the editor is invoked the program
+  should use the control lines' contents instead of the header
+  information. The control lines should not be included in the reply.
+
+  Since it may not be immediately clear whether the user wants to
+  reply to the forwarder or to the original sender, the editor should
+  offer a means to ignore the proposed control lines and start a
+  "normal" reply instead, e.g. by two distinct functions, by user
+  preference or a dialog.
+
+
+  Pseudo code:
+
+  forwarding_message:
+     if is_forwarded_message then
+        don't change FWD* control lines
+     else
+        add FWD* control lines
+
+  quoting_message:
+     if is_forwarded_message then
+        if reply_to_forwarder then
+           use header data (normal quoting)
+        else
+           use FWD* control lines
+        remove FWD* control lines from reply
+     else
+        use header data (normal quoting)
+
+  other_functions:
+     remove/ignore FWD* control lines
+
+
+  Example:
+
+  Message from Joe User to my boss node:
+
+     From: Joe User 1:234/567
+     To:   Harry Herrmannsdoerfer 2:2490/2520
+     Subj: Some questions
+     @MSGID: 1:234/567 12345678
+     Text: Hello Harry!
+           ...
+
+  Harry forwards the message to me:
+
+     From: Harry Herrmannsdoerfer 2:2490/2520
+     To:   Michael Hohner 2:2490/2520.17
+     Subj: Joe's message
+     @FWDFROM Joe User
+     @FWDORIG 1:234/567
+     @FWDTO Harry Herrmannsdoerfer
+     @FWDDEST 2:2490/2520
+     @FWDSUBJ Some questions
+     @FWDMSGID 1:234/567 12345678
+     Text: Hi Michael!
+           ...
+
+  My answer using the new control lines:
+
+     From: Michael Hohner 2:2490/2520.17
+     To:   Joe User 1:234/567
+     Subj: Some questions
+     @REPLY: 1:234/567 12345678
+     Text: Hi Joe!
+
+           JU> ...
+           ...
+
+
+3. Compatiblity
+---------------
+
+  Editor programs which are not prepared for these proposed control
+  lines usually just ignore them and remove them from a reply. A reply
+  goes to the forwarder. Nothing gained and nothing lost.
+
+
+4. Known implementations
+------------------------
+
+  This proposal is implemented in the author's Fidonet editor
+  "FleetStreet for OS/2" (versions 1.17 and newer).
+
+  Also implemented in Odinn Sorensens Fidonet editor "GoldED"
+  (versions 3.00.Alpha5 and newer).
+
+
+A. Contacting the author
+------------------------
+
+  The author may be contacted electronically at the following
+  addresses:
+
+  Fidonet:    2:2490/2520.17
+  Internet:   miho@osn.de
+
+  Suggestions, comments and corrections are always welcome.
+
+
+B. History
+----------
+
+  Rev.1, 19960912: First release as FSC-0092.001.
+  Rev.2, 19971229: Submitted as FSP.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1009.html b/html/ftsc/fsp-1009.html new file mode 100755 index 00000000..b7f5795a --- /dev/null +++ b/html/ftsc/fsp-1009.html @@ -0,0 +1,142 @@ + + +Year 2000 issues in FTN software. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1009
+Revision:       1
+Title:          Year 2000 issues in FTN software
+Author:         Michael Hohner, 2:2490/2520.17
+Revision Date:  29 December 1997
+Expiry Date:    29 December 1999
+----------------------------------------------------------------------
+Contents:
+                1. Introduction
+                2. Generating Fidonet timestamps
+                3. Interpreting Fidonet timestamps
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  The year 2000 causes problems in many computer programs which use
+  two-digit year numbers. Current Fidonet software faces the very same
+  problems. This FSP specifies procedures which enable FTN software to
+  run without problems after the year 2000.
+
+
+1. Introduction
+---------------
+
+  Software using two-digit year numbers may cause problems in the year
+  2000. When the year number rolls over from "99" to "00", some
+  software may interpret the resulting year number as "1900" instead
+  of "2000". Such programs may contain code like this:
+
+     calendar_year = year_number + 1900;  /* wrong! */
+
+  Fidonet software faces the very same problem: the year number in
+  packed messages (see FTS-0001) has only two digits. Some programs
+  interpreting this number incorrectly may decide that messages from
+  the year 1900 are too old and discard them. Other programs probably
+  just display a wrong calendar year.
+
+  The long-term solution would be a transition to four-digit year
+  numbers. However, this would require new data formats and cause
+  every existing software to fail. So a short-term solution is
+  required, resulting in only minimal changes in software. This FSP
+  contains guidelines for proper year-number interpretation. The
+  author encourages all FTN software authors to check their software
+  for possible year-2000 problems (and release fixed versions during
+  the next three years).
+
+
+2. Generating Fidonet timestamps
+--------------------------------
+
+  This should not cause much headache. However, some software may use
+  the following algorithm:
+
+     year_number = calendar_year - 1900  /* wrong! */
+
+  This will result in a three-digit year number in 2000 and lead to
+  incorrect Fidonet timestamps.
+
+  One correct algorithm is:
+
+     year_number = calendar_year mod 100  /* correct! */
+
+
+3. Interpreting Fidonet timestamps
+----------------------------------
+
+  We can make use of the fact that Fidonet didn't exist before 1980,
+  i.e. no messages were created before 1980. So any year number
+  smaller than 80 can't mean "year 19xx", but can only mean "year
+  20xx". One algorithm for correct year number interpretation is:
+
+     if year_number < 80 then
+        calendar_year = 2000 + year_number
+     else
+        calendar_year = 1900 + year_number
+
+  Fidonet software should only use the calendar year for further
+  processing, not the year number from the timestamp.
+
+  This solution will work until 2080, giving us another 80+ years to
+  finally let some innovation happen in Fidonet.
+
+
+A. Contacting the author
+------------------------
+
+  The author may be contacted electronically at the following
+  addresses:
+
+  Fidonet:    2:2490/2520.17
+  Internet:   miho@osn.de
+
+  Suggestions, comments and corrections are always welcome.
+
+
+B. History
+----------
+
+  Rev.1, 19971229: Submitted as FSP.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1010.html b/html/ftsc/fsp-1010.html new file mode 100755 index 00000000..3be37d24 --- /dev/null +++ b/html/ftsc/fsp-1010.html @@ -0,0 +1,242 @@ + + +FTSC Document FSP-1010, Revision 001 + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1010
+Revision:       1
+Title:          Via kludge specification
+Author:         Colin Turner,
+                Joaquim Homrighausen
+Revision Date:  26 April 1999
+Expiry Date:    26 April 2001
+----------------------------------------------------------------------
+Contents:
+                1. Current practice
+                2. Kludge specification
+                3. Examples
+                4. Deprecated formats
+----------------------------------------------------------------------
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  Current practice for Fidonet Technology Network (FTN) NetMail
+  messages is to track their progress through the network and
+  programs by using control lines. These control lines are in
+  the form of a kludge named Via.
+  
+
+1. Current practice
+-------------------
+
+  As NetMail messages are routed through a FidoNet Technology Network
+  or as they are processed on a system, Via control lines are used to
+  track their progress.
+  
+  A single NetMail message may have any number of Via control lines.
+  
+  The Via control lines are stored in a block which starts after any
+  message text. New Via lines should be added to the end of the block
+  separated from the preceding control line by a single ASCII <CR>
+  character (0Dh).
+  
+  A Via control line is typically added:
+  
+    when a netmail packer packs the NetMail for transmission to
+    another system;
+    
+    when a netmail tracker inspects a NetMail.
+
+2. Kludge specification
+-----------------------
+
+  The Via control line is formatted as a number of fields, separated
+  by single space (20h) characters, as follows
+  
+    ^AVia: <FTN Address> @YYYYMMDD.HHMMSS[.Precise][.Time Zone] 
+    <Program Name> <Version> [Serial Number]<CR>
+    
+  Where ^A denotes the ASCII <SOH> (01h) character, and <CR> is the
+  character (0Dh).
+  
+  The fields are defined as follows:
+  
+  FTN Address
+  -----------
+
+  This field is mandatory and is the FidoNet Technology address of 
+  the system inserting the kludge. This may or may not include a
+  domain indicator.
+  
+  @YYYYMMDD.HHMMSS
+  ----------------
+  
+  This field is mandatory and consists of a time stamp. This is the
+  time at which the stamp was placed. The subcomponents are
+  
+  YYYY, the calendar year, in full four digit, decimal form;
+  MM,   the calendar month, in the range 01 to 12, this must be a
+        zero padded, two digit decimal number;
+  DD,   the day of the month, in the range 01 to 31, this must be a
+        zero padded, two digit decimal number;
+  HH,   hours, in the range 00 to 23, this must be a zero padded,
+        two digit decimal number;
+  MM,   minutes, in the range 00 to 59, this must be a zero padded,
+        two digit decimal number;
+  SS.   seconds, in the range 00 to 59, this must be a zero padded,
+        two digit decimal number.
+        
+  Precise
+  -------
+  
+  This field is optional and takes the form of extra precision in the
+  time stamp.
+  
+  If this field is present:
+  
+    it must begin with a single period character;
+    
+    this period must be followed by one or more decimal digits;
+    
+    the field has ended when another period or space is encountered;
+    
+    each decimal digit in the field following this character
+    represents the time of the via line in fractions of a second,
+    such that the the first digit represents tenths of a second,
+    the second digit represents hundreds of a second and so on.
+        
+  Time Zone
+  ---------
+
+  This field is optional, and must be a short, widely accepted
+  alphabetical abbreviation of the time zone that the time stamp
+  in the Via line pertains to.
+  
+  The use of various Time Zone values is deprecated, implementations
+  should attempt to convert the timestamp in the kludge to Universal
+  Time (GMT or UTC) and use the "UTC" Time Zone indicator, where
+  possible.
+  
+  The Time Zone field may only be ommitted when it is not possible
+  for the implementation to determine the correct offset from UTC,
+  and in this case the time stamp must represent local time on the
+  generating system.
+  
+  Program Name
+  ------------
+  
+  This field is mandatory, and must follow the format used in the PID
+  control line (detailed in FSC-46).
+  
+  Version
+  -------
+
+  This field is mandatory, and must follow the format used in the PID
+  control line (detailed in FSC-46).
+  
+  Serial Number
+  -------------
+  
+  This field is optional, and must follow the format used in the PID
+  control line (detailed in FSC-46).
+
+  Note that unlike many kludges, the "Via" text of the kludge itself
+  is in mixed, and not all upper case.
+  
+3. Examples
+-----------
+
+  Example of valid usage are
+  
+  ^AVia 2:443/13 @19990305.043212.UTC O/T-Track+ 2.69
+  ^AVia 2:443/13@fidonet @19980331.231202.UTC FrontDoor 2.32.mL
+  ^AVia 2:443/13.0 @19990101.002102.UTC FastEcho 1.46.1 21321
+  ^AVia 2:443/13 @19990323.230132 FakeMail 1.2
+  ^AVia 2:2480/18@fidonet @19990307.182128.47.UTC ITrack+ 1.3/G6 FP000069
+  
+4. Deprecated formats
+---------------------
+
+  Some other formats for the Via line are in use today, but these
+  formats are rather variable and inconsistent in nature, while
+  the format specified above is both more widespread and more
+  consistent.
+  
+  New implentations may need to parse these formats, but must not
+  generate them.
+  
+  The formats in use include, but are not limited to
+  
+  <NAME> [VERSION] [SERIAL] <ADDRESS> <TIMESTAMP> <TIMEZONE>
+  <NAME> <ADDRESS>, <TIMESTAMP> <TIMEZONE> <VERSION>
+  
+  Not that the time stamp in the above formats is also widely
+  variable, and takes forms which include, but may not be limited to
+  
+  <Day> <Month> <Year> AT <Hour>:<Min>:[Sec]
+  <Day of Week> <Month> <Day of Month> <Year>  <Hour>:<Min>:<Sec>
+  ON <Day of Month> <Month> <Year>  <Hour>:<Min>:<Sec>
+  <Month>/<Day> <Hour>:<Min>
+  @YYMMDDHHMMSS
+  
+  In the last listed format, observe in particular the two digit year
+  and lack of period to seperate the date from time.
+
+A. References
+-------------
+
+  [FTS-1] "A Basic FidoNet(r) Technical Standard Revision 16", Randy
+  Bush. September 1995.
+
+  [FSC-46] "A Product Identifier for FidoNet Message Handlers",
+  Joaquim Homrighausen, August 1994.
+
+
+B. Author contact data
+----------------------
+
+  Colin Turner
+  Fidonet: 2:443/13
+  E-mail:  ct@piglets.com
+  WWW:     http://www.piglets.com
+  
+  Joaquim Homrighausen
+  Fidonet: 2:201/330
+  E-mail:  joho@defsol.se
+  WWW:     http://www.defsol.se
+
+
+C. History
+----------
+
+  Rev.1, 990426: First release.
+
+**********************************************************************
+
+Back Go Back + + diff --git a/html/ftsc/fsp-1011.html b/html/ftsc/fsp-1011.html new file mode 100755 index 00000000..eaabefa8 --- /dev/null +++ b/html/ftsc/fsp-1011.html @@ -0,0 +1,1756 @@ + + +FTSC Document FSP-1011, Revision 003 + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1011
+Revision:       3
+Title:          Binkp - a protocol for transferring FidoNet mail over
+                reliable connections
+Authors:        Dima Maloff
+                Nick Soveiko
+                Maxim Masiutin
+Revision Date:  31 July 2000
+Expiry Date:    31 July 2002
+
+----------------------------------------------------------------------
+
+Abstract
+--------
+
+   This specification defines binkp - a protocol to handle a session
+   between two Fidonet Technology systems over a reliable connection.
+   Assumption that the connection is reliable makes possible to
+   eliminate error-checking and unnecessary synchronization steps,
+   achieving both ease of implementation and major performance
+   improvement over connections with large unpredictable delays (e.g.
+   Internet).
+
+Status of this document
+-----------------------
+
+   This document is a Fidonet Standards Proposal (FSP).
+
+   This document specifies an optional Fidonet standard protocol for
+   the Fidonet community, and requests discussion and suggestions for
+   improvements.
+
+   This document is released to the public domain, and may be used,
+   copied or modified for any purpose whatever.
+
+Available formats
+-----------------
+
+   Binkp Specification is also available in HTML format at
+   http://www.ritlabs.com/binkp/
+
+Table of contents
+-----------------
+
+    1. Background
+         1. Objectives
+         2. Motivation for a New Protocol
+    2. Definitions
+    3. Protocol Overview
+    4. Frame Format
+         1. Notation
+         2. Examples
+    5. Protocol Commands and Their Arguments
+         1. Classification
+         2. File Name Issues
+         3. Non-ASCII Characters in Command Argument symbol string
+         4. Binkp Commands
+         5. Example of Frame Exchange in a Simple binkp Session
+    6. Protocol States
+         1. Session Setup Stage
+              1. Originating Side
+              2. Answering Side
+         2. File Transfer Stage
+         3. Session Termination
+    7. Recommended Protocol Extensions
+         1. Non-Reliable Mode
+         2. Multiple Batch Mode
+         3. Multiple Passwords Mode
+         4. Keyed Hashing Challenge-Response Authentication Mechanism
+              1. Overview
+              2. Sequence of Steps
+              3. Generating and Transmitting Challenge Data
+              4. Producing and Transmitting a Digest
+              5. Indicating CRAM Capabilities
+              6. Example of Frame Exchange During CRAM Authentication
+              7. Notes on Hash Function Algorithms
+    8. License
+    9. Glossary
+   10. References
+   11. Acknowledgements
+    A. Author Contact Data
+    B. History
+
+     ---------------------------------------------------------------
+
+1. Background
+-------------
+
+  1.1 Objectives
+  --------------
+
+   It's been a long time since a new Fidonet protocol has been
+   developed, [EMSI] definitions being published last time in 1991,
+   not speaking about basic standards, [FTS-0001] and [FTS-0006].
+   Fidonet is evolving everyday and new transport layers are being
+   introduced into practice. This led to a situation when in certain
+   Fidonet Regions a visible portion of traffic, especially long
+   distance traffic generating high toll, is being carried by means of
+   protocols that formally are not Fidonet standards. This creates an
+   ambiguity for such systems in indicating their additional
+   capabilities in Fidonet nodelist and in some instances, from being
+   listed in the nodelist at all.
+
+   This document attempts to document the current practice for
+   communication between two Fidonet systems via a reliable channel,
+   provide technical reference for Fidonet software developers and
+   eventually improve Fidonet connectivity.
+
+  1.2 Motivation for a new protocol
+  ---------------------------------
+
+   Existing Fidonet Technical Standards and Fidonet Reference Library
+   documents [FTS-0001], [FTS-0006], [EMSI] specify both session
+   handshake procedures and transmission capabilities that imply:
+     * non-reliable communication channel between mailers
+     * low round-trip times in the communication channel between
+       mailers.
+
+   This was commonplace a few years ago, when Fidonet systems were not
+   using transport other than direct dial-up on a visible basis.
+   Things have changed today, when other communication media becomes
+   widely available on a day-to-day basis. This communication media
+   typically provides implementation of Physical, Data Link, Network
+   and Transport layers of the ISO/OSI Reference Model and facilitates
+   relieving Session layer of inappropriate functions, such as error
+   control, flow control, call management and data transparency
+   [Halsall95]. Examples of such communication media are TCP/IP socket
+   connection and HDLC family protocol connection.
+
+   New communication media can be generally characterized by the
+   reliable transmission service offered by it to the Session layer
+   protocol. Reliable transmission implies that:
+     * Data link and/or Transport layer protocols are responsible for
+       error control and delivery of frames in correct sequence
+     * Session layer and higher layer protocols are operating on top
+       of connection-oriented mode
+     * Quality of Service provisions (if any) result in unspecified
+       delays between transmitter and receiver
+     * connections are rarely aborted.
+
+   Combination of these factors imposed the following requirements for
+   the new Fidonet protocol:
+     * error control can be eliminated throughout the session layer
+       protocol for both handshake and default file transfer method
+     * session setup procedure should minimize number of
+       synchronization points for fast handshake
+     * protocol should be insensitive to delays and robust with
+       respect to timeouts
+     * application flow control should be moved to file level;
+       individual data frames do not need to be error checked nor
+       acknowledged
+     * protocol should be independent from both higher and lower layer
+       protocols
+     * protocol should be reasonably easy to implement and allow
+       future extensions.
+
+2. Definitions
+--------------
+
+   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT" and "MAY"
+   in this document are to be interpreted as specified in [FTA-0006].
+   However, for readability, these words may sometimes not appear in
+   all uppercase letters in this specification. Although it should not
+   impact minimal realization of binkp protocol, it must be noted that
+   Protocol Extensions may override, update or obsolete requirement
+   levels indicated by the above keywords in chapters from 3 to 6
+   inclusive.
+
+   Calling party in this document is referred to as the Originating
+   side and called party is referred to as the Answering side.
+   Originating side here is the party that initiates the connection
+   between two systems.
+
+   Mailer in this document is a software that implements the protocol.
+
+   Words "frame", "packet", and "block" when used in this document
+   refer to binkp's Frames, unless explicitly stated otherwise.
+
+   Other definitions that are not local to this document can be found
+   in the Glossary.
+
+   This document is organized as following:
+
+   Frames section defines binkp's frames. Binkp/1.0 commands and their
+   arguments section provides detailed description of all defined
+   protocol commands together with recommendations for their usage.
+   Actual binkp implementation may match it's own diagrams provided
+   that such implementation remains fully compatible with current
+   specification. Protocol states section gives rigorous state
+   diagrams for the minimum realization of binkp. All mailers MUST
+   support this minimum realization. Recommended Protocol Extensions
+   section documents most important extensions to the basic protocol
+   that are in use as of the time of this writing. The License,
+   Glossary and References sections can be found at the end of this
+   document.
+
+3. Protocol Overview
+--------------------
+
+   Binkp is a Fidonet session layer protocol intended for use over
+   data transparent bi-directional channels with reliable
+   transmission. There are no other requirements for the service
+   provided by the underlying protocol suite. Presentation and
+   application layer protocols are not discussed here. Whenever TCP/IP
+   socket is used, IANA registered port number for binkp 24554 SHOULD
+   be used (as registered with the Internet Assigned Numbers
+   Authority).
+
+   Functionality of the minimum protocol realization makes provision
+   for:
+     * password protected sessions
+     * 4D/5D addressing for Fidonet and technology compatible networks
+     * exchange of Type 2 [FTS-0001], Type 2.2 [FSC-0045], Type 2+
+       [FSC-0039] and [FSC-0048], Type 3 [FSC-0081] packets and
+       [FTS-0006] arcmail in both directions, including poll and mail
+       pickup, as well as transfer of any binary or ASCII files
+     * handling WaZOO [FTS-0006] file requests
+     * ensuring integrity of transmitted mail and files
+     * simultaneous bi-directional transmission
+     * maximizing performance over packet switched data networks
+
+   Binkp uses only one synchronization point during session startup,
+   that is password exchange. This feature facilitates fast session
+   startup for high latency links. Sliding window flow control is
+   incorporated on the file level. This ensures that a batch of small
+   files is transmitted with the same efficiency as a one large file.
+
+4. Frame Format
+---------------
+
+   Binkp is defined in terms of sending and receiving specifically
+   formatted data blocks. We call them frames.
+
+   Command frames carry protocol commands and may change protocol
+   state. Data frames are usually appended to files being received by
+   mailers or may be discarded, depending on the protocol state.
+
+   The particular way of mapping an octet stream or a datagram stream
+   of the transport layer into binkp frames may depend on the
+   underlying protocol suite. At this time, we define such mapping for
+   TCP/IP socket connection which can also be used for similar
+   transports as well.
+
+   The socket stream is being split into binkp frames in the following
+   manner:
+
+     7 6543210 76543210
+    +-+-------+--------+--- ................ ---+
+    |T|      SIZE      |          DATA          |
+    +-+-------+--------+--- ................ ---+
+    |<-   2 octets   ->|<- up to 32767 octets ->|
+       (frame header)          (frame data)
+
+   If T bit is 0, this is a data frame.
+
+   If T bit is 1, this is a command frame.
+
+   15 bits marked SIZE carry the size of the DATA part of the frame in
+   octets (with the bit marked 0 being the least significant). That
+   is, the actual length of a binkp frame is SIZE+2.
+
+   The size of the DATA part may vary between 1 and 32767 octets. A
+   correct realization should never set SIZE to 0. Upon receiving of a
+   packet header with the SIZE field set to 0, the total length of the
+   incoming packet must be treated as 2, this packet must be dropped,
+   and the event should be logged.
+
+   The first octet of a command frame data is the command ID. The ID
+   must be between 0 and 127 inclusive.
+
+   Other octets carry command arguments. Command arguments are an
+   arbitrary symbol string that may be null-terminated. Treating of a
+   null character in the middle of a command depends on realization
+   (with the options being "treat as whitespace" or "treat as
+   end-of-line"). The terminating null character (if any) is either
+   stripped or used by mailers internally as an end-of-line marker.
+
+  4.1 Notation
+  ------------
+
+   As stated before, command ID is a small number between 0 and 127.
+   Every binkp command defined in this document has a symbolic name in
+   the form M_XXX. Symbolic names are defined in binkp commands
+   section. We will use symbolic names and not numeric command IDs to
+   refer to commands everywhere in this document.
+
+   The following notation is used to describe binkp's command frames:
+
+         M_XXX "Data string"
+
+   The actual numeric command ID for the command with the symbolic
+   name of M_XXX should be written into the first octet of the DATA
+   area of a binkp frame. "Data string" is a string to be copied into
+   DATA area starting at second octet. SIZE should be set to the total
+   length of "Data string" plus one for the octet to store the command
+   number. T bit should be set to 1.
+
+  4.2 Examples
+  ------------
+
+   M_OK "":
+
+     7 6543210 76543210 76543210
+    +-+-------+--------+--------+
+    |1|      0        1|       4|
+    +-+-------+--------+--------+
+     |                |        +----- command ID (no arguments)
+     |                +-------- frame length
+     +- command frame flag
+
+   M_NUL "TEST":
+
+    +-+-------+--------+--------+-------+--------+--------+--------+
+    |1|      0        5|       0|   T        E        S       T    |
+    +-+-------+--------+--------+-------+--------+--------+--------+
+
+5. Protocol Commands and Their Arguments
+----------------------------------------
+
+  5.1 Classification
+  ------------------
+
+   Protocol commands may be classified the following way:
+
+     * By argument type:
+                    M_SKIP. Mailer MUST parse these commands and it is not
+            recommended to log arguments of these commands as they
+            are. Mailer-parseable commands can be further subdivided
+            by containment of a file name in the argument.
+                              commands contain a file name in their arguments.
+                                 MAY ignore and/or log arguments of these commands.
+     * By protocol stage:
+                    M_PWD (must not be sent by the Answering side), M_OK (must
+            not be sent by the Originating side). These commands MUST
+            never be sent during the file transfer stage.
+                    These commands MUST NOT be sent session setup stage.
+                    any time during the session.
+
+  5.2 File Name Issues
+  --------------------
+
+   In Mailer-parseable commands that contain a file name, the file
+   name MUST NOT include a whitespace (ASCII value 20 hex). The file
+   name SHOULD NOT include symbols other than alphanumeric
+   (A-Z,a-z,0-9) and safe characters as defined below in BNF. All
+   other symbols are to be considered unsafe and SHOULD be escaped in
+   the form of two hexadecimal digits preceded by a backslash (e.g. a
+   whitespace must be transmitted as "\20").
+
+   filename        = *pchar
+   pchar           = unreserved | escape
+   unreserved      = ALPHA | DIGIT | safe
+   safe            = "@" | "&" | "=" | "+" | "%" | "$" | "-" | "_" |
+                     "." | "!" | "(" | ")" | "#" | "|"
+   escape          = "\" HEX HEX
+
+   National characters should not be escaped, but rather transmitted
+   using [UTF8] encoding (see section discussing non-ASCII characters
+   below).
+
+   The best current practice is that Mailer does not alter a file name
+   without sysop's intention. If the mailer does provide such a
+   mechanism, it MUST BE optional and it SHOULD BE off by default.
+
+   The protocol does not impose limitations on the file name length
+   other than those arising from the finite length of the binkp frame
+   itself.
+
+  5.3 Non-ASCII Characters in Command Argument Symbol String
+  ----------------------------------------------------------
+
+   Generally, mailer SHOULD use only characters from the ASCII range
+   [32...126] in the symbol strings for command arguments. In case
+   when there is a necessity to use non-ASCII characters, mailer
+   SHOULD use the [UTF8] format of the multioctet Universal Character
+   Set [ISO10646]. Mailer SHOULD use non-ASCII characters only if the
+   other side have indicated it's support by transmitting M_NUL "OPT
+   UTF8" frame during the session setup stage. Otherwise, mailer
+   SHOULD assume that the remote does not support non-ASCII characters
+   and SHOULD NOT use them in command arguments.
+
+  5.4 Binkp Commands
+  ------------------
+
+   Format: symbolic_command_name command_ID
+
+   M_NUL 0
+
+           Command arguments contain human-readable information, such
+           as nodelist info, sysop name, etc. This frame can also be
+           used by some Mailers to exchange protocol options. Mailer
+           MAY ignore and/or log arguments of M_NUL.
+
+           e.g. "ZYZ Dima Maloff"
+
+           The following format of M_NUL argument is recommended for
+           compatibility purposes:
+
+              * M_NUL "SYS system_name"
+              * M_NUL "ZYZ sysop's_name"
+              * M_NUL "LOC system_location"
+              * M_NUL "NDL system_capabilities"
+              * M_NUL "TIME remote_date_time"
+                remote_date_time format is described in [RFC822].
+                Example of valid remote_date_time is
+                Sun, 06 Nov 1994 08:49:37 GMT
+              * M_NUL "VER mailer_version protocol_version"
+                note: binkp/1.0 mailers should send "binkp/1.0" string
+                for protocol_version.
+              * M_NUL "TRF netmail_bytes arcmail_bytes"
+                traffic prognosis (in bytes) for the netmail
+                (netmail_bytes) and arcmail and files (arcmail_bytes),
+                both are decimal ASCII strings
+              * M_NUL "OPT protocol options"
+                here protocol options is a space separated list of
+                binkp options and extensions supported by the mailer.
+              * M_NUL "PHN string"
+                phone number, ip address or other network layer
+                addressing ID
+              * M_NUL "OPM string"
+                string is a message for the system operator that may
+                require manual attention
+
+   M_ADR 1
+
+           List of 4D/5D addresses (space separated).
+
+           e.g. "2:5047/13@fidonet 2:5047/0@fidonet"
+
+   M_PWD 2
+
+           Session password, case sensitive. After successful password
+           authentication of the remote, originating side proceeds to
+           the file transfer stage. This command MUST never be sent by
+           the Answering side.
+
+           e.g. "pAsSwOrD"
+
+   M_OK 4
+
+           Acknowledgement for a correct password. Upon receiving of
+           this command, originating side goes to file transfer stage.
+           This command MUST never be sent by the Originating side.
+           Arguments may be ignored.
+
+           e.g. ""
+
+   M_FILE 3
+
+           Space separated list of parameters for the next file to be
+           transmitted: filename; size in bytes; unixtime; file
+           transmission offset.
+
+           In protocol extensions, negative values for the offset may
+           have special meaning (see non-reliable mode for an example
+           of such usage), basic implementation may treat negative
+           values as an error.
+
+           Size, time and offset parameters are decimal. Until the
+           next M_FILE command is received, all data frames must carry
+           data from this file in consecutive manner. There is no end
+           of file identifier as the file size is known beforehand. If
+           there are "extra" data frames, Mailer may append this data
+           to the file. By default, transmission of each file should
+           be started from offset 0. M_GET command sent by the remote
+           MUST force the mailer to start transmission from the
+           specified offset.
+
+           e.g. "config.sys 125 2476327846 0"
+
+           or, answering to M_GET with offset 100:
+
+           "config.sys 125 2476327846 100"
+
+   M_EOB 5
+
+           End-of-Batch. M_EOB command must be transmitted after all
+           the files have been sent.
+
+           Arguments of the command may be ignored.
+
+           e.g. ""
+
+   M_GOT 6
+
+           File acknowledgement, that must be transmitted upon
+           receiving of the last data frame for current file.
+           Arguments for this command shall be the same as for the
+           M_FILE sent by remote, excluding the last argument, file
+           offset, which is not transmitted back to the system which
+           have sent M_FILE. M_GOT can also be transmitted while
+           receiving a file, in which case transmitting party may
+           interpret it as a destructive skip.
+
+           e.g. "config.sys 125 2476327846"
+
+   M_ERR 7
+
+           This command indicates a fatal error. A party sending M_ERR
+           should abort the session. Argument should contain an error
+           explanation and may be logged. Mailer sends M_ERR in
+           response for an incorrect password. Mailer NUST NOT abort a
+           session without sending a M_ERR or a M_BSY frame (though
+           state machine tables, for simplicity, may not include
+           "transmit M_ERR" instructions).
+
+           e.g. "Incorrect password"
+
+   M_BSY 8
+
+           M_BSY command is transmitted when the system encounters a
+           non-fatal error typically due to temporary lack of
+           resources to proceed with the session. The argument should
+           contain an explanation of the situation and may be logged
+           by remote. M_BSY may be sent at any time during the session
+           (including session setup stage), not only the stages
+           explicitly indicated in the finite state machine. The side,
+           which have sent M_BSY, is in legal position to abort the
+           session. Mailer MUST be able to accept M_BSY at any time.
+           Though state machine tables, for simplicity, may not
+           include handling of M_BSY command, Mailer MUST NOT be
+           confused by reception of M_BSY command.
+
+           e.g. "Too many servers are running already"
+
+           If a mailer wishes to suggest the remote a time interval
+           before the next session attempt, it may choose to transmit
+           it in the following format:
+
+           M_BSY "RETRY NNNN: explanation"
+
+           where NNNN is interval in seconds (decimal string) and
+           explanation is an arbitrary string containing explanation
+           of the matter (optional).
+
+   M_GET 9
+
+           M_GET command is a request to (re)send files. Arguments of
+           the command are the same as for the M_FILE command and
+           refer to a file which we'd like to receive from the remote.
+
+           Mailer may send M_GET when it doesn't like transmission
+           file offset (e.g. file was partially received during one of
+           the previous sessions).
+
+           e.g. "config.sys 125 2476327846 100"
+
+           Mailer reacts to this command as follows: according to the
+           first three arguments (filename/size/unixtime), it
+           determines whether the M_GET argument is the current file
+           being transmitted to the remote (or a file that have been
+           transmitted, but we are still waiting an M_GOT ack for it).
+           If this is the case, it should
+
+              * discard transmission in progress as soon as possible
+              * perform seek() to the specified offset
+              * proceed with transmission of the file requested
+                starting with an appropriate M_FILE.
+
+           For the example above, corresponding M_FILE will have the
+           following arguments: "config.sys 125 2476327846 100"
+
+           When the mailer is finished with transmitting data of the
+           requested file it may proceed with transmission of other
+           files it has for the remote.
+
+   M_SKIP 10
+
+           Non destructive skip. Parameter is a space separated list
+           of filename, size and unixtime. This command indicates that
+           the remote should postpone sending the file until next
+           session.
+
+           e.g. "config.sys 125 2476327846"
+
+  5.5 Example of Frame Exchange in a Simple Binkp Session
+  -------------------------------------------------------
+
+   +-----------------------------------------------------------------+
+   | Originating side                | Answering side                |
+   |---------------------------------+-------------------------------|
+   | M_NUL "SYS ..."                 | M_NUL "SYS ..."               |
+   | M_NUL "ZYZ ..."                 | M_NUL "ZYZ ..."               |
+   | M_NUL "LOC ..."                 | M_NUL "LOC ..."               |
+   | M_NUL "VER ..."                 | M_NUL "VER ..."               |
+   | M_ADR "2:2/2.2@fidonet"         | M_ADR "3:3/3.3@fidonet"       |
+   | M_PWD "password"                | (waiting for a password from  |
+   |                                 | remote)                       |
+   |---------------------------------+-------------------------------|
+   | (waiting for password           | M_OK "" (or M_ERR "Bad        |
+   | acknowledgement)                | password")                    |
+   |---------------------------------+-------------------------------|
+   | (got M_OK)                      | M_FILE "file2 200 42342434 0" |
+   |---------------------------------+-------------------------------|
+   | M_FILE "file1 100 423424244 0"  | data                          |
+   |---------------------------------+-------------------------------|
+   | data                            | data                          |
+   |---------------------------------+-------------------------------|
+   | data                            | data                          |
+   |---------------------------------+-------------------------------|
+   | M_EOB                           | (got file1, acknowledging it) |
+   |---------------------------------+-------------------------------|
+   | (got file2, acknowledging it)   | M_GOT "file1 100 423424244"   |
+   |---------------------------------+-------------------------------|
+   | M_GOT "file2 200 42342434"      | data                          |
+   |---------------------------------+-------------------------------|
+   |                                 | M_EOB                         |
+   +-----------------------------------------------------------------+
+
+6. Protocol States
+------------------
+
+   The protocol has two major stages: session setup (different for
+   originating side and answering side) and file transfer (where state
+   machined for both sides are the same). Methods for initiating
+   connection as well as numerical values for particular timeouts are
+   dependent on the underlying layer's protocol suite and are not
+   considered here. Mailer MAY allow configuration of timeouts in
+   reasonably wide range to cover all supported transport protocols.
+
+   The Finite State Machine notation is used throughout this section
+   as defined by [FTS-0001].
+
+  6.1 Session Setup Stage
+  -----------------------
+
+   Originating side should initiate a binkp session according to Table
+   1. Answering side should be able to act according to Table 2. Any
+   optional extensions of the handshake procedure MUST NOT confuse the
+   other side, which may choose at it's discretion to follow this
+   minimal implementation. Upon successful handshake, both sides
+   follow Table 3 (file transfer stage). That's why terms Answering
+   side and Originating side were chosen for this specification
+   instead of Client and Server - both sides play the same roles, and
+   their state machines differ in session setup stage only.
+
+   Session setup stage has the following roles
+
+     * Authentication (REQUIRED). Answering side, upon reception of a
+       password (common secret word) from Originating side, decides
+       whether the password really matches the list of presented
+       addresses, and either acknowledges it by sending M_OK frame or
+       rejects by sending M_ERR frame. This mechanism is called Basic
+       Authentication Scheme and MUST be supported by all Mailers.
+       Basic Authentication Scheme has the following limitations:
+          * If Originating side presented multiple addresses, the
+            password for all of the addresses must be the same (may be
+            solved by Multiple passwords extension).
+          * Cleartext reusable passwords are passed over a network
+            (may be solved by CRAM extension).
+          * Verification is made on Answering side only, thus
+            Originating side has no way to verify Answering side (may
+            be solved by dual CRAM or public-key cryptography, not
+            discussed in this document).
+     * Indicating protocol options (OPTIONAL). Sides may exchange
+       specially formatted M_NUL messages to indicate supported
+       extensions. Sides MAY use another technique to indicate
+       extensions.
+
+    6.1.1 Originating Side
+    ----------------------
+
+   Originating side sends M_ADR and M_PWD frames, waits for successful
+   authentication acknowledgement from the Answering side (M_OK frame)
+   and goes to file transfer stage. Originating side MUST NOT wait
+   before sending M_ADR frame, i.e. this frame should be send just
+   after setting up a connection on underlying layer. Originating side
+   MUST NOT wait before sending M_PWD except after reception of M_ADR
+   frame. The term wait in this paragraph means do not send anything
+   while expecting data from remote.
+
+                Table 1: Session setup, originating side
+   +-----------------------------------------------------------------+
+   | #  | Name       | Predicate(s)     | Action(s)           | Next |
+   |----+------------+------------------+---------------------+------|
+   | S0 | ConnInit   |                  | Attempt to          | S1   |
+   |    |            |                  | establish           |      |
+   |    |            |                  | connection          |      |
+   |----+------------+------------------+---------------------+------|
+   | S1 | WaitConn   | Connection       | Send M_NUL frames   | S2   |
+   |    |            | established      | with system info    |      |
+   |    |            |                  | (at least one M_NUL |      |
+   |    |            |                  | "SYS ..." frame     |      |
+   |    |            |                  | should be sent      |      |
+   |    |            |                  | before M_ADR)       |      |
+   |    |            |                  | Send M_ADR frame    |      |
+   |    |            |                  | with system         |      |
+   |    |            |                  | addresses           |      |
+   |    |            |                  | Set Timer           |      |
+   |    |            |                  | See if we have      |      |
+   |    |            |                  | password for the    |      |
+   |    |            |                  | remote              |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Connection       | Report no           | exit |
+   |    |            | refused          | connection          |      |
+   |----+------------+------------------+---------------------+------|
+   | S2 | SendPasswd | Yes, we have a   | Send M_PWD          | S3   |
+   |    |            | password         | "password" frame    |      |
+   |    |            |                  | Reset Timer         |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | No, there's no   | Send M_PWD "-"      | S3   |
+   |    |            | password         | frame               |      |
+   |----+------------+------------------+---------------------+------|
+   | S3 | WaitAddr   | M_ADR frame      | See if answering    | S4   |
+   |    |            | received         | side presented the  |      |
+   |    |            |                  | address we've       |      |
+   |    |            |                  | called              |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_BSY frame      | Report remote is    | exit |
+   |    |            | received         | busy                |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_ERR frame      | Report error        | exit |
+   |    |            | received         |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_NUL frame      | Ignore (optionally, | S3   |
+   |    |            | received         | log frame argument) |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Other known      | Report unexpected   | exit |
+   |    |            | frame received   | frame               |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Unknown frame    | Ignore              | S3   |
+   |    |            | received         |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Nothing happens  | Wait                | S3   |
+   |    |            |------------------+---------------------+------|
+   |    |            | Timer Expired    | Report timeout      | exit |
+   |----+------------+------------------+---------------------+------|
+   | S4 | AuthRemote | Yes, the address | See if we've sent a | S5   |
+   |    |            | was presented    | password for this   |      |
+   |    |            |                  | address             |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | No, the address  | Report we called    | exit |
+   |    |            | was not          | the wrong system    |      |
+   |    |            | presented        |                     |      |
+   |----+------------+------------------+---------------------+------|
+   | S5 | IfSecure   | Yes, we've sent  | Wait for M_OK frame | S6   |
+   |    |            | a password       |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | No, there was no | Report non-secure   | T0   |
+   |    |            | password         | session             |      |
+   |----+------------+------------------+---------------------+------|
+   | S6 | WaitOk     | M_OK frame       | report secure       | T0   |
+   |    |            | received         | session             |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_BSY frame      | Report remote is    | exit |
+   |    |            | received         | busy (Answering     |      |
+   |    |            |                  | size MAY report     |      |
+   |    |            |                  | busy after          |      |
+   |    |            |                  | reception of        |      |
+   |    |            |                  | caller's address)   |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_ERR frame      | Report error        | exit |
+   |    |            | received         |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_NUL frame      | Ignore (optionally, | S6   |
+   |    |            | received         | log arguments)      |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Other known      | Report unexpected   | exit |
+   |    |            | frame received   | frame               |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Unknown frame    | Ignore              | S6   |
+   |    |            | received         |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Nothing happens  | Wait                | S6   |
+   |    |            |------------------+---------------------+------|
+   |    |            | Timer Expired    | Report timeout      | exit |
+   +-----------------------------------------------------------------+
+
+    6.1.2 Answering Side
+    --------------------
+
+   Originating side sends M_ADR and waits for M_ADR and M_PWD frames
+   from remote. Upon receptions of these frames, it decides whether
+   the password really matches the list of presented addresses, and
+   either acknowledges it by sending M_OK frame (and goes to file
+   transfer stage) or rejects by sending M_ERR frame (and
+   disconnects). The term wait in this paragraph means do not send
+   anything while expecting data from remote.
+
+                 Table 2: Session setup, answering side
+   +-----------------------------------------------------------------+
+   | #  | Name     | Predicate(s)        | Action(s)          | Next |
+   |----+----------+---------------------+--------------------+------|
+   | R0 | WaitConn | Incoming connection | Send M_NUL frames  | R1   |
+   |    |          | established         | with system info   |      |
+   |    |          |                     | (at least one      |      |
+   |    |          |                     | M_NUL "SYS ..."    |      |
+   |    |          |                     | frame should be    |      |
+   |    |          |                     | sent before M_ADR) |      |
+   |    |          |                     | Send M_ADR frame   |      |
+   |    |          |                     | with system        |      |
+   |    |          |                     | addresses          |      |
+   |    |          |                     | Set Timer          |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Nothing happens     | Wait               | R0   |
+   |----+----------+---------------------+--------------------+------|
+   | R1 | WaitAddr | M_ADR frame         | See if we have a   | R2   |
+   |    |          | received            | password for any   |      |
+   |    |          |                     | of the remote      |      |
+   |    |          |                     | addresses          |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | M_ERR frame         | Report error       | exit |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | M_NUL frame         | Log                | R1   |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Other known frame   | Report unexpected  | exit |
+   |    |          | received            | frame              |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Unknown frame       | Ignore             | R1   |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Nothing happens     | Wait               | R1   |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Timer expired       | Report timeout     | exit |
+   |----+----------+---------------------+--------------------+------|
+   | R2 | IsPasswd | Yes, we have a      | Set Timer          | R3   |
+   |    |          | password            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Yes, but we have    | Send M_ERR frame   | exit |
+   |    |          | several different   | Report             |      |
+   |    |          | passwords for       | inconsistent       |      |
+   |    |          | different addresses | password settings  |      |
+   |    |          | of the remote       |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | No, there's no      | Report non-secure  | T0   |
+   |    |          | password            | session            |      |
+   |----+----------+---------------------+--------------------+------|
+   | R3 | WaitPwd  | M_PWD frame         | See if the         | R4   |
+   |    |          | received            | password matches   |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | M_ERR frame         | Report error       | exit |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | M_NUL frame         | Log                | R4   |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Other known frame   | Report unexpected  | exit |
+   |    |          | received            | frame              |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Unknown frame       | Ignore             | R4   |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Nothing happens     | Wait               | R3   |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Timer Expired       | Report timeout     | exit |
+   |----+----------+---------------------+--------------------+------|
+   | R4 | PwdAck   | Yes, the password   | Send M_OK frame    | T0   |
+   |    |          | matches             | Report secure      |      |
+   |    |          |                     | session            |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | No, password does   | Report password    | exit |
+   |    |          | not match           | error              |      |
+   +-----------------------------------------------------------------+
+
+  6.2 File Transfer Stage
+  -----------------------
+
+   File transfer stage is based on two major routines. We call them
+   Receive Routine and Transmit Routine. These routines perform some
+   actions depending on their state variables. State variables are
+   RxState for Receive Routine and TxState for Transmit Routine.
+
+   RxState := { RxWaitF | RxAccF | RxReceD | RxWriteD | RxEOB | RxDone
+   }
+
+   TxState := { TxGNF | TxTryR | TxReadS | TxWLA | TxDone }
+
+                         Table 3: File Transfer
+   +-----------------------------------------------------------------+
+   | #  | Name         | Predicate(s)        | Action(s)      | Next |
+   |----+--------------+---------------------+----------------+------|
+   | T0 | InitTransfer | none                | Set Timer      | T1   |
+   |    |              |                     | Set RxState to |      |
+   |    |              |                     | RxWaitF        |      |
+   |    |              |                     | Set TxState to |      |
+   |    |              |                     | TxGNF          |      |
+   |----+--------------+---------------------+----------------+------|
+   | T1 | Switch       | RxState is RxDone   | Report session | exit |
+   |    |              | and TxState is      | complete       |      |
+   |    |              | TxDone              |                |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Data Available in   | call Receive   | T2   |
+   |    |              | Input Buffer        | routine        |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Free space exists   | call Transmit  | T3   |
+   |    |              | in output buffer    | routine        |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Nothing happens     | Wait           | T1   |
+   |    |              |---------------------+----------------+------|
+   |    |              | Timer Expired       | Report Timeout | exit |
+   |----+--------------+---------------------+----------------+------|
+   | T2 | Receive      | Receive routine     | Set Timer      | T1   |
+   |    |              | returned OK         |                |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Receive routine     | Close all      | exit |
+   |    |              | returned Failure    | opened files   |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Receive routine     | Call Receive   | T2   |
+   |    |              | returned Continue   | routine again  |      |
+   |----+--------------+---------------------+----------------+------|
+   | T3 | Transmit     | Transmit routine    | Set Timer      | T1   |
+   |    |              | returned OK         |                |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Transmit routine    | Close all      | exit |
+   |    |              | returned Failure    | opened files   |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Transmit routine    | Call Transmit  | T3   |
+   |    |              | returned Continue   | routine again  |      |
+   +-----------------------------------------------------------------+
+
+   Tables 4-6 are not actually state machines, but routines called
+   during file transfer stage
+
+   We define here a FIFO queue called "TheQueue", which is used to
+   pass incoming M_GET / M_GOT / M_SKIP frames from Receive Routine to
+   Transmit Routine. Receive routine itself does not react to these
+   frames.
+
+                        Table 4: Receive Routine
+   +-----------------------------------------------------------------+
+   |RxState |Predicate(s) |Condition(s) |Actions(s)|Next    |Return  |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxWaitF |Get a frame  |Haven't got a|none      |RxWaitF |OK      |
+   |        |from Input   |complete     |          |        |        |
+   |        |Buffer       |frame yet    |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got Data     |ignore    |RxWaitF |OK      |
+   |        |             |frame        |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_ERR    |Report    |RxDone  |Failure |
+   |        |             |             |Error     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_GET /  |Add frame |RxWaitF |OK      |
+   |        |             |M_GOT /      |to The    |        |        |
+   |        |             |M_SKIP       |Queue     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_NUL    |Log       |RxWaitF |OK      |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_EOB    |Report End|RxEOB   |OK      |
+   |        |             |             |of Batch  |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_FILE   |none      |RxAccF  |continue|
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got other    |Report    |RxDone  |Failure |
+   |        |             |known frame  |unexpected|        |        |
+   |        |             |             |frame     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got unknown  |ignore    |RxWaitF |OK      |
+   |        |             |frame        |          |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxAccF  |Decide how to|Accept from  |Report    |RxReceD |OK      |
+   |        |accept       |beginning    |receiving |        |        |
+   |        |Incoming File|             |file      |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Accept from  |Send M_GET|RxReceD |OK      |
+   |        |             |offset (we do|Report    |        |        |
+   |        |             |already have |receiving |        |        |
+   |        |             |a part of    |file,     |        |        |
+   |        |             |file)        |requested |        |        |
+   |        |             |             |offest    |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Accept later |Send      |RxWaitF |OK      |
+   |        |             |(or failed to|M_SKIP    |        |        |
+   |        |             |create file) |Report we |        |        |
+   |        |             |             |will      |        |        |
+   |        |             |             |accept    |        |        |
+   |        |             |             |file      |        |        |
+   |        |             |             |later, not|        |        |
+   |        |             |             |in current|        |        |
+   |        |             |             |session   |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Refuse       |Send M_GOT|RxWaitF |OK      |
+   |        |             |(delete on   |Report we |        |        |
+   |        |             |remote)      |do not    |        |        |
+   |        |             |             |accept    |        |        |
+   |        |             |             |file      |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxReceD |Get a frame  |Didn't got a |none      |RxReceD |OK      |
+   |        |from Input   |complete     |          |        |        |
+   |        |Buffer       |frame yet    |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got Data     |none      |RxWriteD|continue|
+   |        |             |frame        |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_ERR    |Report    |RxDone  |Failure |
+   |        |             |             |Error     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_GET /  |Add frame |RxReceD |OK      |
+   |        |             |M_GOT /      |to The    |        |        |
+   |        |             |M_SKIP       |Queue     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_NUL    |Log       |RxReceD |OK      |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_FILE   |Report    |RxAccF  |Continue|
+   |        |             |             |partially |        |        |
+   |        |             |             |received  |        |        |
+   |        |             |             |file      |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got other    |Report    |RxDone  |Failure |
+   |        |             |known frame  |unexpected|        |        |
+   |        |             |             |frame     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got unknown  |ignore    |RxReceD |OK      |
+   |        |             |frame        |          |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxWriteD|Write data to|Write Failed |Report    |RxDone  |Failure |
+   |        |file         |             |error     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |File Pos >   |Report    |RxDone  |Failure |
+   |        |             |Reported     |write     |        |        |
+   |        |             |             |beyond EOF|        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |File Pos =   |Close File|RxWaitF |OK      |
+   |        |             |Reported     |Send M_GOT|        |        |
+   |        |             |             |Report    |        |        |
+   |        |             |             |File      |        |        |
+   |        |             |             |Received  |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |File Pos <   |none      |RxReceD |OK      |
+   |        |             |Reported     |          |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxEOB   |Get a frame  |Didn't get a |none      |RxEOB   |OK      |
+   |        |from Input   |complete     |          |        |        |
+   |        |Buffer       |frame yet or |          |        |        |
+   |        |             |TxState is   |          |        |        |
+   |        |             |not TxDone   |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_ERR    |Report    |RxDone  |Failure |
+   |        |             |             |Error     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_GET /  |Add frame |RxEOB   |OK      |
+   |        |             |M_GOT /      |to The    |        |        |
+   |        |             |M_SKIP       |Queue     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_NUL    |Log       |RxEOB   |OK      |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got other    |Report    |RxDone  |Failure |
+   |        |             |known frame  |unexpected|        |        |
+   |        |             |or data frame|frame     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got unknown  |ignore    |RxEOB   |OK      |
+   |        |             |frame        |          |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxDone  |none         |none         |none      |RxDone  |OK      |
+   +-----------------------------------------------------------------+
+
+   We define the list called "PendingFiles". After we put the last
+   byte of file into output buffer, we cannot yet consider the file as
+   being successfully transmitted, thus we have to add the file to
+   this list and then look for corresponding incoming M_GET / M_GOT /
+   M_SKIP frames to remove the file from the list and decide whether
+   the file was indeed received by remote or remote will accept this
+   file later, or something else. After we have sent M_EOB frame, we
+   must wait until PendingFiles list gets empty before disconnecting.
+
+   If the connection accidentally breaks, all the files left in
+   PendingFiles are considered unsent and will be re-transmitted in
+   the next session. If the connection breaks when the remote did
+   actually receive the file (but the corresponded confirmation frame
+   (M_GOT) didn't came back to us) and we are resending this file
+   again in the next session, remote may get two copies of the same
+   file (file dupe). Binkp allows to reduce or totally suppress such
+   dupes (at a cost of performance, of course), see Non-Reliable mode
+   and "No Dupes" protocol extension (to be found in a separate
+   document at a later date).
+
+                        Table 5: Transmit Routine
+   +-----------------------------------------------------------------+
+   |TxState|Predicate(s)|Condition(s)  |Actions(s)  |Next   |Return  |
+   |-------+------------+--------------+------------+-------+--------|
+   |TxGNF  |Open next   |File opened OK|Send M_FILE |TxTryR |continue|
+   |       |file from   |              |Report      |       |        |
+   |       |outgoing    |              |sending file|       |        |
+   |       |queue       |--------------+------------+-------+--------|
+   |       |            |Failed to open|Report      |TxDone |Failure |
+   |       |            |file          |failure     |       |        |
+   |       |            |--------------+------------+-------+--------|
+   |       |            |No more files |Send M_EOB  |TxWLA  |continue|
+   |       |            |              |Report end  |       |        |
+   |       |            |              |of batch    |       |        |
+   |-------+------------+--------------+------------+-------+--------|
+   |TxTryR |Check       |TheQueue is   |none        |TxReadS|continue|
+   |       |TheQueue    |empty         |            |       |        |
+   |       |            |--------------+--------------------+--------|
+   |       |            |TheQueue is   |call ProcessTheQueue|continue|
+   |       |            |not empty     |                    |        |
+   |-------+------------+--------------+--------------------+--------|
+   |TxReadS|Read data   |Read failed   |Report Error|TxDone |Failure |
+   |       |block from  |--------------+------------+-------+--------|
+   |       |file        |Read OK,      |Send data   |TxGNF  |OK      |
+   |       |            |Reached EOF   |block frame |       |        |
+   |       |            |              |Close       |       |        |
+   |       |            |              |current file|       |        |
+   |       |            |              |Add current |       |        |
+   |       |            |              |file to     |       |        |
+   |       |            |              |PendingFiles|       |        |
+   |       |            |--------------+------------+-------+--------|
+   |       |            |Read OK, not  |Send data   |TxTryR |OK      |
+   |       |            |reached EOF   |block frame |       |        |
+   |-------+------------+--------------+------------+-------+--------|
+   |TxWLA  |Check       |TheQueue is   |none        |TxDone |OK      |
+   |       |TheQueue    |empty and     |            |       |        |
+   |       |            |RxState >=    |            |       |        |
+   |       |            |RxEOB         |            |       |        |
+   |       |            |--------------+------------+-------+--------|
+   |       |            |TheQueue is   |none        |TxWLA  |OK      |
+   |       |            |empty and     |            |       |        |
+   |       |            |RxState <     |            |       |        |
+   |       |            |RxEOB         |            |       |        |
+   |       |            |--------------+--------------------+--------|
+   |       |            |TheQueue is   |call ProcessTheQueue|continue|
+   |       |            |not empty     |                    |        |
+   |-------+------------+--------------+--------------------+--------|
+   |TxDone |none        |none          |none        |TxDone |OK      |
+   +-----------------------------------------------------------------+
+
+   We define a list called KnownFiles. This list contains files that
+   can be requested by the remote using M_GET command. This list shall
+   at least contain all the files that are part of the PendingFiles
+   list.
+
+                    Table 6: ProcessTheQueue routine
+   +-----------------------------------------------------------------+
+   | Predicate(s)       | Condition(s)       | Actions(s)            |
+   |--------------------+--------------------+-----------------------|
+   | M_GET received     | requested file is  | Report unknown file   |
+   |                    | not in the         |                       |
+   |                    | KnownFiles list    |                       |
+   |--------------------+--------------------+-----------------------|
+   | M_GET received for | Requested pos is   | Close and finalize    |
+   | a known file       | FileSize           | file.                 |
+   |                    |                    | Report that remote    |
+   |                    |                    | refused file being    |
+   |                    |                    | transmitted.          |
+   |                    |                    | Set TxState to        |
+   |                    |                    | TxGetNextFile.        |
+   |                    |--------------------+-----------------------|
+   |                    | Requested pos is   | Set file pointer to   |
+   |                    | less than FileSize | requested pos.        |
+   |                    |                    | Report that remote    |
+   |                    |                    | requested offset.     |
+   |                    |                    | Set TxState to        |
+   |                    |                    | TxReadSend.           |
+   |                    |--------------------+-----------------------|
+   |                    | Requested pos is   | Ignore frame          |
+   |                    | greater than       |                       |
+   |                    | FileSize           |                       |
+   |--------------------+--------------------+-----------------------|
+   | M_GOT file that is | none               | Close and finalize    |
+   | currently          |                    | file                  |
+   | transmitting       |                    | Report Remote refused |
+   |                    |                    | file being            |
+   |                    |                    | transmitted           |
+   |                    |                    | Set TxState to TxGNF  |
+   |--------------------+--------------------+-----------------------|
+   | M_GOT file that is | File is in         | Finalize file         |
+   | not currently      | PendingFiles list  | Report file has been  |
+   | transmitting       |                    | sent                  |
+   |                    |                    | Remove file from the  |
+   |                    |                    | PendingFiles list     |
+   |                    |--------------------+-----------------------|
+   |                    | File is not in     | Ignore frame          |
+   |                    | PendingFiles       |                       |
+   |--------------------+--------------------+-----------------------|
+   | M_SKIP file that   | none               | Close file (do not    |
+   | is currently       |                    | finalize, we will     |
+   | transmitting       |                    | send it later, not in |
+   |                    |                    | current session)      |
+   |                    |                    | Report remote will    |
+   |                    |                    | accept this file      |
+   |                    |                    | later                 |
+   |                    |                    | Set TxState to TxGNF  |
+   |--------------------+--------------------+-----------------------|
+   | M_SKIP file that   | none               | Report remote will    |
+   | is not currently   |                    | accept this file      |
+   | transmitting       |                    | later                 |
+   |                    |                    | Remove file from      |
+   |                    |                    | PendingPiles, if      |
+   |                    |                    | exists there          |
+   +-----------------------------------------------------------------+
+
+  6.3 Session Termination
+  -----------------------
+
+   A session may be terminated in any of the following cases:
+
+          should be deemed aborted due to a fatal error.
+          should be deemed aborted due to non-fatal error typically
+       because of temporary lack of resources to proceed with the
+       session.
+             * all the files have been sent
+          * we have received M_EOB from the remote side (there are no
+            more files for us),
+          * we have received acknowledgements for all the files sent,
+          * we have received all the files re-requested by M_GET,
+       In this case, the session should be deemed successfully
+       completed.
+
+   A session termination itself is not a protocol stage. Mailer may
+   terminate a session at any time simply by issuing disconnect
+   (shutdown) command to the underlying transport layer, provided any
+   of the three conditions above are met. Mailer MUST take all proper
+   steps to provide a graceful shutdown of the transport layer, as it
+   is the transport layer that is responsible for all the data
+   transmitted by one side to be received by another before
+   disconnection, provided that shutdown of the transport layer
+   protocol was successful.
+
+7. Recommended Protocol Extensions
+----------------------------------
+
+   This section documents already implemented and proposed extensions
+   for the binkp/1.0. These extensions are purely optional and are
+   included here for the sake of compatibility with future
+   implementations.
+
+   Sides indicate supported protocol extensions by sending M_NUL
+   frame(s) with "OPT list_of_extensions" string, where
+   list_of_extensions is a space separated list of supported protocol
+   extensions. Whenever multiple M_NUL "OPT ..." frames are received
+   during the session, they SHOULD augment the current list of
+   extensions rather than replace it, unless specifically stated
+   otherwise for a particular option.
+
+   Mailer SHOULD NOT use any extension unless exactly sure that this
+   extension is supported by the remote. Mailer SHOULD use M_NUL "OPT
+   ..." to indicate supported options. Other methods for indicating
+   supported extensions are allowed as long as the provide full
+   backwards compatibility.
+
+  7.1 Non-reliable Mode
+  ---------------------
+
+   Non-reliable mode solves the problem with frequently aborted
+   connections when the sides can not successfully complete file
+   transfer before connection is broken. In this case, if the
+   transmitting side starts retransmission from offset 0, performance
+   degrades as by the time it receives M_GET from the remote, network
+   buffers are already full and by the time they are freed for
+   retransmission from requested offset, the connection might go down
+   again.
+
+   In order to circumvent this problem, a mailer can request the
+   remote to enter non-reliable mode by sending a M_NUL "OPT NR" frame
+   at any time during the session. After the remote acknowledges it by
+   sending an M_NUL "OPT NR" frame indicating that the option is
+   supported, both sides can assume that they are in non-reliable
+   mode.
+
+   When session is in non-reliable mode, the transmitting side may
+   send -1 for the offset value in M_FILE command. If it does so, it
+   should wait for the M_GET frame from the receiving side that
+   explicitly specifies file offset and start transmitting file data
+   from this offset. If the receiving side has indicated that it
+   supports non-reliable mode by sending M_NUL "OPT NR" frame, it must
+   recognize -1 as the file offset in M_FILE command as an explicit
+   request for the file offset and transmit an appropriate M_GET frame
+   as soon as possible.
+
+   It should be understood that this option degrades performance over
+   regular quality connections and it should be used only if
+   absolutely necessary.
+
+  7.2 Multiple Batch Mode
+  -----------------------
+
+   The session is in MB mode if both sides set "MB" flag in any of
+   M_NUL "OPT" packets exchanged before sending of M_OK/M_PWD packets.
+
+   In MB mode both sides restart session from RxDone into InitTransfer
+   state if there were any command packets sent or received by any
+   side between starting at InitTransfer and exchanging of M_EOB by
+   the sides (RxDone state). Otherwise, the session terminates as
+   usual.
+
+   Multiple batches mode is intended to handle WaZOO [FTS-0006] file
+   requests. If there were any WaZOO request files transferred in a
+   batch, sides MAY process them and send resulting files in the next
+   batch. Mailers MAY also generate list of files to send in
+   additional batches by other techniques -- including rescanning of
+   their spools or processing of other magic files transferred before
+   in the same session.
+
+  7.3 Multiple Passwords Mode
+  ---------------------------
+
+   Multiple password mode allows to specify different passwords for
+   the different addresses of the remote.
+
+   Originating side identifies it's multipassword capabilities by
+   sending M_NUL "OPT MPWD" during session setup stage before sending
+   any M_ADR commands and waits for response from the answering side.
+
+   If answering side responds with the M_NUL "OPT MPWD", then it
+   supports multiply passwords too. Answering side also always
+   responds with it's own address list: M_ADR "adr1 adr2 adr3 ...". If
+   M_NUL "OPT MPWD" was not received prior to the first M_ADR command,
+   originating side should assume that the remote does not support
+   multiple password mode and send a single password (if any) for one
+   of the addresses of the remote.
+
+   If the MPWD option was indicated by the answering side, originating
+   side now may send M_PWD "pwd1 pwd2 pwd3 ..." with the number of
+   entries in space separated password list equivalent to the number
+   of addresses presented by the answering side. If there is no
+   password for a particular address, it must send '-' character as a
+   placeholder.
+
+   If the passwords presented are consistent, answering side must
+   acknowledge successful authentication by sending M_OK command.
+
+  7.4 Keyed Hashing Challenge-Response Authentication Mechanism
+  -------------------------------------------------------------
+
+    7.4.1 Overview
+    --------------
+
+   Challenge-Response Authentication Mechanism (CRAM) allows to avoid
+   passing cleartext, reusable passwords across the network. Since it
+   utilizes Keyed-Hashing digests [Keyed], it does not require
+   password to be stored in the clear on the Mailer's media, allowing
+   storage of the intermediate results which are known as "contexts".
+
+   Providing binkp-mailer is capable of [Keyed] digest calculation and
+   conversion of a byte array to a hexadecimal string and back,
+   implementation of CRAM is easily achieved by slightly modifying the
+   state machine.
+
+    7.4.2 Sequence of Steps
+    -----------------------
+
+   CRAM adds an additional synchronization step to binkp protocol. The
+   description of this step follows:
+
+          the Originating side, encoded to a hexadecimal string.
+          hexadecimal string, and a password to produce a digest by
+       applying the keyed Hashing algorithm from [Keyed] where the key
+       is the password and the digested text is the challenge data.
+          digest provided. If the digest is correct, the answering side
+       should consider the Originating side authenticated and responds
+       appropriately.
+
+   Similar technique is used in [IMAP-AUTH].
+
+    7.4.3 Generating and Transmitting Challenge Data
+    ------------------------------------------------
+
+   Size and contents of challenge data are implementation-dependent,
+   but it SHOULD be no smaller than 8 bytes and no bigger than 64
+   bytes. Answering side SHOULD never generate the same challenge
+   data.
+
+   Instead of generating a long challenge data, answering side MAY use
+   a hash function to shorten it. In calculation of a challenge data
+   answering side MAY also use connection/line number, caller's IP
+   address, current time, etc.
+
+   Answering side transmits challenge data in the very first M_NUL
+   message, in the following way:
+
+   M_NUL "OPT [othropt] CRAM-lsthf-cde [othropt]"
+
+   lsthf is a list of aliases of supported hash functions, delimited
+   by slash characters. The list begins with alias of the most
+   preferred and ends with alias of the least preferred hash function.
+
+   Currently defined aliases are: MD5 for [MD5] and SHA1 for [SHA-1].
+
+   cde is the challenge data encoded to hexadecimal string, Lower-case
+   ASCII characters MUST be used for encoding, but Mailer SHOULD also
+   accept upper-case characters. The length of the string MUST be
+   even, and the leading zeros MUST NOT be trimmed.
+
+    7.4.4 Producing and Transmitting a Digest
+    -----------------------------------------
+
+   Originating side responds with:
+
+   M_PWD "CRAM-chosenhf-khde [othropt]"
+
+   where chosenhf is the alias of the chosen hash function and khde is
+   the keyed hashed digest, encoded to a hexadecimal string.
+
+   According to [IMAP-AUTH], keyed hashed digest is produced by
+   calculating
+
+   HASH((secret XOR opad), HASH((secret XOR ipad), challengedata))
+
+   where HASH is chosen hash function, ipad and opad are 36 hex and 5C
+   hex (as defined in [Keyed]) and secret is a password null-padded to
+   a length of 64 bytes. If the password is longer than 64 bytes, the
+   hash-function digest of the password is used as an input (16-byte
+   for [MD5] and 20-byte for [SHA-1]) to the keyed hashed calculation.
+
+    7.4.6 Indicating CRAM Capabilities
+    ----------------------------------
+
+   Answering side MUST send
+
+   M_NUL "OPT [othropt] CRAM-lsthf-cde [othropt]"
+
+   as a very first M_NUL message if it supports CRAM.
+
+   It MAY send other non-M_NUL messages before though. Current
+   specification doesn't define any such non-M_NUL message, they are
+   reserved for protocol extension.
+
+   Originating side MUST be ready to receive non-M_NUL before M_NUL in
+   a CRAM session. Binkp state machine MUST ignore any received
+   message of unknown type in order to be compatible with future
+   extensions.
+
+   If an originating side receives a first message that is a M_ADR or
+   a M_NUL message that is not
+
+   M_NUL "OPT [othropt] CRAM-lsthf-cde [othropt]"
+
+   it MUST decide that the answering side doesn't support CRAM and MAY
+   either disconnect or use old password exchange. If the sides have
+   no any compatible hash function, originator may also either
+   disconnect or use old password exchange. If an originating side
+   decides to disconnect, it SHOULD send M_ERR frame with a proper
+   explanation before disconnecting.
+
+   When parsing M_NUL "OPT ..." string (coming from the answering
+   side), originating side first splits it by using space delimiter to
+   get a list of options, and then if an option begins with
+   "CRAM-lsthf-", takes the remaining substring as a
+   hexadecimal-encoded challenge data.
+
+    7.4.7 Example of Frame Exchange During CRAM Authentication
+    ----------------------------------------------------------
+
+   (Password here is tanstaaftanstaaf)
+
+   Originating :
+     send M_NUL messages
+     and M_ADR
+     wait for first M_NUL message
+
+   Answering   :
+     send M_NUL "OPT ND CRAM-SHA1/MD5-f0315b074d728d483d6887d0182fc328"
+     and other messages
+     wait for M_PWD
+
+   Originating :
+     M_PWD "CRAM-MD5-56be002162a4a15ba7a9064f0c93fd00"
+
+   Answering   :
+     M_OK and continue session
+
+    7.4.8 Notes on Hash Function Algorithms
+    ---------------------------------------
+
+   [MD5] and [SHA-1] are the most widely used cryptographic hash
+   functions. [MD5] has been shown to be vulnerable to collision
+   search attacks [Dobb]. This attack and other currently known
+   weaknesses of [MD5] do not compromise the use of [MD5] within CRAM
+   as specified in this document (see [Dobb]); however, [SHA-1]
+   appears to be a cryptographically stronger function. To this date,
+   [MD5] can be considered for use in CRAM for applications where the
+   superior performance of [MD5] is critical. In any case,
+   implementors and users need to be aware of possible cryptanalytic
+   developments regarding any of these cryptographic hash functions,
+   and the eventual need to replace the underlying hash function.
+
+8. License
+----------
+
+   You can implement binkp protocol in your software as long as you
+   agree to the following conditions:
+
+          other way. You shall include the author(s) of the protocol in
+       your copyright statement for the software.
+          versions. Binkp allows development of the new capabilities
+       without compromising interoperability with previous versions.
+       Therefore, it is important that future developments of the
+       protocol are not pursued in different directions by different
+       people. If you have any suggestions regarding future
+       developments of the protocol, make a reasonable effort to
+       contact the author(s), so that the development efforts can
+       coordinated in a way advantageous for everybody.
+          future binkp specifications, you shall reference to it as a
+       "binkp variation" or "binkp derived".
+
+   Remember that you may use, implement or utilize binkp, it's
+   description or any other associated texts or documentations at your
+   own risk, without any warranty, without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
+
+   Binkp author: Dima Maloff.
+
+9. Glossary
+-----------
+
+   Many entries in this glossary are provided courtesy of Butterfly
+   Glossary of Internet and Data Communication terms and RFC-1983.
+
+   connection-oriented
+           Data communication method in which communication proceeds
+           through three well-defined phases: connection
+           establishment, data transfer, connection release. TCP is a
+           connection-oriented protocol.
+
+   data link layer
+           The OSI layer that is responsible for data transfer across
+           a single physical connection, or series of bridged
+           connections, between two Network entities.
+
+   flow control
+           A technique for ensuring that a transmitting entity does
+           not overwhelm a receiving entity.
+
+   HDLC
+           (High level Data Link Control). Popular ISO standard
+           bit-oriented, data link layer protocol derived from SDLC.
+           HDLC specifies an encapsulated method of data on
+           synchronous serial data links.
+
+   IP
+           (Internet Protocol). The Internet Protocol, defined in STD
+           5, RFC 791, is the network layer for the TCP/IP Protocol
+           Suite. It is a connectionless, best-effort packet switching
+           protocol.
+
+   network layer
+           Layer 3 of the OSI reference model. Layer 3 is the layer at
+           which routing, addressing and connection management take
+           place.
+
+   OSI (Open Systems Interconnection) Reference Model
+           A seven-layer structure designed to describe computer
+           network architectures and the way that data passes through
+           them. This model was developed by the ISO (International
+           Organization for Standardization) in 1978 to clearly define
+           the interfaces in multivendor networks, and to provide
+           users of those networks with conceptual guidelines in the
+           construction of such networks.
+
+   port
+           A port is a transport layer demultiplexing value. Each
+           application has a unique port identifier associated with
+           it.
+
+   physical layer
+           The OSI layer that provides the means to activate and use
+           physical connections for bit transmission. In plain terms,
+           the Physical Layer provides the procedures for transferring
+           a single bit across a Physical Media.
+
+   Quality of Service
+           (Also QoS). A measure of performance for a transmission
+           system that reflects its transmission quality and
+           availability of service.
+
+   reliable transmission
+           a type of transport service that:
+              * recovers from errors by retransmitting errored frames
+              * delivers frames in correct sequence (also known as
+                stream-oriented)
+              * usually is used in connection-oriented mode
+
+   session layer
+           Layer 5 of the OSI reference model. Coordinates session
+           activity between applications, including application-layer
+           error control, dialog control, and remote procedure calls.
+
+   sliding window flow control
+           Method of flow control in which a receiver gives
+           transmitter permission to transmit data until a window is
+           full. When the window is full, the transmitter must stop
+           transmitting until the receiver advertises a larger window.
+
+   socket
+           Software structure operating as a communications and point
+           within a network device.
+
+   TCP
+           Transmission Control Protocol. An Internet Standard
+           transport layer reliable protocol defined in STD 7, RFC
+           793. It is connection-oriented and stream-oriented.
+
+   TCP/IP protocol suite
+           Transmission Control Protocol over Internet Protocol. This
+           is a common shorthand which refers to the suite of
+           transport and application protocols which runs over IP.
+
+   transport layer
+           Layer 4 of the OSI reference model. The transport layer is
+           responsible for reliable network communication between end
+           nodes. It implements flow and error control and often uses
+           virtual circuits to ensure reliable data delivery.
+
+   unixtime
+           number of seconds elapsed since 00:00:00 UTC, Jan. 1, 1970.
+
+10. References
+--------------
+
+   [FTS-0001]
+           A Basic FidoNet(r) Technical Standard, Revision 16. Randy
+           Bush, Pacific Systems Group, September 30, 1995. FTS-0001.
+
+   [FTS-0006]
+           YOOHOO and YOOHOO/2U2. The netmail handshake used by
+           Opus-CBCS and other intelligent Fidonet mail handling
+           packages. Version 002, Vince Perriello. 30-Nov-1991.
+           FTS-0006.
+
+   [FSC-0039]
+           M.Howard, A type-2 packet extension proposal, FSC-0039
+           Version 4, 29-Sep-1990. FSC-0039.
+
+   [FSC-0045]
+           T.Henderson, Proposed new packet header, Version 1,
+           17-Apr-1990. FSC-0045.
+
+   [FSC-0048]
+           J.Vroonhof, Proposed type-2 packet extension, Version 2,
+           21-Oct-1990. FSC-0048.
+
+   [FSC-0081]
+           M.Staldal, A type-3 packet proposal, Version 1,
+           01-Mar-1995. FSC-0081.
+
+   [EMSI]
+           Joaquim H. Homrighausen, EMSI/IEMSI protocol definition.
+           May 3, 1991. FSC-0056.
+
+   [FTA-1006]
+           Key words to indicate requirement levels, Fidonet Technical
+           Standards Committee administrative. FTA-1006.
+
+   [Halsall95]
+           Data Communications, Computer Networks and Open Systems, F.
+           Halsall, 4th ed., Addison-Wesley, 1995, ISBN 0-201-42293-X.
+
+   [Dobb]
+           H. Dobbertin, "The Status of MD5 After a Recent Attack",
+           RSA Labs' CryptoBytes, Vol. 2 No. 2, Summer 1996.
+
+   [MD5]
+           Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321,
+           April 1992.
+
+   [SHA-1]
+           NIST, FIPS PUB 180-1: Secure Hash Standard, April 1995.
+
+   [Keyed]
+           Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for
+           Message Authentication", RFC 2104, February 1997.
+
+   [IMAP-AUTH]
+           Klensin, "IMAP/POP AUTHorize Extension for Simple
+           Challenge/Response", RFC 2195, September, 1997
+
+   [RFC822]
+           Standard for the format of ARPA Internet text messages. D.
+           Crocker. Aug-13-1982. RFC 822, STD0011.
+
+   [UTF8]
+           UTF-8, a transformation format of ISO 10646. F. Yergeau.
+           January 1998, RFC 2279.
+
+   [ISO10646]
+           ISO/IEC 10646-1:1993. International Standard -- Information
+           technology -- Universal Multiple-Octet Coded Character Set
+           (UCS) -- Part 1: Architecture and Basic Multilingual Plane.
+           Five amendments and a technical corrigendum have been
+           published up to now. UTF-8 is described in Annex R,
+           published as Amendment 2.
+
+11. Acknowledgements
+--------------------
+
+   This document is partially based on extracts from RFCs and FTSC
+   publications too numerous to be acknowledged individually.
+
+   The authors would like to thank Joaquim Homrighausen, Kim 'B'
+   Heino, Rune Johansen and many others for fruitful discussions and
+   suggestions regarding protocol design and specifications.
+
+A. Author Contact Data
+-----------------------
+
+   Dima Maloff
+   Fidonet: 2:5020/128
+   E-mail: maloff@corbina.net
+   WWW: http://www.corbina.net/~maloff/
+
+   Maxim Masiutin
+   Fidonet: 2:469/84
+   E-mail: max@ritlabs.com
+   WWW: http://www.ritlabs.com/
+
+   Nick Soveiko
+   Fidonet: 2:5030/23.101
+   E-mail: nsoveiko@doe.carleton.ca
+   WWW: http://www.doe.carleton.ca/~nsoveiko/
+
+B. History
+----------
+
+   Rev.1, 19990611:
+           First release
+
+   Rev.2, 19991008:
+              * Added new topic: "Definitions";
+              * clarified the following topics: "Frame Format",
+                "Protocol Commands and Their Arguments", "Keyed
+                Hashing Challenge-Response Authentication Mechanism";
+              * added "unixtime" item to Glossary topic;
+              * corrected links in References topic.
+
+   Rev.3, 20000731:
+              * Table 6 in section 6.2, File transfer stage has been
+                rewritten: TheListOfSendFiles replaced by PendingFiles
+                which was defined earlier. introduced definition of
+                KnownFiles list. new ProcessTheQueue routine w/respect
+                to handling M_GET command
+              * Section 5.2, File Name Issues was rewritten to clearly
+                define safe and unsafe characters in filenames.
+              * Section 5.3, Non-ASCII Characters was rewritten to
+                clarify Unicode usage.
+              * Expanded descriptions for M_NUL "TIME ...", M_NUL "TRF
+                ...", added description of M_NUL "PHN ..." and M_NUL
+                "OPM ..." frames in section 5.4 Binkp Commands.
+              * IANA port number added to section 3, Protocol
+                Overview.
+              * M_GET description in section 5.4, Binkp Commands was
+                rewritten for clarity.
+              * M_BSY "RETRY ..." option documented.
+              * Minor edits throughout the document to improve
+                readability.
+
+Back Go Back + + diff --git a/html/ftsc/fta-1005.html b/html/ftsc/fta-1005.html new file mode 100755 index 00000000..0cd34d52 --- /dev/null +++ b/html/ftsc/fta-1005.html @@ -0,0 +1,268 @@ + + +FTSC Product ID List. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FTA-1005
+Revision:       3
+Title:          FTSC Product Codes
+Author:         Administrator
+Revision Date:  22 March 1998
+Expiry Date:    22 March 1998
+----------------------------------------------------------------------
+Contents:
+                1. Format of product code list
+                2. Application for a product code
+----------------------------------------------------------------------
+
+
+1. Format of product code list
+------------------------------
+
+  The FTSC publishes a list of all product codes issued. The filename
+  is FTSCPROD.nnn, where nnn is a number which increases with each
+  revision.
+
+  The list is an ASCII text file with one line per product. Each line
+  contains a number of fields, delimited by commas. Some fields may
+  contain more than one value. In this case, the different values are
+  delimited with a forward slash ('/'). Spaces in fields are replaced
+  with underscores ('_'). Fields are not case-sensitive.
+
+  These are the fields which are currently defined:
+
+    code,name,platform,type,contact,netaddr[,assigned[,updated]]
+
+  code      The product code. 4 digits hexadecimal.
+  name      Product name.
+  platform  Platforms(s) supported.
+  type      Type(s) of product.
+  contact   Name of contact person.
+  netaddr   FidoNet address of contact person.
+  assigned  Date the product code was originally assigned.
+  updated   Date of last update of the product code data.
+
+  Platforms
+  ---------
+  See the list for examples. (Will be specified more firmly later).
+
+  Product types
+  -------------
+  Mailer    A mailer is a product that exchanges mail with FTS-0001,
+            FTS-0006, EMSI or other protocols that include a product
+            code field.
+  Packer    A packer is a product that creates .PKT files.
+
+  Dates
+  -----
+  The format is YYYYMMDD. A date field may also be blank.
+
+  If you write software which is dependant on this format, please make
+  it tolerant of additional fields after these for upwards
+  compatibility.
+
+
+2. Application for a product code
+---------------------------------
+
+  FidoNet products without an allocated product code which either
+  create Type-2 packets, or negotiate FTS-0001 sessions must use a
+  product code FEh (254d) in Type-2 compatible packet headers. This
+  code as been reserved for that purpose (use by product without a
+  product code). The product code FFh (255d) has been reserved to
+  indicate that the product code is stored elsewhere in the packet
+  header at an as yet unallocated offset.
+
+  The FTSC is currently working on an update to the Type-2 packet
+  specification, to allow 16-bit codes while keeping full backward
+  compatibility with 8-bit codes (something which the current Type-2
+  proposals in the FSC's are not). Until the specification is ready,
+  16-bit codes are issued with the low byte set to FFh (255d).
+
+  Below is an application form for an FTSC product code, which is used
+  to identify your product when used in FidoNet, and providing a means
+  by which you can be contacted should your product be found
+  responsible for problems encountered during its use. The issuance of
+  this product code in no way implies authorisation or approval of
+  your product for use on the network, only provides a means of ready
+  identification.
+
+  This application should be completed and submitted for only `real'
+  and completed products which will be used by FidoNet systems. If you
+  are currently developing a product which is not yet ready for use on
+  the network out of experimental stage, use product code 0 (zero)
+  which is, by convention, reserved for this purpose.
+
+  Please answer the questions as accurately and completely as
+  possible. We need to know what will actually be used on the net, so
+  describe only the current product, and leave future features and
+  plans for the comments section.
+
+  Send the completed form to the administrator of the FidoNet
+  Technical Standards Committee. Please see FTA-1003 for addresses.
+
+  We hope that you will take the time to revise your answers by
+  submitting updates as your product changes. A summary of the
+  information you provide is compiled into a list of all product codes
+  published and updated periodically by the FTSC called
+  "FTSCPROD.nnn".
+
+
+A. Application Form
+-------------------
+
+--- Cut along here ---------------------------------------------------
+
+FTSC Product Code Application
+=============================
+
+Type of application
+-------------------
+
+1.  Mark whichever is appropriate:
+
+    ____  New product application
+    ____  Update existing product       for existing product code ____
+
+
+2.  If this is an update, please briefly state the nature of the
+    update (change author's node number, change of product name, etc.)
+
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+
+Product information
+-------------------
+
+3.  What is the name of the product and the current version name or
+    number?
+
+    __________________________________________________________________
+
+
+4.  What is the name, FidoNet node, and postal address, and voice
+    number of the person(s) or organization responsible for the
+    product?  Where should inquiries be directed and who should be
+    contacted if the product is thought to cause errors on the
+    network?
+
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+
+5.  What operating systems does it currently run on?
+
+    __________________________________________________________________
+
+
+6.  Does the product contain a 'mailer'?  E.g. the package transmits
+    mail to other FidoNet systems and can fall back to FTS-0001,
+    though it may handle other protocols.
+
+    __________________________________________________________________
+
+
+7.  If the answer to question (6) is yes, what additional protocols
+    other than FTS-0001 does the product support? Refer to the
+    specific FTSC document which details this protocol, if any.
+
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+
+    With what additions or restrictions?
+
+    __________________________________________________________________
+
+
+8.  Is the package capable of servicing file requests, and if so,
+    'Bark' style (FTS-0008) and/or WaZOO .REQ (FTS-0006) or both?
+
+    __________________________________________________________________
+
+
+    With what additions or restrictions?
+
+    __________________________________________________________________
+
+
+9.  Is your software capable of functioning as a Continuous Mail
+    system? i.e. nodes running it might be marked as such in the
+    FidoNet nodelist?
+
+    __________________________________________________________________
+
+
+10. How is the product distributed?
+
+    Public Domain  ____________          Shareware      ______________
+    Commercial     ____________          Other          ______________
+    Object code    ____________          Source code    ______________
+
+    Comments: ________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+
+11. Please give additional comments to describe your product.
+
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+--- Cut along here ---------------------------------------------------
+
+
+B. Acknowledgements
+-------------------
+
+  The application form was inspired by one originally published in
+  FSC-0022 and later FSC-0090, originally by Bob Hartman, Jim Long,
+  and Randy Bush and modified by Rick Moore and David Nugent.
+
+
+C. History
+----------
+
+  Rev.1, 19970407: First non-draft release. Author Adrian Walker.
+  Rev.2, 19971229: Author changed to Administrator. Reformatted
+                   document slightly. Changed all dates in the lists
+                   to 4 digit centuries. Added information about
+                   status of 16-bit product codes.
+  Rev.3, 19980322: Moved the product code list out of the document and
+                   into a separate list, FTSCPROD.nnn. Added an
+                   application form. Revised text about 16 bit codes.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0001.html b/html/ftsc/fts-0001.html new file mode 100755 index 00000000..42085282 --- /dev/null +++ b/html/ftsc/fts-0001.html @@ -0,0 +1,1260 @@ + + +A Basic FidoNet(r) Technical Standard. + + + + +
+Document: FTS-0001
+Version:  016
+Date:     30-Sep-95
+
+
+
+
+                     A Basic FidoNet(r) Technical Standard
+|                                Revision 16
+                      Formerly known as FSC001,  FSC-0001
+|                      Randy Bush, Pacific Systems Group
+|                             September 30, 1995
+
+
+
+
+Status of this document:
+
+    This FTS  (FidoNet(r)  Technical  Standard)  specifies  a  standard  for
+    the FidoNet community. FidoNet nodes are expected to adopt and implement
+    this standard. Distribution is subject to the restrictions stated in the
+    copyright paragraph below.
+
+    Fido and FidoNet are registered marks of Tom Jennings and Fido Software.
+
+    Copyright  1986-95,  Randy  Bush.  All  rights  reserved.   A  right  to
+    distribute only  without modification  and only at no charge is granted.
+    Under no  circumstances is this document to be reproduced or distributed
+    as  part of  or packaged with any product or other sales transaction for
+    which any fee is charged.  Any and all other reproduction  or excerpting
+    requires the explicit written consent of the author.
+
+
+ A. Introduction
+
+    FidoNet  has  grown  beyond  most  peoples' fantasies, and  new  FidoNet
+    implementations  are appearing regularly.  Unfortunately, the  scattered
+    nature of the documentation and absence of clear testing procedures have
+    made  implementation  difficult.   FidoNet, in its desire to promote and
+    encourage  FidoNet  implementations,  suggested  a  project  to create a
+    technical  standard for  FidoNet.  The author did not  design or specify
+    the data formats or protocols, only attempted to document them.
+
+    This  document defines the  data structures and communication  protocols
+    which a FidoNet implementation must provide.  The implementor of FidoNet
+    compatible systems is the intended audience of this document.
+
+    The  layered metaphor of the ISO Open Systems Interface reference  model
+    has been used to view FidoNet from a standard perspective.  As with most
+    prospective  ISO/OSI  descriptions, FidoNet  does not always  make  this
+    easy.
+
+    The  content of this document  was gleaned from the references given  at
+    the  end.
+
+    Please direct technical comments and errata to
+|     Randy Bush                       randy@psg.com
+|     Pacific Systems Group
+      9501 S.W. Westhaven Drive
+      Portland, Oregon  US-97225
+|
+
+   1. Basic Requirements for a FidoNet Implementation
+
+      Compatibility is a set of abilities which, when taken as a whole, make
+      it safe to list a net or node in the FidoNet nodelist. In other words,
+      if  another  node should attempt  contact, does it have  a  reasonable
+      chance  of successful communication?  This is a social obligation,  as
+      the  calling  system  pays  money  for the  attempt.   Conversely,  an
+      implementation  should be able to successfully contact other  systems,
+      as life is not a one-way street.
+
+      A FidoNet implementation must be able to call other nodes and transfer
+      messages and files in both directions.  This includes pickup and poll.
+      A FidoNet implementation must be able to accept calls from other nodes
+      and  transfer  messages and  files in both directions.  This  includes
+      pickup.
+
+      FidoNet implementations must be able to receive and process the FidoNet
+      format  nodelist, and transfer nodelists to other nodes.  A  companion
+      document,  FTS-0005, defines the FidoNet format nodelist  and  how  to
+      interpret and process it.
+
+      A  FidoNet implementation must route messages which do not have  files
+      attached through net hosts as shown in a FidoNet format nodelist.
+
+
+   2. Levels of Compliance
+
+      This  documents represents the  most basic FidoNet implementation.   A
+      future  document will define well tested extensions which are optional
+      but  provide sufficient  additional function that implementors  should
+      seriously   consider   them.   SEAdog(tm),  from  System   Enhancement
+      Associates,  is  an  excellent  example  of such an  extended  FidoNet
+      implementation.
+
+
+   3. The ISO/OSI Reference Model (cribbed from "Protocol Verification via
+      Executable Logic Specifications", D. P. Sidhu, in Rudin & West)
+
+      In  the ISO/OSI model, a distributed system consists of entities  that
+      communicate  with  each other  according  to a set of rules  called  a
+      protocol.   The  model is  layered, and there are entities  associated
+      with  each layer of the model which provide services to higher  layers
+      by  exchanging information with their peer entities using the services
+      of  lower layers.  The only actual physical communication between  two
+      systems is at the lowest level.
+
+      Several  techniques  have  been  used  in the  specification  of  such
+      protocols.  A common ingredient in all techniques is the notion of the
+      extended  finite  state automata  or machine.  Extensions include  the
+      addition of state variables for the storing of state information about
+      the  protocol.  The state of an  automation can change as a result  of
+      one of the following events:
+
+      o Request from an upper network layer for service
+
+      o Response to the upper layer
+
+      o Request to the lower network layer to perform a service
+
+      o Response from the lower layer
+
+      o Interaction with the system and environment in which the protocol is
+        implemented (e.g. timeouts, host operating system aborts, ...)
+
+      A  protocol  specification, in  a large part, consists  of  specifying
+      state  changes  in  automata  which  model protocol  entities  and  in
+      describing the data which they exchange.
+
+      For  historical  reasons,  the  term  packet  is used  in  FidoNet  to
+      represent a bundle of messages, as opposed to the more common use as a
+      unit of communication, which is known as a block in FidoNet.
+
+
+   4. Data Description
+
+      A  language  specific  notation  was avoided.  Please help  stamp  out
+      environmental  dependencies.   Only  you  can  prevent  PClone  market
+      dominance.  Don't panic, there are rectangular record layouts too.
+
+      (* non-terminals *)
+      UpperCaseName - to be defined further on
+
+      (* literals *)
+      "ABC"         - ASCII character string, no termination implied
+      nnH           - byte in hexadecimal
+
+      (* terminals *)
+      someName      - 16-bit integer, low order byte first (8080 style)
+      someName[n]   - field of n bytes
+      someName[.n]  - field of n bits
+      someName(n)   - Null terminated string allocated n chars (incl Null)
+      someName{max} - Null terminated string of up to max chars (incl Null)
+
+      (* punctuation *)
+      a b           - one 'a' followed by one 'b'
+      ( a | b )     - either 'a' or 'b', but not both
+      { a }         - zero or more 'a's
+      [ b ]         - zero or one 'b'
+      (* comment *) - ignored
+
+      (* predeclared constant *)
+      Null          = 00H
+
+
+
+ 5. Finite State Machine Notation
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         |  St |
+    |-----+----------+-------------------------+-------------------------+-----|
+    | fnn*|          |                         |                         |     |
+    `-----+----------+-------------------------+-------------------------+-----'
+
+    State #      - Number of this state (e.g. R13).
+                   f  - FSM initial (Window, Sender, Receiver, ...)
+                   nn - state number
+                   *  - state which represents a lower level protocol  which
+                        is represented by yet another automation.
+
+    State Name   - Descriptive name of this state.
+
+    Predicate(s) - Conditions which terminate the state.  If predicates are
+                   non-exclusive, consider them ordered.
+
+    Action(s)    - Action(s) corresponding to predicate(s)
+
+    Next State   - Subsequent state corresponding to predicate(s)
+
+    Ideally,  there  should be  a  supporting section for each  state  which
+    should  give a prose description of the state, its predicates,  actions,
+    etc.  So much for ideals.
+
+
+ B. Application Layer : the System from the User's View
+
+    The application layer is outside the domain of a FidoNet standard, as it
+    is the layer that the user's application sees as opposed to what FidoNet
+    sees.   In  recent  months,  there  has been  sufficient  confusion  and
+    discussion  about  the  format  of  data at this level  to  warrant  the
+    description  of the data structure, the message as it is stored by Fido,
+    SEAdog, and Rover.
+
+    Perfectly valid FidoNet systems may be implemented whose stored messages
+    differ greatly from this format.
+
+
+   1. Application Layer Data Definition : a Stored Message
+
+                               Stored Message
+
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |                                               |
+              ~                 fromUserName                  ~
+              |                   36 bytes                    |
+              +-----------------------+-----------------------+
+       36  24 |                                               |
+              ~                  toUserName                   ~
+              |                   36 bytes                    |
+              +-----------------------+-----------------------+
+       72  48 |                                               |
+              ~                    subject                    ~
+              |                   72  bytes                   |
+              +-----------------------+-----------------------+
+      144  90 |                                               |
+              ~                    DateTime                   ~
+              |                    20 bytes                   |
+              +-----------------------+-----------------------+
+      164  A4 | timesRead (low order) | timesRead (high order)|
+              +-----------------------+-----------------------+
+      166  A6 | destNode (low order)  | destNode (high order) |
+              +-----------------------+-----------------------+
+      168  A8 | origNode (low order)  | origNode (high order) |
+              +-----------------------+-----------------------+
+      170  AA |   cost (low order)    |   cost (high order)   |
+              +-----------------------+-----------------------+
+      172  AC | origNet (low order)   | origNet (high order)  |
+              +-----------------------+-----------------------+
+      174  AE | destNet (low order)   | destNet (high order)  |
+              +-----------------------+-----------------------+
+      176  B0 | destZone (optional)   | destZone (optional)   |
+              +-----------------------+-----------------------+
+      178  B2 | origZone (optional)   | origZone (optional)   |
+              +-----------------------+-----------------------+
+      180  B4 | destPoint(optional)   | destPoint(optional)   |
+              +-----------------------+-----------------------+
+      182  B6 | origPoint(optional)   | origPoint(optional)   |
+              +-----------------------+-----------------------+
+      184  B8 |  replyTo (low order)  |  replyTo (high order) |
+              +-----------------------+-----------------------+
+      186  BA | Attribute (low order) | Attribute (high order)|
+              +-----------------------+-----------------------+
+      188  BC | nextReply (low order) | nextReply (high order)|
+              +-----------------------+-----------------------+
+      190  BE |                      text                     |
+              ~                    unbounded                  ~
+              |                 null terminated               |
+              `-----------------------------------------------'
+
+      Message    = fromUserName(36)  (* Null terminated *)
+                   toUserName(36)    (* Null terminated *)
+                   subject(72)       (* see FileList below *)
+                   DateTime          (* message body was last edited *)
+                   timesRead         (* number of times msg has been read *)
+                   destNode          (* of message *)
+                   origNode          (* of message *)
+                   cost              (* in lowest unit of originator's
+                                        currency *)
+                   origNet           (* of message *)
+                   destNet           (* of message *)
+                   destZone          (* of message *)
+                   origZone          (* of message *)
+                   destPoint         (* of message *)
+                   origPoint         (* of message *)
+                   replyTo           (* msg to which this replies *)
+                   AttributeWord
+                   nextReply         (* msg which replies to this *)
+                   text(unbounded)   (* Null terminated *)
+
+      DateTime   = (* a character string 20 characters long *)
+                                     (* 01 Jan 86  02:34:56 *)
+                   DayOfMonth " " Month " " Year " "
+                   " " HH ":" MM ":" SS
+                   Null
+
+      DayOfMonth = "01" | "02" | "03" | ... | "31"   (* Fido 0 fills *)
+      Month      = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" |
+                   "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"
+      Year       = "01" | "02" | .. | "85" | "86" | ... | "99" | "00"
+      HH         = "00" | .. | "23"
+      MM         = "00" | .. | "59"
+      SS         = "00" | .. | "59"
+
+      AttributeWord   bit       meaning
+                      ---       --------------------
+                        0  +    Private
+                        1  + s  Crash
+                        2       Recd
+                        3       Sent
+                        4  +    FileAttached
+                        5       InTransit
+                        6       Orphan
+                        7       KillSent
+                        8       Local
+                        9    s  HoldForPickup
+                       10  +    unused
+                       11    s  FileRequest
+                       12  + s  ReturnReceiptRequest
+                       13  + s  IsReturnReceipt
+                       14  + s  AuditRequest
+                       15    s  FileUpdateReq
+
+                             s - need not be recognized, but it's ok
+                             + - not zeroed before packeting
+
+      Bits numbers ascend with arithmetic significance of bit position.
+
+
+      Message Text
+
+      Message text is unbounded and null terminated (note exception below).
+
+      A 'hard' carriage return, 0DH,  marks the end of a paragraph, and must
+      be preserved.
+
+      So   called  'soft'  carriage  returns,  8DH,  may  mark  a   previous
+      processor's  automatic line wrap, and should be ignored.  Beware  that
+      they may be followed by linefeeds, or may not.
+
+      All  linefeeds, 0AH, should be ignored.  Systems which display message
+      text should wrap long lines to suit their application.
+
+      If the first character of a physical line (e.g. the first character of
+      the  message text, or the character immediately after a hard  carriage
+      return (ignoring any linefeeds)) is a ^A (, 01H), then that
+      line  is  not  displayed  as  it  contains  control  information.  The
+      convention for such control lines is:
+        o They begin with ^A
+        o They end at the end of the physical line (i.e. ignore soft s).
+        o They begin with a keyword followed by a colon.
+        o The keywords are uniquely assigned to applications.
+        o They keyword/colon pair is followed by application specific data.
+
+      Current ^A keyword assignments are:
+|     o TOPT  - destination point address
+      o FMPT  - origin point address
+      o INTL   - used for inter-zone address
+
+
+      File Specifications
+
+      If  one  or more  of FileAttached, FileRequest, or  FileUpdateReq  are
+      asserted  in an AttributeWord, the subject{72} field is interpreted as
+      a  list of file specifications  which may include wildcards and  other
+      system-dependent data.  This list is of the form
+
+      FileList = [ FileSpec { Sep FileSpec } ] Null
+
+      FileSpec = (* implementation dependent file specification.  may
+                    not contain Null or any of the characters in Sep. *)
+
+      Sep      = ( " " | "," )  { " " }
+
+
+      There are deviations from and additions to these specifications
+
+      1  - Fido does not necessarily terminate the message text with a Null,
+           but  uses  an empty line (0DH 0AH 0DH 0AH).  Some  Fido utilities
+           use an EOF (1AH).
+
+      2 - SEAdog zeros the message cost field when building a message.
+
+      4 - SEAdog uses a different format for dates, e.g.
+
+      DateTime   = (* a character string 20 characters long *)
+                   (* SEAdog format Mon  1 Jan 86 02:34 *)
+                   DayOfWk " " DayOfMo " " Month " " Year " " HH ":" MM Null
+
+      DayOfWk    = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
+      DayOfMo    = " 1" | " 2" | " 3" | ... | "31"  (* blank fill *)
+
+
+
+   2. Application Layer Protocol : Schedules and Events
+
+      At  the application level, FidoNet imposes few protocol  requirements.
+      An   implementation   must   automatically   originate   and   receive
+      node-to-node  FidoNet  connections.   Some implementations do this  in
+      'windows'  or  time  slots.   Routing  of  messages  will  usually  be
+      different and customizable for each scheduled window.
+
+      The ability to send to and receive from any FidoNet listed node during
+      the Zone Mail Hour (eg. 9:00-10:00 UCT in Z1) is considered mandatory.
+
+      Current  implementations assemble all data for outbound connections at
+      the  start of a window, and  disassemble inbound data at the end of  a
+      window.   Due to performance considerations on small machines, this is
+      considered  a valid optimization.   Observe that it somewhat  inhibits
+      dynamic routing.
+
+
+ C. Presentation Layer : the User from the System's View
+
+   1. Presentation Layer Data Definition : the Packed Message
+
+      To  conserve space and eliminate fields which would be meaningless  if
+      sent  (e.g. timesRead), messages are packed for transmission.  As this
+      is  a data structure which is actually transferred, its definition  is
+      critical  to FidoNet.  A packed  message has a number of fixed  length
+      fields followed by four null terminated strings.
+
+      While  most of the string fields in a stored message are fixed length,
+      to  conserve space strings are variable length when in a packet.   All
+      variable  length strings are all Null terminated, including especially
+      the message text.
+
+
+                                Packed Message
+
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |    0     |     2      |    0      |    0      |
+              +-----------------------+-----------------------+
+        2   2 | origNode (low order)  | origNode (high order) |
+              +-----------------------+-----------------------+
+        4   4 | destNode (low order)  | destNode (high order) |
+              +-----------------------+-----------------------+
+        6   6 | origNet (low order)   | origNet (high order)  |
+              +-----------------------+-----------------------+
+        8   8 | destNet (low order)   | destNet (high order)  |
+              +-----------------------+-----------------------+
+       10   A | Attribute (low order) | Attribute (high order)|
+              +-----------------------+-----------------------+
+       12   C |   cost (low order)    |   cost (high order)   |
+              +-----------------------+-----------------------+
+       14   E |                                               |
+              ~                    DateTime                   ~
+              |                    20 bytes                   |
+              +-----------------------+-----------------------+
+       34  22 |                  toUserName                   |
+              ~                  max 36 bytes                 ~
+              |                null terminated                |
+              +-----------------------+-----------------------+
+              |                 fromUserName                  |
+              ~                  max 36 bytes                 ~
+              |                null terminated                |
+              +-----------------------+-----------------------+
+              |                    subject                    |
+              ~                  max 72 bytes                 ~
+              |                null terminated                |
+              +-----------------------+-----------------------+
+              |                      text                     |
+              ~                    unbounded                  ~
+              |                 null terminated               |
+              `-----------------------------------------------'
+
+      Due  to routing, the origin and  destination net and node of a  packet
+      are  often quite different from  those of the messages within it,  nor
+      need  the origin and destination nets and nodes of the messages within
+      a packet be homogenous.
+
+      PakdMessage  = 02H 00H           (* message type, old type-1 obsolete *)
+                     origNode          (* of message *)
+                     destNode          (* of message *)
+                     origNet           (* of message *)
+                     destNet           (* of message *)
+                     AttributeWord
+                     cost              (* in lowest unit of originator's
+                                          currency *)
+                     DateTime          (* message body was last edited *)
+                     toUserName{36}    (* Null terminated *)
+                     fromUserName{36}  (* Null terminated *)
+                     subject{72}       (* Null terminated *)
+                     text{unbounded}   (* Null terminated *)
+
+
+
+
+
+
+
+ 2. Presentation Layer Protocol : a Mail Window
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W0  | WindTop  | 1 end of window reached | reset modem to not answr| exit|
+   |     |          | 2 time remains in window| ensure modem can answer | W1  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W1  | WindIdle | 1 incoming call         |                         | W2  |
+   |     |          | 2 receive-only mode     |                         | W0  |
+   |     |          | 3 send-only mode        |                         | W3  |
+   |     |          | 4 60-180 secs & no call |                         | W3  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W2* | WindRecv |                         | (receive call R0)       | W3  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W3  | WindCall | 1 select outgoing call  | increment try count     | W4  |
+   |     |          | 2 no outgoing calls     |                         | W0  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W4* | WindSend |                         | (make call S0)          | W5  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W5  | WindMark | 1 call successful       | remove node fr call list| W0  |
+   |     |          | 2 no connect            | remove if try cnt > lim | W0  |
+   |     |          | 3 call failed           | incr conn cnt, remove   | W0  |
+   |     |          |                         |   if con cnt > lim      |     |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+    The  length of the inter-call delay time at W1.4 is not critical.  It is
+    important that this not be a constant, so two systems calling each other
+    do  not incur infinite busy signals.  Sophisticated implementations  may
+    vary  the  inter-call delay  depending  on number of calls to  be  made,
+    window width, user specification, etc.
+
+
+ D. Session Layer Protocol : Connecting to Another FidoNet Machine
+
+    A session is a connection between two FidoNet machines.  It is currently
+    assumed  to be over the  DDD telephone network via modems.  The  calling
+    machine starts out as the sender and the called machine as the receiver.
+    The  pickup  feature is described  by the sender and  receiver  changing
+    roles  midway through the session, after the sender has transferred  the
+    message  packet and any attached files.  Due to the lack of security  in
+    the  pickup protocol (danger of pickup by a fake node), a change in  the
+    protocol may be expected in the near future.
+
+    Once  a connection has been established, each system should ensure  that
+    the  physical connection remains  throughout the session.  For  physical
+    layers  implemented  through modems,  this means monitoring the  carrier
+    detect signal, and terminating the session if it is lost.
+
+    Error  detection at the physical layer should be monitored for both sent
+    and  received  characters.  Parity,  framing, and other physical  errors
+    should be detected.
+
+    Sender
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S0  | SendInit |                         | dial modem              | S1  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S1  | WaitCxD  | 1 carrier detected      | delay 1-5 seconds       | S2  |
+   |     |          | 2 busy, etc.            | report no connection    | exit|
+   |     |          | 3 voice                 | report no carrier       | exit|
+   |     |          | 4 carrier not detected  | report no connection    | exit|
+   |     |          |   within 60 seconds     |                         |     |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S2  | WhackCRs | 1 over 30 seconds       | report no response  | exit|
+   |     |          | 2 ?? s received     | delay 1 sec             | S3  |
+   |     |          | 3 s not received    | send    | S2  |
+   |     |          |                         |   delay ??? secs        |     |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S3  | WaitClear| 1 no input for 0.5 secs | send TSYNCH = AEH       | S4  |
+   |     |          | 2 over 60 seconds       | hang up, report garbage | exit|
+   |     |          |   and line not clear    |                         |     |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S4* | TSyncChk | 1 'C' or NAK (peeked at)| (XMODEM send packet XS1)| S5  |
+   |     |          | 2 over 2 seconds        | eat noise, resend TSYNCH| S4  |
+   |     |          | 3 over 30 seconds       | hang up report not Fido | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S5  | CheckMail| 1 XMODEM successful     | (Fido registers success)| S6  |
+   |     |          | 2 XMODEM fail or timeout| hang up, report mail bad| exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S6* | SendFiles|                         | (BATCH send files BS0)  | S7  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S7  | CheckFile| 1 BATCH send successful |                         | S8  |
+   |     |          | 2 BATCH send failed     | hang up, rept files fail| exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S8  | TryPickup| 1 wish to pickup        | note send ok            | R2* |
+   |     |          | 2 no desire to pickup   | delay 5 secs            | exit|
+   |     |          |                         |   hang up, rept send ok |     |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+    Although  the  above  shows  the  sender  emitting only one  TSYNCH,  it is
+    recommended  that a timeout of 5-20 seconds should initiate another TSYNCH.
+    The receiver should tolerate multiple TSYNCHs.
+
+    In state S4, the phrase "peeked at" means that the character is not removed
+    from the buffer.  Therefore when XS1 is started the proper character for
+    beginning the Xmodem transfer will be detected.
+
+   Receiver
+
+    The  receiving FSM is given  an external timer, the expiration of  which
+    will cause termination with a result of 'no calls' (R0.2).
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R0  | WaitCxD  | 1 carrier detected      |                         | R1  |
+   |     |          | 2 external timer expires| report no calls         | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R1  | WaitBaud | 1 baud rate detected    | send signon with s  | R2  |
+   |     |          | 2 no detect in ?? secs  | hang up, report no baud | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R2  | WaitTsync| 1 TSYNCH received       | ignore input not TSYNCH | R3  |
+   |     |          | 2 60 seconds timeout    | hang up, report not Fido| exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R3* | RecMail  |                         | (XMODEM rec packet XR0) | R4  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R4  | XRecEnd  | 1 XMODEM successful     | delay 1 second          | R5  |
+   |     |          |                         |   flush input           |     |
+   |     |          | 2 XMODEM failed         | hang up, rept mail fail | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R5* | RecFiles |                         | (BATCH rec files BR0)   | R6  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R6  | ChkFiles | 1 BATCH recv successful | delay 2 secs            | R7  |
+   |     |          | 2 BATCH recv failed     | hang up, report bad file| exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R7  | AllowPkup| 1 have pickup for sender| receiver becomes sender | S3* |
+   |     |          | 2 nothing to pickup     | hang up, rept recv ok   | exit|
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+ E. Transport Layer : ?????
+
+   1. Data Definitions
+
+   2. Transport Layer Protocol : Routing
+
+      FidoNet   does  not  necessarily  send  a  message  directly  to   its
+      destination.   To reduce the number of network connections, mail to  a
+      subset  of  the  nodelist  may  be  routed  to one  node  for  further
+      distribution  within  that  subset.   In addition, custom  routing  is
+      possible.  Routing of a message is determined in one of three ways.
+
+      o If there are files attached, then a message must be sent directly to
+        its destination.
+
+      o Messages without attached files should be routed through the inbound
+        host  of the destination  node's  subnet  as specified  by a FidoNet
+        format nodelist.
+
+      o To prevent overloading of inbound hosts, a system should provide for
+        host routing to be disabled for a target node, or nodes.
+
+
+ F. Network Layer : the Network's View of the System, Routing and Packets
+
+
+   1. Network Layer Data Definition : the Packet Header
+
+      The  packet contains messages in packed format to be transferred  over
+      the  net during a connection.  As this data structure is  transferred,
+      its definition is critical to FidoNet.
+
+      A  packet may contain zero or more packed messages.  A packet  without
+      messages is often generated as a poll packet.
+
+      Every  packet begins with a  packet header.  The fields of the  packet
+      header are of fixed length.
+
+
+                                Packet Header
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 | origNode (low order)  | origNode (high order) |
+              +-----------------------+-----------------------+
+        2   2 | destNode (low order)  | destNode (high order) |
+              +-----------------------+-----------------------+
+        4   4 |   year (low order)    |   year (high order)   |
+              +-----------------------+-----------------------+
+        6   6 |  month (low order)    |  month (high order)   |
+              +-----------------------+-----------------------+
+        8   8 |   day (low order)     |   day (high order)    |
+              +-----------------------+-----------------------+
+       10   A |   hour (low order)    |   hour (high order)   |
+              +-----------------------+-----------------------+
+       12   C |  minute (low order)   |  minute (high order)  |
+              +-----------------------+-----------------------+
+       14   E |  second (low order)   |  second (high order)  |
+              +-----------------------+-----------------------+
+       16  10 |   baud (low order)    |   baud (high order)   |
+              +-----------------------+-----------------------+
+       18  12 |    0     |     2      |    0      |    0      |
+              +-----------------------+-----------------------+
+       20  14 | origNet (low order)   | origNet (high order)  |
+              +-----------------------+-----------------------+
+       22  16 | destNet (low order)   | destNet (high order)  |
+              +-----------------------+-----------------------+
+       24  18 |       prodCode        |       serialNo        |
+              +-----------------------+-----------------------+
+       26  1A |                                               |
+              |             password   (some impls)           |
+              |                  eight bytes                  |
+              |                  null padded                  |
+              |                                               |
+              +-----------------------+-----------------------+
+       34  22 | origZone (low) (opt)  | origZone (high) (opt) |
+              +-----------------------+-----------------------+
+       36  24 | destZone (low) (opt)  | destZone (high) (opt) |
+              +-----------------------+-----------------------+
+       38  26 |                     fill                      |
+              ~                   20 bytes                    ~
+              |                                               |
+              +-----------------------+-----------------------+
+       58  3A |                 zero or more                  |
+              ~                    packed                     ~
+              |                   messages                    |
+              +-----------------------+-----------------------+
+              |    0     |     0      |    0     |     0      |
+              `-----------------------+-----------------------'
+
+
+      Packet       = PacketHeader  { PakdMessage }  00H 00H
+
+      PacketHeader = origNode   (* of packet, not of messages in packet *)
+                     destNode   (* of packet, not of messages in packet *)
+                     year       (* of packet creation, e.g. 1986 *)
+                     month      (* of packet creation, 0-11 for Jan-Dec *)
+                     day        (* of packet creation, 1-31 *)
+                     hour       (* of packet creation, 0-23 *)
+                     minute     (* of packet creation, 0-59 *)
+                     second     (* of packet creation, 0-59 *)
+                     baud       (* max baud rate of orig and dest, 0=SEA *)
+                     PacketType (* old type-1 packets now obsolete *)
+                     origNet    (* of packet, not of messages in packet *)
+                     destNet    (* of packet, not of messages in packet *)
+                     prodCode   (* 0 for Fido, write to FTSC for others *)
+                     serialNo   (* binary serial number (otherwise null)*)
+                     password   (* session password  (otherwise null)   *)
+                     origZone   (* zone of pkt sender (otherwise null)  *)
+                     destZone   (* zone of pkt receiver (otherwise null)*)
+                     fill[20]
+
+      PacketType   = 02H 00H  (* 01H 00H was used by Fido versions before 10
+                                 which did not support local nets.  The packed
+                                 message header was also different for those
+                                 versions *)
+
+      prodCode     = (  00H      (* Fido *)
+                     |  ...
+                     |  ??H      (* Please apply for new codes *)
+                     )
+
+
+      The  remainder of the packet consists of packed messages.  Each packed
+      message  begins  with  a  message type word 0200H.   A  pseudo-message
+      beginning with the word 0000H signifies the end of the packet.
+
+
+   2. Network Layer Data Description : a File with Attributes
+
+      The  BATCH  protocol uses  the MODEM7 filename and TeLink/XMODEM  file
+      transfer protocols to transfer the file with attributes.
+
+      When  a  file is transferred via  FidoNet, an attempt is made to  also
+      pass  the operating system's attributes  for the file such as  length,
+      modification  date, etc.  FidoNet does this via a special prefix block
+      to  the XMODEM file transfer using a protocol known as TeLink.  As the
+      TeLink  protocol relies on a modification to the XMODEM file  transfer
+      protocol, it is documented at the data link layer level.
+
+      The  MODEM7 file name is redundant if there is also a TeLink block, in
+      which case the name may be taken from either or both.
+
+                              FileName as Sent
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |                   fileName                    |
+              ~                   8  bytes                    ~
+              |           left adjusted blank filled          |
+              +-----------------------+-----------------------+
+        8   8 |                    fileExt                    |
+              ~                    3  bytes                   ~
+              |           left adjusted blank filled          |
+              `-----------------------------------------------'
+
+
+ 3. Network Layer Protocol : BATCH File Finite State Machines
+
+
+    BATCH File Sender
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BS0*| MoreFiles| 1 more files to send    | (MODEM7 FName send MS0) | BS1 |
+   |     |          | 2 no more files to send |                         | BS3 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BS1 | CheckFNm | 1 MODEM7 Filename ok    | (TeLink send file XS0)  | BS2 |
+   |     |          | 2 MODEM7 Filename bad   | report name send bad    | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BS2 | CheckFile| 1 TeLink send ok        |                         | BS0 |
+   |     |          | 2 TeLink send bad       | report file send bad    | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BS3 | EndSend  | 1 rec NAK for next file | send EOT, report send ok| exit|
+   |     |          | 2 10 seconds no NAK     | send EOT, report no NAK | exit|
+   `-----+----------+-------------------------+-------------------------+-----'
+
+    When  no files remain, the sender responds to the receiver's NAK with an
+    EOT.  The EOT is not ACK/NAKed by the receiver.
+
+    Filenames  must be upper case ASCII.  The data link layer uses "u" as  a
+    control character.
+
+
+    BATCH File Receiver
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BR0*| RecvName |                         | (MODEM7 FName recv MR0) | BR1 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BR1 | CheckFNm | 1 MODEM7 no more files  | report files recd ok    | exit|
+   |     |          | 2 MODEM7 Filename ok    | (TeLink recv file XR0)  | BR2 |
+   |     |          | 2 MODEM7 Filename bad   | report name recv bad    | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BR2 | CheckFile| 1 TeLink recv ok        |                         | BR0 |
+   |     |          | 2 TeLink recv bad       | report file recv bad    | exit|
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+ G. Data Link Layer : Error-Free Data Transfer
+
+   1. Data Link Layer Data Definition : XMODEM/TeLink Blocks
+
+      XMODEM  transfers  are  in  blocks  of 128  uninterpreted  data  bytes
+      preceded  by  a three  byte header  and followed by either a one  byte
+      checksum  or a two byte crc remainder.  XMODEM makes no provision  for
+      data  streams  which  are  not  an  integral number  of  blocks  long.
+      Therefore,  the sender pads streams whose length is not a multiple  of
+      128 bytes with the end-of-file character (^Z for MS-DOS), and use some
+      other  means  to convey  the  true data length to the  receiver  (e.g.
+      TeLink file info block).
+
+      Data blocks contain sequence numbers so the receiver can ensure it has
+      the  correct block.  Block  numbers are sequential unsigned eight  bit
+      integers  beginning with 01H and wrapping to 00H, except that a TeLink
+      block is given sequence number 00H.
+
+      For  files which are attached to the mail packet, not the mail  packet
+      itself,  if the sending system is aware of the file attributes as they
+      are  known to the operating system, then the first block of the XMODEM
+      transfer  may be a special TeLink block to transfer that  information.
+      This  block  differs  in that  the  first byte is a SYN  character  as
+      opposed  to an SOH, and it is always sent checksum as opposed to CRC.
+      Should the receiver be unwilling to handle such information, after two
+      NAKs (or "C"s), the sender skips this special block and goes on to the
+      data itself.
+
+
+
+                        XMODEM Data Block (CRC mode)
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |        SOH  -  Start Of Header -  01H         |
+              +-----------------------------------------------+
+        1   1 |                 BlockNumber                   |
+              +-----------------------------------------------+
+        2   2 |               BlockComplement                 |
+              +-----------------------------------------------+
+        3   3 |                128 bytes  of                  |
+              ~                uninterpreted                  ~
+              |                    data                       |
+              +-----------------------------------------------+
+      131  83 |             CRC high order byte               |
+              +-----------------------------------------------+
+      132  84 |             CRC  low order byte               |
+              `-----------------------------------------------'
+
+
+
+                      XMODEM Data Block (Checksum mode)
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |        SOH  -  Start Of Header -  01H         |
+              +-----------------------------------------------+
+        1   1 |                 BlockNumber                   |
+              +-----------------------------------------------+
+        2   2 |               BlockComplement                 |
+              +-----------------------------------------------+
+        3   3 |                128 bytes  of                  |
+              ~                uninterpreted                  ~
+              |                    data                       |
+              +-----------------------------------------------+
+      131  83 |                Checksum byte                  |
+              `-----------------------------------------------'
+
+
+                       TeLink File Descriptor Block
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       SYN  -  File Info Header -  16H         |
+              +-----------------------------------------------+
+        1   1 |                     00H                       |
+              +-----------------------------------------------+ data offset
+        2   2 |                     FFH                       |  dec  hex
+              +-----------------------------------------------+
+        3   3 |     File Length, least significant byte       |  0    0
+              +-----------------------------------------------+
+        4   4 | File Length, second to least significant byte |  1    1
+              +-----------------------------------------------+
+        5   5 |  File Length, second to most significant byte |  2    2
+              +-----------------------------------------------+
+        6   6 |      File Length, most significant byte       |  3    3
+              +-----------------------------------------------+
+        7   7 |            Creation Time of File              |  4    4
+              |                "DOS Format"                   |
+              +-----------------------------------------------+
+        9   9 |            Creation Date of File              |  6    6
+              |                "DOS Format"                   |
+              +-----------------------------------------------+
+       11   B |                 File  Name                    |  8    8
+              ~                  16 chars                     ~
+              |        left justified  blank filled           |
+              +-----------------------------------------------+
+       27  1B |                    00H                        | 24   18
+              +-----------------------------------------------+
+       28  1C |            Sending Program Name               | 25   19
+              ~                  16 chars                     ~
+              |         left justified  Null filled           |
+              +-----------------------------------------------+
+       44  2C |            01H (for CRC) or 00H               | 41   29
+              +-----------------------------------------------+
+       45  2D |                    fill                       | 42   2A
+              ~                  86 bytes                     ~
+              |                  all zero                     |
+              +-----------------------------------------------+
+      132  84 |                Checksum byte                  |
+              `-----------------------------------------------'
+
+
+
+      XMODEMData   = XMODEMBlock      (* block of data with header and
+                                         trailer *)
+                     | TeLinkBlock    (* TeLink File Descriptor Block *)
+                     | ACK            (* acknowledge data received ok *)
+                     | NAK            (* negative ACK & poll 1st block *)
+                     | EOT            (* end of xfer, after last block *)
+                     | "C"            (* 43H *)
+
+      XMODEMBlock  = SOH              (* Start of Header, XMODEM Block *)
+                     blockNumber[1]   (* sequence, i'=mod( i+1, 256 ) *)
+                     blockCompl[1]    (* one's compl of BlockNumber *)
+                     data[128]        (* uninterpreted user data block *)
+                     (CRC | Checksum) (* error detect/correction code *)
+
+      TeLinkBlock  = SYN              (* File Info Header *)
+                     00H              (* block no, must be first block *)
+                     FFH              (* one's complement of block no *)
+                     fileLength[4]    (* length of data in bytes *)
+                     CreationTime[2]  (* time file last modified or zero *)
+                     CreationDate[2]  (* date file last modified or zero *)
+                     fileName(16)     (* name of file, not vol or dir *)
+                     00H              (* header version number *)
+                     sendingProg(16)  (* name of program on send side *)
+                     crcMode[1]       (* 01H for CRC 00H for Checksum *)
+                     fill[87]         (* zeroed *)
+                     Checksum         (* error detect/correction code *)
+
+      ACK          = 06H              (* acknowledge data received ok *)
+      NAK          = 15H              (* negative ACK & poll 1st block *)
+      SOH          = 01H              (* start of header, begins block *)
+      SYN          = 16H              (* start of TeLink file info blk *)
+      EOT          = 04H              (* end of xfer, after last block *)
+
+      CRC          = crc[2]           (* CCITT Cyclic Redundancy Check *)
+
+      Checksum     = checksum[1]      (* low 8 bits of sum of data bytes
+                                         using unsigned 8 bit arithmetic *)
+
+      CreationDate = year[.7]         (* 7 bits, years since 1980, 0-127  *)
+                     month[.4]        (* 4 bits, month of year, 1-12 *)
+                     day[.5]          (* 5 bits, day of month, 1-31 *)
+
+      CreationTime = hour[.5]         (* 5 bits, hour of day, 0-23 *)
+                     minute[.6]       (* 6 bits, minute of hour, 0-60 *)
+                     biSeconds[.2]    (* 6 bits, seconds/2, 0-29 *)
+
+
+      Note  that the crcMode is always set to 01H in current implementations
+      as  all TeLink/XMODEM implementations use the CRC method.   Therefore,
+      it is always set to 01H by the sender, and is ignored by the receiver.
+
+
+ 2. Data Link Layer Protocol : XMODEM/TeLink Finite State Machines
+
+    The  protocol is receiver driven, the receiver polling the sender  for
+    each  block.   If the receiver polls  for the first block using a  "C"
+    (43H)  as  the poll character,  it would prefer to have the  CRC-CCITT
+    polynomial  remainder error detection code at the end of each block as
+    opposed  to a one byte unsigned checksum.  The sender will respond  to
+    the  "C"  poll iff it can  comply.  If the sender chooses checksum  as
+    opposed  to  CRC, it waits for  the receiver to poll with  NAK  (15H).
+    Should  the  checksum method be  preferable to the receiver, it  polls
+    with NAK rather than "C".
+
+    The sender returns an EOT instead of a data block when no data remain.
+
+    Neither  the  sender nor the  receiver should send the block or  ACK/NAK
+    response  while there is data being received.  They should wait for  the
+    line to settle, and possibly time out.
+
+    It  is  suggested that one's  input buffer be cleared immediately  after
+    sending  block or ACK/NAK response, before waiting for the response from
+    the  other  end.  This  clears  any line garbage which  occurred  during
+    transmit.
+
+
+    XMODEM/TeLink Sender
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS0 | WaitTeLnk| 1 over 40-60 seconds    | report sender timeout   | exit|
+   |     |          | 2 over 2 tries          | note TeLink block failed| XS1 |
+   |     |          | 3 NAK or "C" received   | send TeLink, incr tries | XS0 |
+   |     |          | 4 ACK received          | TeLink ok, set crc/cksm | XS2 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS1 | WaitStart| 1 over 40-60 seconds    | report sender timeout   | exit|
+   |     |          | 2 over 20 tries         | report send failed      | exit|
+   |     |          | 3 NAK received          | set checksum mode       | XS2 |
+   |     |          | 4 "C" recd, I can crc   | set crc mode            | XS2 |
+   |     |          | 5 "C" recd, I can't crc |                         | XS1 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS2 | SendBlock| 1 more data available   | send next data block    | XS3 |
+   |     |          |                         |   as checksum or crc    |     |
+   |     |          | 2 last block has gone   | send EOT                | XS4 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS3 | WaitACK  | 1 10 retries or 1 minute| report send failed      | exit|
+   |     |          | 2 ACK received          |                         | XS2 |
+   |     |          | 3 NAK (or C if 1st blk) | resend last block       | XS3 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS4 | WaitEnd  | 1 10 retries or 1 minute| report send failed      | exit|
+   |     |          | 2 ACK received          | report send successful  | exit|
+   |     |          | 3 NAK received          | resend EOT              | XS4 |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+    XMODEM/TeLink Receiver
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XR0 | RecStart | 1 prefer crc mode       | Send "C"                | XR1 |
+   |     |          | 2 want checksum mode    | send NAK                | XR1 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XR1 | WaitFirst| 1 10 retries or 1 minute| report receive failure  | exit|
+   |     |          | 2 > 3 retries or 30 secs| set want checksum mode  | XR0 |
+   |     |          | 3 EOT received          | delay < sec, purge input| exit|
+   |     |          |                         | send ACK, report no file|     |
+   |     |          | 4 TeLink block recd     | send ACK, set crc/cksm  | XR2 |
+   |     |          | 5 data block recd       | send ACK, set crc/cksm  | XR2 |
+   |     |          | 6 bad block or 2-10 secs| incr retry count        | XR0 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XR2 | WaitBlock| 1 10 retries or 1 minute| report receive failure  | exit|
+   |     |          | 2 EOT received          | send ACK, report recd ok| exit|
+   |     |          |                         | send ACK, report recd ok|     |
+   |     |          | 3 data block received   | send ACK                | XR2 |
+   |     |          | 4 bad block or 2-10 secs| send NAK, incr retry cnt| XR2 |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+    A  number of checks should be made to ensure a valid data block has been
+    received.
+
+    o  The  physical  layer  should  have encountered no errors,  e.g.  parity,
+       framing, etc.
+
+    o  The length of the block should not be less than expected.
+
+    o  If  the blocks sequence  number does not match the  complement,  then
+       respond with a NAK and attempt to read the block again.
+
+    o  If the block's sequence number is one previous (remember wrap around)
+       to that of the expected block, respond with an ACK and read again.
+
+    o  If the sequence number fits neither of the above criteria, and is yet
+       not the expected sequence number, abort the receive.
+
+    o  The checksum or CRC should be correct.
+
+
+
+ 3. Data Link Layer Protocol : MODEM7 Filename Finite State Machines
+
+
+    MODEM7 Filename Sender
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         |  St |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MS0 | WaitNak  | 1 20 retries or 1 minute| filename send failed    | exit|
+   |     |          | 2 NAK received          | send ACK & 1st ch of fn | MS1 |
+   |     | (note 1) | 3 C received            | return fn skipped       | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MS1 | WaitChAck| 1 ACK rcd, fname done   | send SUB = 1AH          | MS2 |
+   |     |          | 2 ACK rcd, fname ~done  | send next ch of fname   | MS1 |
+   |     |          | 3 other char or 1 sec   | send "u", incr retry cnt| MS0 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MS2 | WaitCksm | 1 cksum recd and ok     | send ACK, report fn ok  | exit|
+   |     |          | 2 cksum recd but bad    | send "u", incr retry cnt| MS0 |
+   |     |          | 3 no cksum in 1 sec     | send "u", incr retry cnt| MS0 |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+    MODEM7 Filename Receiver
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         |  St |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MR0 | SendNak  | 1 20 tries or 1 minute  | report filename failure | exit|
+   |     |          | 2                       | send NAK, incr try cnt  | MR1 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MR1 | WaitAck  | 1 rcd ACK               |                         | MR2 |
+   |     |          | 2 rcd EOT               | report no files remain  | exit|
+   |     |          | 3 5 secs & no ACK/EOT   |                         | MR0 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MR2 | WaitChar | 1 recd EOT (can happen?)| report no files remain  | exit|
+   |     |          | 2 recd SUB              | send checksum byte      | MR3 |
+   |     |          | 3 recd "u"              |                         | MR0 |
+   |     |          | 4 recd char of name     | send ACK                | MR2 |
+   |     |          | 5 no char in 1 second   |                         | MR0 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MR3 | WaitOkCk | 1 recd ACK within 1 sec | report recd filename ok | exit|
+   |     |          | 2 recd "u" or other char|                         | MR0 |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+    SUB  is the ASCII character ^Z or 1AH.  The checksum is the unsigned low
+    order eight bits of the sum of the characters in the transferred filename
+    including the SUB.
+
+    Although  one second timeouts are used successfully by Fido and  SEAdog,
+    some fear that this is too small a timeout for some satellite and packet
+    network links.
+
+    Note 1 - MS0.3 is a common addition to accommodate a common noncompliance.
+             Support of MS0.3 is optional for a compliant mailer.  This hack
+             also requires modification of a number of state tables, see
+             FSC-0011.
+
+
+ H. Physical Layer : the Actual Connection of Two FidoNet Systems
+
+    Will  one of the more hardware-oriented comm types give me some idea  of
+    what's needed here?  Can we leave it open enough to allow implementation
+    over a non-dial net?  Thanks.
+
+
+ I. Revisions since FTS-0001
+
+    89 Oct 25 (rev 13)
+      o packet header: optional serialNo, password, and orig/dest zone
+      o stored message to/from zone/point info added as option per
+        Fido-12 and Dutchie
+      o XR1 and XR2 changes per FSC-0011
+      o reference to FSC-0011 for the MODEM7-avoidance hack, MS0.3
+      o dropped enumeration of product codes
+      o S4 modification from FSC-0011
+      o Nodelist and EID reference appropriate documents
+      o various cosmetics
+    90 July 1-5 (rev 14)
+      o spelling errors caught by Ray Gardner
+      o references to the now dead IFNA elided
+      o offset at end of Packed Message was 10 as opposed to 20 bytes
+      o Packed Message and Packet Header corrections by Roland Gautschi
+      o Offsets in TeLink header caught by Rick Moore
+    90 August 30 (rev 15)
+      o corrected offsets in packet header
+    95 September 30 (rev 16)
+      o TOPT corrected
+      o contact info changed
+
+
+ J. Acknowledgements
+
+    Ben  Baker,  Thom  Henderson,  Tom  Jennings,  Ken Kaplan, and  Gee Wong
+    suggested, informed,  reviewed, and  encouraged.   Tom  and Thom gave me
+    all the basics, and even allowed me to look at actual code.  Bob Hartman 
+    was  foolish  enough  to implement  the  specification, and was generous
+    with useful feedback.  Ray  Gardner caught  my  spelling errors ,
+    and Roland Gautschi and Rick Moore found offset and length errors.
+
+    My employer, Pacific Systems Group was kind enough to donate my time to
+    research and to write this document.
+
+    Fido and FidoNet are registered trademarks of Tom Jennings.
+
+    SEAdog is a trademark of System Enhancement Associates.
+
+
+ K. Bibliography
+
+    Documentation  for the protocols  and data formats are scattered.   Some
+    are  unattributed, some even untitled.
+
+    Anonymous, changes to MODEM to implement CRC option  XMDM-CRC.TXT
+
+    Baker, Ken and Moore, Rick, Nodelist Definition, currently FTS-0005
+
+    Christensen, Ward, "MODEM Protocol Overview" of 1 January 82  XMODEM.TXT
+
+    Hartman, Bob, "Some thoughts that I had on FSC001", FSC-0011
+
+    Henderson, Thom, "SEAdog Electronic Mail System Version 3" of April 86
+
+    International  Standards Organization,  "Data Processing - Open  Systems
+    Interconnection - Basic Reference Model"  ISO/DIS 7498  April 82
+
+    Jennings,   Tom,  "FidoNet  Electronic  Mail  Protocol"  8  February  85
+    FIDOMAIL.DOC
+
+    Jennings,   Tom,  "Fido's  Internal  Structures"  of  13  September  85
+    STRUCT.TXT aka STRUCT.APX
+
+    Jennings, Tom, "Extending XMODEM/MODEM File Transfer Protocol to support
+    DOS" 20 September 83   FILEXFER.DOC
+
+    Jordan, Larry, "XMODEM File Transfer Protocol"  XMDM-LJ.TXT
+
+    Rudin,   H   and   West,  C,  "Protocol  Specification,   Testing,   and
+    Verification,  III" Proceedings of  the IFIP WG 6.1 Third  International
+    Workshop   on   Protocol  Specification,  Testing,   and   Verification,
+    Rueschlikon Switzerland 31 May - 2 June 1983.
+
+    Tanenbaum, Andrew, "Computer Networks" Prentice Hall 1981
+
+    Messages generated by Fido 11w, SEAdog 3.8, and QMail 1.01
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0004.html b/html/ftsc/fts-0004.html new file mode 100755 index 00000000..33d6f901 --- /dev/null +++ b/html/ftsc/fts-0004.html @@ -0,0 +1,414 @@ + + +Echomail Specification. + + + + +
+FTS-0004        EchoMail Specification
+
+This document is directly derived from the documentation of
+
+-------------------------------------------------------------------------------
+
+                           The Conference Mail System
+                                        
+                                       By
+                                  Bob Hartman
+                       Sysop of FidoNet(tm) node 132/101
+                                        
+                  (C) Copyright 1986,87, Spark Software, Inc.
+                                        
+                              427-3 Amherst Street
+                              CS  2032, Suite  232
+                              Nashua,  N.H.  03061
+                                        
+                              ALL RIGHTS RESERVED.
+
+-------------------------------------------------------------------------------
+
+version 3.31 of 12 December, 1987.
+
+With Bob Hartman's kind consent, copying for the purpose of technological
+research and advancement is allowed.
+
+                                        
+-------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+                                        
+
+     WHAT IS THE CONFERENCE MAIL SYSTEM?
+
+          Conference Mail  is a  technique to  permit several  nodes  on  a
+          network to  share a  message base,  similar  in  concept  to  the
+          conferences available on many of the computer services, but it is
+          most closely related to the Usenet system consisting of more than
+          8,000 systems  world wide. All systems sharing a given conference
+          see any  messages entered  into the  conference  by  any  of  the
+          participating systems.  This can  be implemented in such a way as
+          to be  totally transparent  to the users of a particular node. In
+          fact, they  may not  even be  aware of  the network being used to
+          move their  messages about from node to node! Unfortunately, this
+          has its  disadvantages also  - most  users who  are not  educated
+          about Conference  Mail do  not realize  the messages  transmitted
+          cost MANY  sysops (system  operators) money,  not just  the local
+          sysop. This  is an important consideration in Conference Mail and
+          should not be taken lightly.  In a conference with 100 systems as
+          participants the cost per message can get quite high.
+
+          The Conference  Mail System is designed to operate in conjunction
+          with a  FidoNet compatible  mail server.  The currently supported
+          mail servers  are Fido(tm),  SEAdog(tm), Opus, and Dutchie. Since
+          the mail  server is  a prerequisite  to using the Conference Mail
+          System, it  will be  assumed you  already have  your mail  server
+          operating correctly  on your   system, and you are connected into
+          FidoNet or a compatible network.
+
+
+     HISTORY OF THE CONFERENCE MAIL SYSTEM
+
+          In late  1985, Jeff  Rush, a  Fido  sysop  in  Dallas,  wanted  a
+          convenient means  of sharing  ideas with the other Dallas sysops.
+          He created  a system  of programs  he called  Echomail,  and  the
+          Dallas sysops' Conference was born.
+
+          Within a  short time  sysops in other areas began hearing of this
+          marvelous new  gadget and  Echomail took  on a  life of  its own.
+          Today, a  scant year and a half later, the FidoNet public network
+          boasts a myriad of conferences varying in size from the dozen-or-
+          so participants  in the  FidoNet  Technical  Standards  Committee
+          Conference  to   the  Sysops'  Conference  with  several  hundred
+          participants. It  is not  uncommon for a node to carry 30 or more
+          conferences and share those conferences with 10 or more nodes.
+
+
+     HOW IT WORKS
+
+          The Conference  Mail System  is functionally  compatible with the
+          original Echomail utilities.  In general, the process is:
+
+          1. A  message is  entered into  a designated  area on  a  FidoNet
+          compatible system.
+
+          2. This message is "Exported" along with some control information
+          to each system "linked" to the conference through the originating
+          system.
+
+          3. Each  of the  receiving systems  "Import" the message into the
+          proper Conference Mail area.
+
+          4. The receiving systems then "Export" these messages, along with
+          additional control  information,  to  each  of  their  conference
+          links.
+
+          5. Return to step 3.
+
+          As you  can see,  the method  is quite  simple -  in general.  Of
+          course, following  the steps  literally would mean messages would
+          never stop being Exported and transmitted to other systems.  This
+          obviously would  not be  desired or  the  network  would  quickly
+          become overburdened.  The information  contained in  the 'control
+          information' section  is used  to prevent  transmitting the  same
+          message more than once to a single system.
+
+
+     CONFERENCE MAIL MESSAGE CONTROL INFORMATION
+
+          There are  five pieces  of control  information associated with a
+          Conference  Mail  message.  Some  are  optional,  some  are  not.
+          Normally this information is never entered by the person creating
+          the  message.   The  following   control  fields   determine  how
+          Conference Mail is handled:
+
+          1. Area line
+
+               This is  the first  line of  a conference  mail message. Its
+               actual appearance is:
+
+                                     AREA:CONFERENCE
+
+               Where CONFERENCE is the name of the conference. This line is
+               added when  a conference  is  being  "Exported"  to  another
+               system. It  is based upon information found in the AREAS.BBS
+               (configuration) File  for the  designated message area. This
+               field is  REQUIRED by  the receiving  system to  "Import"  a
+               message into the correct Conference Mail area.
+
+          2. Tear Line
+
+               This line is near the end of a message and consists of three
+               dashes (---)  followed by  an  optional  program  specifier.
+               This is  used to show the first program used to add Echomail
+               compatible control information to the message. The tear line
+               generated by Conference Mail looks like:
+
+                                    --- 
+
+               This  field   is  optional   for  most  Echomail  compatible
+               processors, and  is added  by the  Conference Mail System to
+               ensure complete  compatibility. Some systems will place this
+               line in  the message  when it  is first  created, but  it is
+               normally added when the message is first "exported."
+
+          3. Origin line
+
+               This line  appears near  the bottom of a message and gives a
+               small amount  of  information  about  the  system  where  it
+               originated. It looks like:
+
+                      * Origin: The Conference Mail BBS (1:132/101)
+
+               The "  * Origin:  " part  of the  line is  a constant field.
+               This is followed by the name of the system as taken from the
+               AREAS.BBS file  or a  file named  ORIGIN located  in the DOS
+               directory of  the  designated  message  area.  The  complete
+               network address  (1:132/101 in  this case)  is added  by the
+               program inserting  the line.  This field is generated at the
+               same time  as the  tear line,  and therefore  may either  be
+               generated at  the time  of  creation  or  during  the  first
+               "export"  processing.   Although  the  Origin  line  is  not
+               required by  all Echomail  processors, it  is added  by  the
+               Conference Mail System to ensure complete compatibility.
+
+
+          4. Seen-by Lines
+
+               There can  be many  seen-by lines  at the  end of Conference
+               Mail messages,  and they  are the real "meat" of the control
+               information. They  are used  to  determine  the  systems  to
+               receive the exported messages. The format of the line is:
+
+                           SEEN-BY: 132/101 113 136/601 1014/1
+
+               The net/node  numbers correspond  to the net/node numbers of
+               the systems having already received the message. In this way
+               a message  is never  sent to a system twice. In a conference
+               with many  participants the  number of  seen-by lines can be
+               very large.   This line is added if it is not already a part
+               of the  message, or added to if it already exists, each time
+               a message  is exported  to other systems. This is a REQUIRED
+               field, and  Conference Mail  will not  function correctly if
+               this field  is not put in place by other Echomail compatible
+               programs.
+
+          5. PATH Lines
+
+               These are  the last  lines in  a Conference Mail message and
+               are a  new addition,  and therefore  is not supported by all
+               Echomail processors. It appears as follows:
+
+                                  ^aPATH: 132/101 1014/1
+
+               Where the  ^a stands  for Control-A  (ASCII character 1) and
+               the net/nodes  listed correspond  to  those  systems  having
+               processed the  message before it reached the current system.
+               This is  not the  same as  the seen-by  lines, because those
+               lines list  all systems  the message has been sent to, while
+               the path line contains all systems having actually processed
+               the message.  This is not a required field, and few echomail
+               processors currently  support it,  however it  can  be  used
+               safely with  any other  system, since  the line(s)  will  be
+               ignored. For  a discussion  on how  the  path  line  can  be
+               helpful, see the "Advanced Features" section of this manual.
+
+
+     METHODS OF SENDING CONFERENCE MAIL
+
+          To this  point the  issue of how Conference Mail is actually sent
+          has been glossed over entirely. The phrase has been, "the message
+          is exported  to another  system."   What exactly  does this mean?
+          Well, for starters lets show what is called the "basic" setup:
+
+          In this setup exported mail is placed into the FidoNet mail area.
+          Each message   exported  from a  Conference  Mail  area  has  one
+          message generated  for each  receiving system.  This mail is then
+          sent the  same as any other network mail. When Echomail was first
+          created this was the only way mail could be sent.
+
+          The "basic"  method has some disadvantages. First, since Echomail
+          has grown so large it is not uncommon to get 200 new messages per
+          day imported  into various message bases. It is also not uncommon
+          for a  system to  be exporting  messages to 4 or 5 other systems.
+          Simple arithmetic  shows 800-1000  messages per day would be sent
+          in normal  netmail! This  puts a tremendous strain on any netmail
+          system, not  to mention transmission time and the resultant phone
+          charges. When this limitation of Echomail was first noticed a lot
+          of people started scratching their heads wondering what to do. If
+          a  solution  could  not  be  found  it  appeared  Echomail  would
+          certainly overrun the capabilities of FidoNet.
+
+          Thom Henderson  (from System Enhancement Associates) came up with
+          the original  ARCmail program.  Having previously written the ARC
+          file archiving  and compression  program,  he  knew  the  savings
+          achievable by  having all  of the netmail messages placed in .ARC
+          format for  transmission. As  a byproduct, the messages no longer
+          appeared in  the netmail  area,  but  were  included  in  a  file
+          attached to  a message  (see your  FidoNet mailer manual for file
+          attaches).  In   this  way  the  tremendous  number  of  messages
+          generated, and the phone bill problems were both solved.
+
+          Unfortunately, ARCmail  required the  messages to first be placed
+          into the  netmail area  before it  could be  run. In  effect,  it
+          caused the  messages to  be scanned once when they were exported,
+          once during  the ARCmail  phase, once when ARCmail was run at the
+          other end  to get  the messages out of .ARC format, and once when
+          those messages  were later  imported into  a message  base on the
+          receiving system.  The Conference Mail System solves this problem
+          by eliminating  the ARCmail  program. Conference  Mail builds the
+          ARCmail files during Export, and unpacks them during Import. This
+          way  messages   are  exported  directly  to  ARCmail  style  file
+          attaches, and imported directly from ARCmail style file attaches.
+          The scanning  phases between importing and exporting messages are
+          totally removed and processing time is proportionally reduced.
+
+          This is  now the  most common  method for sending Conference Mail
+          between systems.  The overhead  involved in  doing it  during the
+          importing and exporting phases is much less than what is involved
+          if ARCmailing  is not  utilized. This was a primary consideration
+          in the  design and  implementation of the Conference Mail System,
+          and as  a result  the entire system is optimized for this type of
+          use.  Please  refer  to  the  Import  and  Export  functions  for
+          specifics on how to use the ARCmailing feature.
+
+
+     CONFERENCE TOPOLOGY
+
+          The  way   in  which  systems  link  together  for  a  particular
+          conference is  called the "conference topology."  It is important
+          to know  this structure  for two  reasons: 1)  It is important to
+          have a  topology which  is  efficient  in  the  transfer  of  the
+          Conference Mail  messages, and  2) It  is  important  to  have  a
+          topology which  will not  cause systems  to see the same messages
+          more than once.
+
+          Efficiency can  be measured  in a  number  of  ways;  least  time
+          involved for all systems to receive a message, least cost for all
+          systems to receive a message, and fewest phone calls required for
+          all systems  to receive  a message  are all  valid indicators  of
+          efficiency. Users  of Echomail compatible systems have determined
+          (through trial  and error)  the best  measure of  efficiency is a
+          combination  of  all  three  of  the  measurements  given  above.
+          Balancing the equation is not trivial, but some guidelines can be
+          given:
+
+               1. Never have two systems attempting to send Conference mail
+               to each other at the same time. This results in "collisions"
+               that will  cause both  systems to  fail. To  avoid this, one
+               system should  be responsible  for polling  while the  other
+               system is holding mail. This arrangement can alternate based
+               upon various  criteria, but  both systems  should  never  be
+               attempting to call each other at the same time.
+
+               2. Have  nodes form  "stars" for  distribution of Conference
+               Mail. This arrangement has several nodes all receiving their
+               Conference Mail from the same system. In general the systems
+               on the  "outside"  of  the  star  poll  the  system  on  the
+               "inside". The  system on  the "inside"  in turn  polls other
+               systems to  receive the Conference Mail that is being passed
+               on to the "outside" systems.
+
+               3. Utilize  fully connected  polygons with  a few  vertices.
+               Nodes can  be connected in a triangle (A sends to B and C, B
+               sends to  A and  C, C sends to A and B) or a fully connected
+               square (all  corners of  the square send to all of the other
+               corners). This  method is useful for getting Conference Mail
+               messages to each node as quickly as possible.
+
+
+          All of  these efficiency  guidelines have to be tempered with the
+          guidelines dealing  with keeping  duplicate messages  from  being
+          exported. Duplicates  will occur  in any  topology that  forms  a
+          closed polygon  that is not fully connected. Take for example the
+          following configuration:
+
+                                      A ----- B
+                                      |       |
+                                      |       |
+                                      C ----- D
+
+          This square  is a  closed polygon that is not fully connected. It
+          is capable of generating duplicates as follows:
+
+               1. A message is entered on node A.
+
+               2. Node  A exports  the message to node B and node C placing
+               the seen-by for A, B, and C in the message as it does so.
+
+               3. Node  B sees that node D is not listed in the seen-by and
+               exports the message to node D.
+
+               4. Node  C sees that node D is not listed in the seen-by and
+               exports the message to node D.
+
+          At this  point node  D has  received the  same message  twice - a
+          duplicate was  generated. Normally  a "dup-ring"  will not  be as
+          simple as  a square.  Generally it  will be caused by a system on
+          one end  of a  long chain  accidentally connecting to a system on
+          the other end of the chain. This causes the two ends of the chain
+          to become connected, forming a polygon.
+
+          In FidoNet  this problem  is reduced somewhat by having "Regional
+          Echomail Coordinators"  (RECS) that try to keep track of Echomail
+          connections within  their regions  of the  world. A  further rule
+          which is  followed is  that only  the RECS  are allowed  to  make
+          inter-regional connections for the larger conferences. In return,
+          the RECS  have established  a very  efficient topology which gets
+          messages from  coast to  coast, and onto over 200 systems in less
+          than 24  hours. If  no one were willing to follow the rules, then
+          this system  would collapse,  but due to the excellent efficiency
+          it has remained intact for over a year.
+
+
+     Why a PATH line?
+
+          As was  previously mentioned,  the PATH  line is a new concept in
+          Echomail. It  stores the  net/node numbers  of each system having
+          actually processed  a message.  This  information  is  useful  in
+          correcting the  biggest problem  encountered by  nodes running an
+          Echomail compatible  system - the problem of finding the cause of
+          duplicate messages.  How does  the  PATH  line  help  solve  this
+          problem? Take the following path line as an example:
+
+               ^aPATH: 107/6 107/312 132/101
+
+          This  shows  the  message  was  processed  by  system  107/6  and
+          transferred to  system 107/312.  It further  shows system 107/312
+          transferred the  message to  132/101, and  132/101  processed  it
+          again. Now take the following path line as the example:
+
+               ^aPATH: 107/6 107/312 107/528 107/312 132/101
+
+          This shows  the message  having been processed by node 107/312 on
+          more than one occasion. Based upon the earlier description of the
+          'information control'  fields in  Echomail messages, this clearly
+          is an  error in  processing (see  the section  entitled  "How  it
+          Works"). This  further shows   node  107/528 as  the  node  which
+          apparently processed  the message  incorrectly. In  this case the
+          path line  can be  used to quickly locate the source of duplicate
+          messages.
+
+          In  a   conference  with  many  participants  it  becomes  almost
+          impossible to  determine the  exact topology used. In these cases
+          the use of the path line can help a coordinator of the conference
+          track any  possible breakdowns in the overall topology, while not
+          substantially increasing  the amount  of information transmitted.
+          Having this  small amount of information added to the end of each
+          message pays  for itself very quickly when it can be used to help
+          detect a  topology  problem  causing  duplicate  messages  to  be
+          transmitted to each system.
+
+-30-
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0005.html b/html/ftsc/fts-0005.html new file mode 100755 index 00000000..ba57602a --- /dev/null +++ b/html/ftsc/fts-0005.html @@ -0,0 +1,617 @@ + + +The Distribution Nodelist. + + + + +
+ | Document: FTS-0005
+ | Version:  003
+ | Date:     February 7, 1996
+ | Maintainer: David Nugent, 3:632/348@fidonet
+
+
+                       The Distribution Nodelist
+
+                        Originally by Ben Baker
+       Amended by Rick Moore, 1:115/333@FidoNet, February 5, 1989
+     Amended by David Nugent, 3:632/348@FidoNet, February 27, 1996
+
+
+|   Copyright 1986-1996 by the FidoNet Technical Standards Committee.
+    All rights reserved. Duplication and/or distribution permitted
+    for non-commercial purposes only.
+
+    This document supersedes and replaces the document known under
+|   the names of FSC002, FSC-0002, and FTS-0002. Significant changes,
+|   which excludes mere formatting changes, to the previous version
+|   of this document have been "redlined" (marked with a vertical
+|   bar in the leftmost column).
+
+    This document defines the format and content of the nodelist for
+    the Public FidoNet Network (PFN) as published on Friday of each
+|   week. This format is historically known as the "St. Louis nodelist
+|   format".
+
+    The PFN is an international network of independently owned
+    electronic mail systems, most with interlocking electronic
+    bulletin board systems. The distribution nodelist, or simply
+    "nodelist", is the glue which holds the network together. It is
+    the PFN's "phone book" and it defines the top-level network
+|   structure and is the means by which FidoNet retains its integrity
+|   as a point-to-point mail network.
+
+
+| THE NODELIST
+
+    The nodelist is published as an ASCII text file named
+    NODELIST.nnn, where nnn is a three digit number representing the
+|   day-of-year of the Friday publication date, with zeros filling
+|   positions to the left if necessary. This file is packed into a
+|   archive file named NODELIST.?nn, where 'nn' are the last two
+|   digits of day-of-year, and the character at the position of the
+|   '?' indicating the type of compression used. Conventions as to
+|   which compression method is used for the distributed nodelist is
+|   a matter of local policy and is usually determined by each zone's
+|   Zone Coordinator.
+
+    As stated above, NODELIST.nnn is an ASCII text file. It contains
+    two kinds of lines; comment lines and data lines. Each line is
+    terminated with an ASCII carriage return and line feed character
+    sequence, and contains no trailing white-space (spaces, tabs,
+|   etc.). The file is terminated with a DOS end-of-file character
+|   (character value 26 decimal, or "control-Z").
+
+    Comment lines contain a semicolon (;) in the first character
+    position followed by zero or more alphabetic characters called
+    "interest flags". A program which processes the nodelist may use
+    comment interest flags to determine the disposition of a comment
+    line. The remainder of a comment line (with one exception,
+|   treated below) is free-form ASCII text. There are five types of
+|   comments flags:
+
+|       ;S This is of particular interest to Sysops
+|       ;U This is of particular interest to BBS users
+|       ;F This should appear in any formatted "Fido List"
+|       ;A This is of general interest (shorthand for ;SUF)
+|       ;E This is an error message inserted by the nodelist generator
+|       ; This comment may be ignored by a nodelist processor
+
+    The first line of a nodelist is a special comment line containing
+    identification data for the particular edition of the nodelist.
+    The following is an example of the first line of a nodelist:
+
+    ;A FidoNet Nodelist for Friday, July 3, 1987 -- Day number 184 : 15943
+
+    This line contains the general interest flag, the day, date, and
+|   three-digit (zero-filled) day-of-year number of publication, and
+    ends with a 5 digit decimal number with leading zeros, if
+    necessary. This number is the decimal representation of a check
+    value derived as follows:
+
+        Beginning with the first character of the second line, a
+        16 bit cyclic redundancy check (CRC) is calculated for the
+        entire file, including carriage return and line feed
+        characters, but not including the terminating EOF
+        character. The check polynomial used is the same one used
+        for many file transfer protocols:
+
+                    2**16 + 2**12 + 2**5 + 2**0
+
+    The CRC may be used to verify that the file has not been edited.
+    The importance of this will become evident in the discussion of
+    NODEDIFF, below. CRC calculation techniques are well documented
+|   in various technical references, and will not be treated further
+    here.
+
+    The content of the remaining comments in the nodelist are
+    intended to be informative. Beyond the use of interest flags for
+    distribution, a processing program need not have any interest in
+    them.
+
+    A nodelist data line contains eight variable length "fields"
+    separated by commas (,). No space characters are allowed in a
+    data line, and underscore characters are used in lieu of spaces.
+    The term "alphanumeric character" is defined as the portion of
+    the ASCII character set from 20 hex through 7E hex, inclusive.
+    The following discussion defines the contents of each field in a
+    data line.
+
+
+  Field 1: Keyword
+
+    The keyword field may be empty, or may contain one of the
+    following:
+
+    Zone
+
+        Begins the definition of a geographic zone and define its
+        coordinator. All the data lines following a line with the
+        "Zone" keyword down to, but not including, the next
+        occurrence of a "Zone" keyword, are regions, networks, and
+|       nodes within the defined zone.  Node entries defined
+|       immediately after the "Zone" keyword and before the next
+|       region or host entry are known as zone adminstrative nodes.
+|       These are allocated by the Zone Coordinator for use by nodes
+|       in the entire zone; for example, mail gateways between
+|       FidoNet zones.
+
+    Region
+
+        Begins the definition of a geographic region and defines
+        its coordinator. All the data lines following a line with
+        the "Region" keyword down to,  but not including,  the
+        next occurrence of a "Zone",  "Region",  or "Host"
+        keyword, are independent nodes within the defined region.
+
+    Host
+
+        Begins the definition of a local network and defines its
+|       network coordinator. All the data lines following a line
+        with the Host keyword down to, but not including, the
+        next occurrence of a "Zone", "Region",  or "Host" keyword,
+        are local nodes, members of the defined local network.
+
+    Hub
+
+        Begins the definition of a routing sub-unit within a
+        multi-level local network. The hub is the routing focal
+        point for nodes listed below it until the next occurrence
+        of a "Zone", "Region", "Host", or "Hub" keyword. The hub
+        entry MUST be a redundant entry, with a unique number, for
+        one of the nodes listed below it, within its hub segment.
+        This is necessary because some nodelist processors
+        eliminate these entries in all but the local network.
+
+    Pvt
+
+        Defines a private node with unlisted number. Private nodes
+        are only allowed as members of local networks.
+
+    Hold
+
+        Defines a node which is temporarily down. Mail may be sent
+        to it and is held by its host or coordinator.
+
+    Down
+
+        Defines a node which is not operational. Mail may NOT be
+        sent to it. This keyword may not be used for longer than
+        two weeks on any single node, at which point the "down"
+        node is to be removed from the nodelist.
+
+    
+
+|       The field contains no text (not the sequence ""),
+|       and defines a normal node entry.
+
+|   Only one of these may be used in any individual data line.
+
+
+  Field 2: Zone/Region/Net/Node number
+
+    This field contains only numeric digits and is a number in the
+    range of 0 to 32767. If the line had the "Zone", "Region", or
+    "Host" keyword, the number is the zone, net, or region number,
+    and the node has an implied node number of 0. Otherwise, the
+    number is the node number. The zone number, region or net number,
+    and the node number, taken together, constitute a node's FidoNet
+    address.
+
+    Zone numbers must be unique. Region or net numbers must be unique
+    within their zone, hub numbers unique be within their net, node
+|   numbers unique within their net (and region, for regional
+|   independent nodes, zone for zone administrative entries). Duplicate
+    node numbers under different hubs within the same net are not
+    allowed.
+
+
+  Field 3: Node name
+
+    This field may contain any alphanumeric characters other than
+    commas and spaces. Underscores are used to represent spaces, and
+    a comma delimits the end of the field. This is the name by which
+    the node is known, usually as determined by the node or the
+    coordinator responsible for compiling the segment.
+
+
+  Field 4: Location
+
+    This field may contain any alphanumeric characters other than
+    commas and spaces. Underscores are used to represent spaces. This
+    field contains the location of the node. It is usually expressed
+    as the primary local location (town, suburb, city, etc.) plus the
+    identifier of the regional geopolitical administrative district
+    (state, province, department, county, etc.). Wherever possible,
+    standard postal abbreviations for the major regional district
+    should be used (IL, BC, NSW, etc.).
+
+
+  Field 5: Sysop name
+
+    This field may contain any alphanumeric characters other than
+    commas and spaces. Underscores are used to represent spaces. This
+    is the name of the system operator.
+
+
+  Field 6: Phone number
+
+    This field contains at least three and usually four numeric
+    sub-fields separated by dashes (-). The fields are country code,
+    city or area code, exchange code, and number. The various parts
+    of the phone number are frequently used to derive cost and
+    routing information, as well as what number is to be dialed. A
+    typical example of the data in a phone number field is
+    1-800-555-1212, corresponding to country 1 (USA), area 800
+    (inbound WATS), exchange 555, and number 1212.
+
+    Alternatively, this field may contain the notation
+    "-Unpublished-" in the case of a private node. In this case, the
+|   keyword "Pvt" must appear at the start of the line.
+
+
+  Field 7: Baud rate
+
+    This field contains one of the values: 300, 1200, 2400, 9600,
+|   19200, or 38400.
+
+|   This baud rate is indicative only of the maximum baud rate that
+|   may be expected when connecting to a node and is generally of use
+|   only where a calling node needs to adjust the baud rate used to
+|   dial to the caller's modem speed in order to achieve a
+|   connection, a requirement that with modem technology available in
+|   1996 is rarely if ever needed. This information is largely
+|   superseded by modem protocol flags (see next section) where any
+|   two nodes using a common protocol may have other expectations
+|   with regards to actual transfer rates. Use of the baud rate field
+|   alone is therefore depreciated.
+
+
+  Field 8 - Flags
+
+    This optional field contains data about the specific operation of
+    the node, such as file requests, modem protocol supported, etc.
+    Any text following the seventh comma on a data line is taken
+    collectively to be the flags field. The required format is zero
+    or more sub-fields, separated by commas. Each sub-field consists
+    of a flag, possibly followed by a value.
+
+    The following flags define special operating conditions:
+
+       Flag    Meaning
+
+       CM      Node accepts mail 24 hours a day
+       MO      Node does not accept human callers
+|      LO      Node accepts calls only from valid listed node
+|              numbers in the current FidoNet nodelist
+
+
+    The following flags define modem protocols supported:
+
+       Flag    Meaning
+
+|      V21     ITU-T V21      300 bps full duplex
+|      V22     ITU-T V22     1200 bps full duplex
+|      V29     ITU-T V29     9600 bps half duplex
+|      V32     ITU-T V32     9600 bps full duplex
+|      V32b    ITU-T V32bis 14400 bps full duplex
+|      V33     ITU-T V33
+|      V34     ITU-T V34    28800 bps full duplex
+
+       H96     Hayes V9600
+       HST     USR Courier HST up to 9600
+|      H14     USR Courier HST up to 14400
+|      H16     USR Courier HST up to 16800
+       MAX     Microcom AX/96xx series
+       PEP     Packet Ensemble Protocol
+|      CSP     Compucom Speedmodem
+|      ZYX     Zyxel series
+|      VFC     V.Fast Class
+|      V32T    V.32 Terbo
+
+       NOTE:   Many V22 modems also support Bell 212A.
+
+    If no modem flag is given, Bell 212A is assumed for 1200 bps
+    systems, ITU-T V22bis is assumed for 2400 bps systems.
+
+
+    The following flags define type of error correction available. A
+    separate error correction flag should not be used when the error
+    correction type can be determined by the modem flag. For
+|   instance, a modem flag of HST implies MNP, V32b implies V32 and
+|   V42b implies V42. Therefore MNP+HST, H14+MNP, H16+MNP, V32+V32b
+|   and V42+V42b flag pairs are redundant and should not be used.
+
+        Flag    Meaning
+
+        MNP     Microcom Networking Protocol error correction
+|       V42     ITU-T LAP-M error correction w/fallback to MNP 1-4
+|       V42b    ITU-T LAP-M error correction w/fallback to MNP 1-5
+
+
+    The following flags define the type(s) of compression of mail
+    packets supported.
+
+        Flag    Meaning
+
+        MN      No compression supported
+
+|       NOTE:   While FidoNet nodes usually exchange mail
+|               using a variety of different file compression
+|               formats negotiated between individual systems, the
+|               presence of this flag indicates the INABILITY TO
+|               RECEIVE MAIL compressed using the SEA ARC version 5
+|               compression format and/or named according to the
+|               ARCmail 0.6 mail bundle naming method. This is, by
+|               convention, the most common mail compression format
+|               in use within FidoNet. The presence of this flag
+|               would normally indicate that all mail should be sent
+|               uncompressed unless there is some overriding
+|               arrangement with the receiving system.
+
+    The following flags indicate the types of file and file update
+    requests supported.
+
+        Flag    Meaning
+
+        XA      Bark and WaZOO file/update requests
+        XB      Bark file/update requests, WaZOO file requests
+|       XC      Bark file requests, WaZOO file file/update
+        XP      Bark file/update requests
+        XR      Bark and WaZOO file requests
+        XW      WaZOO file requests
+|       XX      WaZOO file/update requests
+
+
+    The following flag defines gateways to other domains (mail
+    networks).
+
+        Flag    Meaning
+
+        Gx..x   Gateway to domain 'x..x', where 'x..x` is a string
+                of alphanumeric characters.
+
+        NOTE:   Valid values for 'x..x' are assigned by the FidoNet
+|               International Coordinator or the person appointed as
+|               Internetworking Coordinator by the FidoNet
+|               International Coordinator. Current valid values of
+                'x..x' may usually be found in the notes at the end
+|               of the current FidoNet nodelist. The most common
+|               gateway flag is "GUUCP", to denote a gateway to the
+|               Internet mail system that gates on behalf of the
+|               fidonet.org internet domain.
+
+
+    The following flags define the dedicated mail periods supported.
+    They have the form "#nn" or "!nn" where nn is the UTC hour the mail
+    period begins, '#' indicates Bell 212A compatibility, and '!'
+    indicates incompatibility with Bell 212A.
+
+        Flag    Meaning
+
+|       #01     Zone 5 mail hour (01:00 - 02:00 UTC)
+        #02     Zone 2 mail hour (02:30 - 03:30 UTC)
+|       #03     Zone 4 mail hour (08:00 - 09:00 UTC)
+        #09     Zone 1 mail hour (09:00 - 10:00 UTC)
+        #18     Zone 3 mail hour (18:00 - 19:00 UTC)
+|       #20     Zone 6 mail hour (20:00 - 21:00 UTC)
+
+        NOTE:   When applicable, the mail period flags may be strung
+                together with no intervening commas, e.g.. "#02#09"
+|               or "!02!09". Only mail hours other than that
+                standard within a node's zone should be given. Since
+                observance of mail hour within one's zone is
+                mandatory, it should not be indicated.
+
+
+    The following flag defines user-specific values. If present,
+    this flag MUST be the last flag present in a nodelist entry.
+
+        Flag    Meaning
+
+        Ux..x   A user-specified string, which may contain any
+                alphanumeric character except blanks. This string
+                may contain one to thirty-two characters of
+                information that may be used to add user-defined
+                data to a specific nodelist entry.
+
+|       NOTE:   Ux..x flags are the mechanism by which new flags may
+|               be experimentally introduced into the nodelist for a
+|               trial period to assess their worth. They are
+|               therefore of a temporary nature, and after their
+|               introduction they are eventually either promoted
+|               to a non-U flag or dropped from use altogether.
+
+    The FTSC recognizes that the FidoNet International Coordinator is
+    the ultimate authority over what appears in the FidoNet nodelist.
+    Also, FTSC is by definition a deliberative body, and adding or
+    changing a flag may take a considerable amount of time.
+    Therefore, the FidoNet International Coordinator may temporarily
+    make changes or additions to the flags as defined in this
+    document. The FidoNet International Coordinator will then consult
+    with FTSC over the changes needed to this document to reflect
+    these temporary changes.
+
+
+    The following are examples of nodelist data lines:
+
+    Host,102,SOCALNET,Los_Angeles_CA,Richard_Martz,1-213-874-9484,2400,XP
+    ,101,Rainbow_Data,Culver_City_CA,Don_Brauns,1-213-204-2996,2400,
+
+
+| THE NODEDIFF
+
+|   With more than thirty-five thousand nodes as of this date (1996),
+|   the nodelist, even in archive form, is a document of substantial
+|   size. Since distribution of the nodelist occurs via electronic
+    file transfer, this file is NOT routinely distributed. Instead,
+|   when a new nodelist is prepared weekly, it is compared with the
+    previous week's nodelist, and a file containing only the
+    differences is created and distributed.
+
+|   The distribution difference file, called NODEDIFF.nnn, where nnn
+    is the day-of-year of publication, is actually an editing script
+    which will transform the previous week's nodelist into the
+    current nodelist. A definition of its format follows:
+
+    The first line of NODEDIFF.nnn is an exact copy of the first line
+|   of LAST WEEK'S nodelist (i.e. the first line of the nodelist to
+|   which the current difference file applies). This is used as a
+    first-level confidence check to insure that the correct file is
+    being edited. The second and subsequent lines are editing
+    commands and data.
+
+    There are three editing commands and all have the same format:
+
+  
+
+     is a 1 letter command, one of A, C, or D.
+
+     is a decimal number greater than zero, and defines the
+    number of lines to be operated on by the command. Each command
+    appears on a line by itself. The commands have the following
+    meanings:
+
+        Ann     Add the following nn lines to the output file.
+        Cnn     Copy nn unchanged lines from the input to the output
+                file.
+        Dnn     Delete (or skip) nn lines from the input file.
+
+    The following illustrate how the first few lines of a
+|   hypothetical NODEDIFF.213 might look:
+
+        ;A Friday, July 25, 1986 -- Day number 206 : 27712
+        D2
+        A2
+        ;A Friday, August 1, 1986 -- Day number 213 : 05060
+        ;A
+        C5
+
+    This fragment illustrates all three editing commands. The first
+    line is the first line from the previous nodelist, NODELIST.206.
+    The next line says "delete the first two lines" from
+    NODELIST.206. These are the identification line and the line
+    following it. The next command says "add the next two lines" to
+    NODELIST.213 at the "current" location. The two data lines are
+    followed by a command which says "copy five unchanged lines" from
+    NODELIST.206 to NODELIST.213. Notice that the first line added
+|   will ALWAYS contain the new nodelist CRC, so that the software
+|   applying the changes to the old nodelist may check the result of
+|   its editing.
+
+    Since only the differences will be distributed, it is important
+    to insure the accuracy of the newly created nodelist. This is the
+    function of the CRC mentioned above. It is sufficient for a
+    program designed to perform the above edits to pick the CRC value
+    from the first line added to the output file, then compute the
+    CRC of the rest of the output file. If the two CRCs do not agree,
+    one of the input files has been corrupted. If they do agree, the
+    probability is very high (but not 100%) that the output file is
+    accurate.
+
+    For actual distribution, NODEDIFF.nnn is packed into an archive
+|   file named NODEDIFF.?nn, where 'nn' are the last two digits of
+|   day-of-year, and '?' indicates the compression format used.
+
+
+| NODELIST COMPILATION
+
+|   This section is included for tutorial reasons and is not intended
+|   as a definition of any specific method by which FidoNet MUST
+|   compile its weekly nodelist. It merely represents an attempt to
+|   document the method by which it currently does so. It is intended
+|   to be explanatory, and seeks to answer commonly asked questions,
+|   such as how the nodelist is compiled and where the information
+|   comes from, why the nodelists used in different FidoNet zones are
+|   not the same document, and why the difference file generated for
+|   use in one FidoNet zone cannot be applied to the nodelist
+|   generated for use in a different zone, even though the week
+|   numbers match.
+
+|   Nodelists are compiled via a distributed method, which follows
+|   the same structure as the FidoNet coordinator hierarchy. At the
+|   lowest level, network coordinators maintain a list of the nodes
+|   in their network and are responsible for the addition, removal
+|   and correction of individual node's listings in their "segment"
+|   (as portions of the full nodelist are called). In some larger
+|   networks, it is common for this job to be shared with hub
+|   coordinators appointed by the net coordinator, though the
+|   responsibility for those hub segments still remains with the
+|   network coordinator.
+
+|   At a nominated day during the week, before the regional level
+|   segment is submitted to the zone coordinator, individual net
+|   coordinators submit their segments to the regional coordinator
+|   who subsequently compiles these segments and transmits the merged
+|   copy to the zone coordinator. These are combined by the zone
+|   coordinator with the separate segments of other zones and
+|   compiled into that zone's version of the world nodelist. This
+|   world nodelist is then compared with the previous week's version,
+|   a difference file is generated and subsequently distributed
+|   throughout the zone.
+
+|   In some cases, in the interest of saving in transmission times
+|   and therefore costs, the compilation process itself may be better
+|   served by the submission of DIFFERENCE FILES rather than full
+|   net- or region-level segments. Each coordinator therefore retains
+|   a copy of the previously submitted segments and applies
+|   difference files to those to derive the new one. This process is
+|   exactly identical to the NODEDIFF/NODELIST scenario described
+|   earlier in this document, with the same first line and CRC
+|   validation method used to guard the integrity of the nodelist
+|   segments.
+
+|   For a number of reasons, it is important that publication of the
+|   nodelist be as timely as possible. These reasons include: the
+|   nodelist is a definitive list of valid FidoNet addresses that may
+|   receive mail, and must therefore be as correct and up-to-date as
+|   possible to save nodes the unnecessary expense of mail routed to
+|   possibly non-existing addresses; the nodelist contains the list
+|   of telephone numbers that may be called by any user of the
+|   FidoNet nodelist and should therefore be accurate so as not to
+|   unduly annoy owners of those phone numbers should a listed node
+|   go down and an unsuspecting telephone subscriber inherit the same
+|   telephone number.
+
+|   Given this constraint, the expense of international calls and the
+|   fact that FidoNet is a worldwide network that exists in many time
+|   zones, it may be unreasonable to expect the compilation of the
+|   nodelist to be delayed until each zone coordinator can transmit
+|   their most up-to-date zone segment to a central authority for
+|   compilation and subsequent redistribution in any week. For the
+|   sake of expedience, each zone instead maintains its own separate
+|   world nodelist which contains a compilation of the current zone's
+|   latest segments and including the most current copy to hand of
+|   all other FidoNet zone's segments. The zone level nodelist
+|   generated each week by each zone coordinator is then transmitted
+|   to all other zone coordinators for inclusion into their separate
+|   world nodelist as timing permits.
+
+|   In theory, then, the only difference between nodelists
+|   distributed in each zone in any week are accounted for by timing
+|   differences in the exchange of each zone's separate segment. In
+|   practice, other constraints may interfere with timeliness, such
+|   as the difficulty and expense of international telephonic
+|   communications. Also, another point of variance is introduced by
+|   the fact that each zone usually includes its own zone segment
+|   first into its world nodelist to assist - amongst other things -
+|   software that uses the nodelist for index generation. Some
+|   software in common use in FidoNet indexes the nodelist according
+|   to its sequential order (e.g. version 5 and 6 compiled nodelist
+|   formats), and including the current zone first before others will
+|   have a beneficial effect on software performance.
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0006.html b/html/ftsc/fts-0006.html new file mode 100755 index 00000000..6cddb22c --- /dev/null +++ b/html/ftsc/fts-0006.html @@ -0,0 +1,870 @@ + + +YOOHOO and YOOHOO/2U2. + + + + +
+Document: FTS-0006
+Version:  002
+Date:     30-Nov-1991
+
+
+
+
+                            YOOHOO and YOOHOO/2U2
+
+                    The netmail handshake used by Opus-CBCS
+             and other intelligent Fidonet mail handling packages
+
+
+                              Vince Perriello
+                             FidoNet 1:2343/491
+
+
+
+
+Status of this document:
+
+     This FTS (FidoNet(r) Technical Standard) specifies an optional
+     standard for the FidoNet community.  Implementation of the
+     protocols defined in this document is not mandatory,  but all
+     implementations of these protocols are expected to adhere to this
+     standard.  Distribution of this document is subject to the 
+     restrictions listed below.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software
+
+
+
+
+LEGAL STUFF
+-----------
+
+The original  protocol and documentation are by Wynn Wagner III.  Updates
+have  been  made  to  this  document  by  Vince Perriello,  who  also  is
+responsible for most of the sample routine included with this document.
+
+They are  released to the  public for  any use  whatsoever as long as you 
+don't  modify any  transmitted  structure  or try to  make money  hawking
+either the sample code or this document as if you owned them.
+
+If you choose to use the  method  or  the  sample  routines,  you  do  so
+entirely at your own risk.  It  is  possible that the routines will cause
+physical damage to your equipment, an invasion of  fire ants, the plague,
+or an extended visit from in-laws.  If any  of  that  stuff  (or anything
+else) happens, you accept the consequences totally.
+
+
+CREDITS
+-------
+
+Fido  and  Fidonet  are  registered  trademarks of Tom Jennings and  Fido
+Software.
+
+ARCmail was originated by System Enhancement Associates.
+
+The ZModem protocol was designed by Chuck Forsberg. The SEAlink / SEAlink
+Overdrive protocols are copyrighted by System Enhancment Associates.  The
+TeLink protocol was designed and first implemented by Tom Jennings.
+
+The state charts in this document were done by Vince Perriello.
+
+Rick Huebner designed  and  implemented  the  basic  WaZOO  file  request
+method.  Update  request functionality was added by Vince Perriello.  Bob
+Hartman is responsible for the addition of Domain support.
+
+FTS-0001, describing the base FidoNet protocol, was created by Randy Bush.
+
+FTS-0007, describing enhancement to FTS-0001 using SEAlink and/or SEAlink
+Overdrive, was created by Phil Becker.
+
+YooHoo and YooHoo/2u2                                              Page 2
+Overview
+
+
+
+UPFRONT
+-------
+
+YOOHOO and YOOHOO/2U2 are  the  initial  handshakes  for the WaZOO e-mail
+protocol.  They are designed to let two systems establish a common ground
+for a netmail session while making  sure  that non-WaZOO software doesn't
+get upset by material it can't understand.
+
+The YOOHOO procedure begins as a single  byte  (0xf1).   If the system on
+the other end doesn't reply to that byte,  no  further  YOOHOO  or  WaZOO
+transmissions are attempted.  To a non-WaZOO netmail system,  the  YOOHOO
+byte will simply seem like a byte of debris.
+
+The  calling  system  initiates  the  YOOHOO  by  sending  the  attention
+character.   If the receiving system seems interested, the calling system
+sends a  128  byte packet containing such information as system and sysop
+names as well as a "capability mask." A 16-bit CRC protects the integrity
+of the 128-byte packet.
+
+In response, the receiving  system  prepares  a  128  byte packet to send
+back.  This is the YOOHOO/2U2 procedure.
+
+
+FEATURES
+--------
+
+The features of YOOHOO and YOOHOO/2U2 include
+
+      * non-interference with systems that don't understand the
+        handshake
+
+      * almost foolproof method for identifying a remote system
+        and establishing a common ground for transmission
+
+      * built-in room to expand the capabilities of WaZOO without
+        having to resort to a kludge
+
+
+USAGE
+-----
+
+A calling system simply uses  a  routine  that  transmits both YooHoo and
+TSYNC  handshake initiating characters to the  called  system.    If  the
+called system responds with an XMODEM 'NAK',  an FTS-0001 session will be
+initiated.  If an 'ENQ' is received, the  `YooHoo_Sender()'  routine will
+be invoked to handle the session negotiation.
+
+A  receiving  system  can call a routine like `YooHoo_Receiver()'  if  it
+detects the YOOHOO character, or just drop into the FTS-0001  logic if it
+sees a TSYNC.
+
+This simple method allows a mailer to take care of both the TSYNC and the
+YOOHOO handshakes.
+
+YooHoo and YooHoo/2u2                                              Page 3
+WaZOO Protocols
+
+
+
+PROTOCOLS
+---------
+
+Currently there are four WaZOO methods in use:
+
+1. ZedZap 
+   ------
+
+        a Zmodem variant. The originator does a batch send then goes into a
+        receive batch mode.  The called system does receive then send. In 
+        the event of a file request (see description below) made by the 
+        called system, one more turnaround is made to service the request.
+
+      * Unlike the "True" Zmodem protocol described by Chuck Forsberg, 
+        ZedZap routines must be able to handle a batch mode that has no 
+        actual files. In other words, it is possible for there to be a 
+        init sequence followed immediately by a ZFIN.
+
+      * The maximum packet size is 8192. This is usually varied based on 
+        the baud rate. For example, at 2400 it might be 2048 bytes, then 
+        for 9600 baud and above the maximum of 8192 could apply. Note that
+        THIS IS A SIGNIFICANT VARIATION FROM STRICT ZMODEM IMPLEMENTATION.
+        (There's another WaZOO capability bit for those systems which 
+        can not handle this block size)
+
+      * Netmail packets are transmitted as files with names in the form
+        "12345678.PKT". Because of this, multiple packets may be sent in 
+        a single session.
+
+      * If the calling system transmits a .REQ file for file requests, the
+        receiving system can respond to it.  See "WaZOO File Requests" 
+        (below) for information on the .REQ file.
+
+2. ZedZip
+   ------
+
+        This capability is identical to ZedZap, but does not use buffers
+        greater than 1K in size (like "True" Zmodem). It is also 
+        permissible to send a "null" packet in a ZedZip session. This
+        allows a system which must use a strict Zmodem implementation to
+        participate in a WaZOO session using Zmodem.
+
+
+3. DietIFNA
+   --------
+
+        The session operates like FTS-0001/FTS-0007. The notable exceptions 
+        are as follows:
+
+      * The same packet naming convention as ZedZap applies, allowing more
+        than one packet to be transmitted in a single session.
+
+YooHoo and YooHoo/2u2                                              Page 4
+WaZOO Protocols
+
+
+
+      * Telink file transfers don't even attempt to exchange file names
+        using modem7. The receiving system extracts the file name from the 
+        Telink or SEAlink header block.
+
+      * If SEAlink is used, run-ahead (the number of blocks to slide) is 
+        based on the baud rate:  BlocksToSlide = BaudRate / 400, up to a 
+        max of 24 blocks.
+
+      * When there is nothing to send, a system should remain quiet.  In 
+        other words, the end of a session can be determined by a timeout.
+
+      * Under no circumstances should "BARK" file request logic be active
+        during a DietIFNA session. File requests, if any, should be 
+        transmitted using a .REQ file.
+
+
+        Many implementations of DietIfna have been accomplished by the mere
+        exchange of packets, followed by straight FTS-0001/0007 code. This
+        is incorrect but probably not easily remedied at this point. We have
+        made an effort to document this change in "reality" in this revision
+        of the document.
+
+4. Janus
+   -----
+
+        Janus is a full-duplex simultaneous bidirectional file transfer
+        protocol. In other words, it can send and receive files at the same
+        time.  It's very loosely derived from ZModem and HDLC/X.25 protocol
+        technology, in that it uses variable length data-typed packets, and
+        that transmission of file data does not require ACKs.
+
+        The protocol is documented elsewhere; it is beyond the scope of this
+        document to do so.
+
+YooHoo and YooHoo/2u2                                              Page 5
+Choosing WaZOO Methods
+
+
+
+How to decide which WaZOO method to use
+---------------------------------------
+
+
+Since the called system has all the information  necessary to decide what
+WaZOO method to employ,  the best way to implement the process is for the
+calling  system  to send,  in its  capability  mask,  all the  bits which
+correspond to methods it can use (or wants to use)  in communicating with
+the called system.  The called  system then looks at these bits and sends
+back only the bit which corresponds to the method it wants to use.
+
+If the  called system  sends  back a mask  which contains  more  than one
+capability of the  calling system,  it can create a  problem situation if
+one system  arrives at its choice of methods  differently from the other.
+Thus, when the called system doesn't make the choice, both systems should
+choose as follows:
+
+1. Janus
+
+2. ZedZap
+
+3. ZedZip
+
+4. DietIFNA
+
+The capability highest on the list which both systems indicate ability to
+execute should be the one employed.
+
+YooHoo and YooHoo/2u2                                              Page 6
+WaZOO Filename conventions
+
+
+
+WaZOO FILENAMES
+---------------
+
+
+1. MESSAGE PACKETS ... xxxxxxxx.PKT
+
+        Normal (unarchived) messages are sent in a file name that has a tag 
+        of .PKT.  The "x" characters should be hex digits.
+
+
+2. ARCmail ... xxxxxxxx.{MO|TU|WE|TH|FR|SA|SU}#
+
+        Message packets are often shipped in an archive that has been
+        compressed with some LZ utility.
+
+        The file name consists of a name with hex digits. The tag is one of
+        seven two-character prefixes ("MO", "TU", "WE", "TH", "FR", "SA" or
+        "SU") and a number (0-9).
+
+        This particular naming convention was established by ARCmail version
+        0.60, which is a defacto standard in FidoNet.
+
+
+3. FILE REQUESTS ... xxxxxxxx.REQ
+
+        This is explained below.
+
+        In a nutshell, the file name consists of the receiving system's 
+        Fidonet address expressed as two 4-digit hex numbers.  The file tag 
+        is .REQ.
+
+        In a Janus session, the .REQ file isn't actually sent. Janus has
+        a transaction system which sends the .REQ file one line at a time
+        and then accepts the file(s) which the request generates.
+
+YooHoo and YooHoo/2u2                                              Page 7
+Flow of a ZedZap or ZedZip Session
+
+
+
+FLOW OF A ZEDZAP OR ZEDZIP SESSION
+----------------------------------
+
+
+
+The calling system:
+
+
+      * Send YooHoo
+
+      * Receive YooHoo/2u2
+
+      * In a single batch, send bundles, files, file request (.REQ) files 
+        (in that order)
+
+      * In a single batch, receive bundles, files, file requests, and 
+        requested files (in that order)
+
+      * If a file request (.REQ) file came in, send all requested files 
+        in a single batch.
+
+
+Receiving system:
+
+      * Receive YooHoo
+
+      * Send YooHoo/2u2
+
+      * In a single batch, receive bundles, files, file requests
+
+      * In a single batch, send bundles, files, our file requests, and 
+        respond to file requests that arrived from the remote system.
+
+      * If we sent a .REQ file in the preceding step, receive all files 
+        in a single batch.
+
+
+YooHoo and YooHoo/2u2                                              Page 8
+WaZOO File Requests
+
+
+
+WAZOO FILE REQUESTS
+-------------------
+
+Rick Huebner, who adapted the ZModem routines for Opus, and the architect of
+the Janus file transfer protocol, designed the ".REQ file"-based file request
+system.
+
+
+REQ FILE:
+
+A WaZOO file request is based on a request file.  The name of a request file
+is similar to the .OUT and .FLO files used by Opus-CBCS and similar mail
+products (such as BinkleyTerm).
+
+         TEMPLATE: netnode.REQ
+
+         EXAMPLE:  00010002.REQ   ... a request being sent to 1/2
+
+The .REQ file is simply a text file that contains the files we want from the
+remote system. Those file names can include wildcards, but should not contain
+a path. Optionally, there can be a password if the sending system requires one.
+
+The "netnode" part of the file name is built from the remote systems net and
+node numbers.  Both numbers become 4-character hex numbers in the file name.
+
+Let's say we're requesting THIS.ARC and all node lists from 12/2.  The file
+name would be 000C0002.REQ.  The contents would look like this:
+
+                  this.arc
+                  nodelist.*
+
+If the sysop of 12/2 requires a password of THAT to get the file THIS.ARC, the
+REQ file contents would have to change:
+
+                  this.arc !that
+                  nodelist.*
+
+Transaction-level passwords (of 6 or fewer characters) follow the file name:
+
+                  !
+
+YooHoo and YooHoo/2u2                                              Page 9
+WaZOO File Requests
+
+
+
+
+If the request is of the "update" genre, the type of update and the time,
+expressed as a UNIX-style long decimal ASCII number, follows the name, or in
+the event that there is a transaction-level password, the password. For
+example, an update request for file NEWOPUS.*, where you already have a file
+dated 1-January 1989, 00:00 and you live on the East Coast (GMT+06) would be:
+
+                  NEWOPUS.* +599634000
+
+The sign is required, it indicates the type of update request. A '+' means
+that all files matching the filespec "NEWOPUS.*" newer than the shown time
+will be sent, a '-' means that all matching files with dates up to and
+including the indicated time will be sent.
+
+
+The complete format of an action line in an REQ file is, then:
+
+          [!][<+/->
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0007.html b/html/ftsc/fts-0007.html new file mode 100755 index 00000000..4135db75 --- /dev/null +++ b/html/ftsc/fts-0007.html @@ -0,0 +1,1869 @@ + + +An Enhanced FidoNet(r) Technical Standard. + + + + +
+Document: FTS-0007
+Version:  003
+Date:     15-Oct-1990
+Updates:  FTS-0001
+
+
+
+
+                  An Enhanced FidoNet(r) Technical Standard
+                Extending FTS-0001 to include SEAlink protocol
+                    (Including Overdrive and File Restart)
+
+                             October 15, 1990
+
+
+
+
+Status of this document:
+
+    This document specifies an optional standard for the FidoNet community.
+    Implementation of the protocols defined in this document is not mandatory,
+    but all implementations of these protocols are expected to adhere to this
+    standard.  Distribution of this document is subject to the limitations of
+    the copyright notice displayed below.
+
+
+    Copyright 1989-90 by Philip L. Becker.  Portions of this document are
+    copyright 1986-90 by Randy Bush and are incorporated with his consent.
+    All rights reserved.  A right to distribute only without modification and
+    only at no charge is granted.  Under no circumstances is this document to
+    be reproduced or distributed as part of or packaged with any product or
+    other sales transaction for which any fee is charged.  Any and all other
+    reproduction or excerpting requires the explicit written consent of the
+    copyright holders.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    Introduction
+
+    While the basic FTS-0001 protocol has become reasonably standardized, it
+    is technically inferior when used with modem speeds of 2400bps or higher,
+    and results in considerably slower file transfers than more sophisticated
+    protocols under many line and modem configurations.
+
+    Very sophisticated protocols exist to allow absolute maximum efficiency,
+    but these protocols are much more difficult to implement than the basic
+    XMODEM used by FTS-0001.  A need exists for a standardized, easy to
+    implement extension to the FTS-0001 protocol which can gain much better
+    performance.  SEAlink is such an extension.  It is nearly as easy to
+    implement as the FTS-0001 protocol with which it is fully backward
+    compatible.  Despite its ease of implementation, it provides several
+    significant performance advantages. Among these advantages are:
+
+         o  Transparently communicates with strict FTS-0001 implementations.
+
+         o  Transparently communicates with FTS-0001 variants which omit
+            either the MODEM7 file name or the TeLink header block.
+
+         o  Transparently becomes a sliding window XMODEM protocol when
+            communicating with a like implementation.  This sliding window
+            protocol gives significantly improved throughput when there is
+            an end-to-end delay.
+
+         o  Offers a negotiated streaming mode for high speed asymmetrical
+            modems to further enhance throughput for such links.
+
+         o  Offers a negotiated file restart capability which allows an
+            interrupted transfer to restart where it left off, reducing
+            time spent to retransmit the file.
+
+    This document defines the  data structures and communication protocols
+    which a FidoNet SEAlink implementation must provide.  The implementor of
+    FidoNet compatible systems is the intended audience of this document.
+
+    This document has the same overall format and state table descriptions
+    as FTS-0001.  SEAlink is implemented by modifying the following tables:
+
+       Session Layer:   Sender - S1
+       Network Layer:   Batch File Sender - BS0
+       Network Layer:   Batch File Receiver - BR0
+       Data Link Layer: XMODEM/TeLink Sender - XS0
+       Data Link Layer: XMODEM/TeLink Receiver - XR0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                             1
+                              Table of Contents
+
+
+                                                                          Page
+    The purpose of the SEAlink protocol ...................................  3
+
+    How SEAlink negotiates its enhancements ...............................  4
+
+    Basic requirements for a FidoNet Implementation .......................  5
+
+    Levels of Compliance ..................................................  5
+
+    The ISO/OSI Reference Model ...........................................  5
+
+    Data Description Language .............................................  6
+
+    Finite State Machine Notation .........................................  7
+
+    Glossary of variables and terms .......................................  7
+
+    Application layer .....................................................  8
+
+    Presentation layer ....................................................  8
+
+    Session layer protocol ................................................  8
+         Session State Table: Sender (S0) .................................  9
+         Session State Table: Receiver (R0) ............................... 10
+
+    Transport layer ....................................................... 10
+
+    Network layer ......................................................... 11
+         Data Definition: MODEM7 file name ................................ 11
+         Network State Table: Batch File Sender (BS0) ..................... 12
+         Network State Table: Batch File Receiver (BR0) ................... 13
+
+    Data Link Layer ....................................................... 14
+         Data Definition: XMODEM data block (CRC) ......................... 14
+         Data Definition: XMODEM data block (Checksum) .................... 15
+         Data Definition: TeLink header block ............................. 15
+         Data Definition: SEAlink header block ............................ 16
+         Data Definition: SEAlink RESYNC packet ........................... 16
+         DDL Definition: XMODEMBlock, TeLink header ....................... 17
+         DDL Definition: SEAlink header, ACK, NAK, RESYNC block ........... 18
+         Checksum and CRC calculation algorithms .......................... 19
+         Data Link Layer protocol ......................................... 20
+         Data Link State Table: XMODEM/TeLink/SEAlink Sender (XS0) ........ 21
+         Data Link State Table: Transmitter ACK/NAK check (AC0) ........... 22
+         Data Link State Table: XMODEM/TeLink/SEAlink Receiver (XR0) ...... 24
+         Data Link State Table: Send NAK (SN0) ............................ 26
+         Data Link State Table: Send ACK (SA0) ............................ 26
+         Data Link State Table: MODEM7 Filename Sender (MS0) .............. 27
+         Data Link State Table: MODEM7 Filename Receiver (MR0) ............ 27
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            2
+    The purpose of the SEAlink protocol
+
+    The purpose of the SEAlink protocol is to provide a much higher level
+    of capability than the XMODEM protocol provides, while retaining the
+    ease of implementation which has made the XMODEM protocol ubiquitous.
+
+    In order for an extended protocol to function in FidoNet, it has to be
+    fully upward compatible with FTS-0001 mailers, and also those slight
+    variants of FTS-0001 which can communicate well with FTS-0001 mailers.
+    To meet this requirement, any extension to the FTS-0001 protocol has
+    to be capable of transparently negotiating away its extended capabilities
+    and communicate with strict FTS-0001 mailers (and their approved variants)
+    properly and reliably.
+
+    This means that an extended protocol must miminally do the following:
+
+        o  Detect that the other mailer can or cannot support its extensions
+           automatically, and within the framework of a legitimate FTS-0001
+           protocol encounter.
+
+        o  Support mail sessions with or without MODEM7 file names and with
+           or without TeLink headers in either combination.
+
+    To be useful such an extended protocol should also be able to reliably
+    detect when the other mailer can support its extensions so they can
+    be used to maximum benefits.
+
+    The major problems which exist with a standard FidoNet FTS-0001 session
+    result from the use of the XMODEM protocol.  This is a half duplex protocol
+    which forces a line turnaround on every transmitted block.  As a result,
+    any end-to-end delay in the transmission link is directly added to each
+    transmitted data block twice (once for each line turnaround).
+
+    To dramatize how easily XMODEM is impacted by even small line delays, let's
+    examine a 2400bps call on a line with 500ms (1/2 second) delay on each line
+    turnaround.  This is not an uncommon delay time on long distance calls.  A
+    single data block in the XMODEM CRC format contains 133 characters.  This
+    means it will be transmitted in 554ms.  The ACK/NAK response is a single
+    character and will take 4ms.  Thus with no delay (an ideal link) an XMODEM
+    transfer would send 128 data characters in 558ms for an effective data
+    throughput of about 230cps.  With a 500ms line turnaround delay, these same
+    128 data bytes will take 1558ms resulting in a throughput of 82cps.  If
+    faster modem speeds are used, the percentage impact is even greater.
+
+    The solution to this problem is to enhance the XMODEM protocol by adding
+    a "sliding window" capability which allows more than one block to be sent
+    before an acknowledgment is received.  This converts the protocol to a
+    full duplex protocol, and if the "window size" (the number of blocks which
+    may be sent before the sender must wait for an acknowledgment) is larger
+    that the line turnaround delay, then the ideal throughput can be restored
+    even to lines with long turnaround delays.  SEAlink is such a protocol.
+
+    The standard SEAlink window size is 6 blocks, but the state tables given
+    below implement a receiver which will operate correctly with any window
+    size up to 127 blocks.  Thus an implementation which uses a larger window
+    size will be totally compatible with the standard 6 block window versions.
+
+    A second problem with the XMODEM protocol arises when asymmetrical high
+    speed modems are used.  These modems achieve much higher throughput when
+    data is sent in only one direction.  Since they provide error free links,
+    a protocol which does not send any positive acknowledgments, but only
+    reports any bad blocks received will achieve a significantly higher
+
+
+
+                                                                             3
+    throughput than a protocol which is either full duplex or which turns
+    around between each block such as XMODEM or normal SEAlink.  It is for
+    this purpose that SEAlink Overdrive is provided.  It is a streaming version
+    of SEAlink designed to provide much higher throughput on asymmetrical
+    high speed links which provide end-to-end data flow control.
+
+    Finally, there is the annoying problem which occurs when a large data file
+    transfer has nearly completed and a loss of connection occurs.  Normally
+    the entire file must be retransmitted on a new call, resulting in lost
+    time and money.  The SEAlink RESYNC enhancement allows an interrupted
+    file transfer to be resumed at the point it was interrupted thus minimizing
+    the impact of such an interruption.
+
+    How SEAlink Negotiates its enhancements
+
+    SEAlink makes some assumptions about how FTS-0001 mailer implementations
+    react to various stimuli in order to negotiate its enhancements.  For the
+    sender, the test consists of two parts:
+
+    1.  Send a SEAlink header and see if the other end acknowledges it.  In
+        general it will, because most XMODEM implementations will think that
+        the SEAlink header is a "previous block" and ACK and discard it.  If
+        the receiver refuses to accept a SEAlink header block in three tries,
+        then it clearly cannot do SEAlink protocol and the negotiation is over.
+
+    2.  Since the receiver's acknowledgment of the SEAlink header is not a
+        sufficient criteria to determine if the receiver in fact supports
+        SEAlink, the sender dynamically examines the acknowledgments the
+        receiver provides to determine if their format indicates support of
+        SEAlink or not and adjusts its sending techniques accordingly.  This
+        is also the technique used to detect whether the receiver is in fact
+        supporting any extensions (such as SEAlink Overdrive) which have been
+        requested in the header.
+
+    For the receiver, the negotiation occurs during the receipt of the first
+    valid block.
+
+    1.   If the first block received is a valid SEAlink header, then the
+         transmitter supports SEAlink and the receiver can switch to it.  This
+         same header also indicates if the transmitter wants or can support the
+         SEAlink options such as Overdrive and File RESYNC.
+
+     2.  If the first block received is a valid TeLink header, then the
+         transmitter supports a variant of FTS-0001 and SEAlink support may
+         be assumed to be absent.
+
+     3.  If the first block received is an XMODEM data block then SEAlink
+         support may also be assumed to be absent.
+
+    If the receiver gets a SEAlink header, it can then arbitrarily decide
+    which of any requested options it wishes to use.  It may not use an option
+    for which support is not indicated in the sender's SEAlink header block.
+
+    The remainder of this document provides the details for a full SEAlink
+    implementation with Overdrive and RESYNC support.  A glossary of terms and
+    indicators is provided along with a full state table description of the
+    protocol implementation.
+
+
+
+
+
+
+
+
+                                                                             4
+    This document follows the format of FTS-0001 to allow ease of
+    comparison of the two protocols.  This document could not have been
+    generated without the tremendous efforts of those whose work resulted in
+    FTS-0001.  FidoNet owes a great debt to those efforts.  The following
+    introduction is reprinted from FTS-0001.
+
+    The layered metaphor of the ISO Open Systems Interface reference model
+    has been used to view FidoNet from a standard perspective.  As with most
+    prospective ISO/OSI descriptions, FidoNet does not always make this easy.
+
+
+   1. Basic Requirements for a FidoNet Implementation
+
+      Compatibility is a set of abilities which, when taken as a whole, make
+      it safe to list a net or node in the IFNA nodelist.  In other words,
+      if another node should attempt contact, does it have a reasonable
+      chance of successful communication?  This is a social obligation, as
+      the calling system pays money for the attempt.  Conversely, an
+      implementation should be able to successfully contact other systems,
+      as life is not a one-way street.
+
+      A FidoNet implementation must be able to call other nodes and transfer
+      messages and files in both directions.  This includes pickup and poll.
+
+      A FidoNet implementation must be able to accept calls from other nodes
+      and transfer messages and files in both directions.  This includes
+      pickup.
+
+      A FidoNet implementation must be able to receive and process the IFNA
+      format nodelist, and transfer nodelists to other nodes.  A companion
+      document, FTS-0005, defines the IFNA format nodelist and how to
+      interpret and process it.
+
+      A FidoNet implementation must route messages which do not have files
+      attached through net hosts as shown in an IFNA format nodelist.
+
+
+   2. Levels of Compliance
+
+      This documents represents an extended FidoNet implementation.  It
+      defines a well tested extension which is optional but provides
+      sufficient additional function that implementors should seriously
+      consider it.  SEAdog(tm), from System Enhancement Associates,
+      is the inspiration for this extended FidoNet implementation.
+      System Enhancement Associates is the creator of the SEAlink protocol.
+
+
+   3. The ISO/OSI Reference Model (cribbed from "Protocol Verification via
+      Executable Logic Specifications", D. P. Sidhu, in Rudin & West)
+
+      In the ISO/OSI model, a distributed system consists of entities that
+      communicate with each other according to a set of rules called a
+      protocol.   The model is layered, and there are entities associated
+      with each layer of the model which provide services to higher layers
+      by exchanging information with their peer entities using the services
+      of lower layers.  The only actual physical communication between two
+      systems is at the lowest level.
+
+
+
+
+
+
+
+
+                                                                             5
+      Several techniques have been used in the specification of such
+      protocols.  A common ingredient in all techniques is the notion of the
+      extended finite state automata or machine.  Extensions include the
+      addition of state variables for the storing of state information about
+      the protocol.  The state of an automaton can change as a result of
+      one of the following events:
+
+      o Request from an upper network layer for service
+
+      o Response to the upper layer
+
+      o Request to the lower network layer to perform a service
+
+      o Response from the lower layer
+
+      o Interaction with the system and environment in which the protocol is
+        implemented (e.g. timeouts, host operating system aborts, ...)
+
+      A protocol specification, in a large part, consists of specifying
+      state changes in automata which model protocol entities and in
+      describing the data which they exchange.
+
+      For historical reasons, the term packet is used in FidoNet to
+      represent a bundle of messages, as opposed to the more common use as a
+      unit of communication, which is known as a block in FidoNet.
+
+
+   4. Data Description
+
+      A language specific notation was avoided.  Please help stamp out
+      environmental dependencies.   Don't panic, there are rectangular record
+      layouts too.  The following defines the data description language used.
+
+      (* non-terminals *)
+      UpperCaseName - to be defined further on
+
+      (* literals *)
+      "ABC"         - ASCII character string, no termination implied
+      nnH           - byte in hexadecimal
+
+      (* terminals *)
+      someName      - 16-bit integer, low order byte first (8080 style)
+      someName[n]   - field of n bytes
+      someName[.n]  - field of n bits
+      someName(n)   - Null terminated string allocated n chars (incl Null)
+      someName{max} - Null terminated string of up to max chars (incl Null)
+      someName - String of up to max chars, NOT null terminated
+
+      (* punctuation *)
+      a b           - one 'a' followed by one 'b'
+      ( a | b )     - either 'a' or 'b', but not both
+      { a }         - zero or more 'a's
+      [ b ]         - zero or one 'b'
+      (* comment *) - ignored
+
+      (* predeclared constant *)
+      Null          = 00H
+
+
+
+
+
+
+
+
+                                                                             6
+ 5. Finite State Machine Notation
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | fnn*|          |                         |                         |     |
+    `-----+----------+-------------------------+-------------------------+-----'
+
+    State #      - Number of this state (e.g. R13).
+                   f  - FSM initial (Window, Sender, Receiver, ...)
+                   nn - state number
+                   *  - state which represents a lower level protocol  which
+                        is represented by yet another automation.
+
+    State Name   - Descriptive name of this state.
+
+    Predicate(s) - Conditions which terminate the state.  If predicates are
+                   non-exclusive, consider them ordered.
+
+    Action(s)    - Action(s) corresponding to predicate(s)
+
+    Next State   - Subsequent state corresponding to predicate(s)
+
+    Ideally, there should be a supporting section for each state which
+    should give a prose description of the state, its predicates, actions,
+    etc.  So much for ideals.  The following is a list of all of the terms
+    and variables used in the following state machine descriptions:
+
+
+                     Glossary of variables and terms
+
+    SEAlink - Flag indicating SEAlink or XMODEM mode
+
+    SLO - Flag indicating overdrive if in SEAlink mode
+
+    RESYNC - Flag indicating whether transmitting end can honor RESYNC
+             file positioning requests or only NAKs
+
+    MACFLOW - Flag indicating whether the sender supports the Macintosh flow
+              control option.  This is an optional feature used by TABBY
+              because the Macintosh serial port does not support RTS/CTS.
+
+    CRC - Flag indicating whether block check is done using CRC or Checksum
+
+    T1 and T2 - Timeout Timers which run asynchronously with the code
+
+    WINDOW - Number of unacknowledged blocks which may be transmitted
+
+    SendBLK - Next 128 byte block number in file to send.  May not occur in
+              sequential order, so file positioning may be necessary when
+              it is time to send this block
+
+    ACKBLK - Highest block number in file which has been acknowledged by
+             the receiver as received without error
+
+    Last Blk - Block number of last 128 byte block (or partial block) in the
+               file being sent.
+
+    NumNAK - Number of NAKs received since last ACK
+
+    ACKs Rcvd - Number of ACKs received since the start of this file send
+
+
+
+                                                                             7
+                     Glossary of variables and terms (cont.)
+
+    ACKST - State of ACK/NAK machine during auto-detect of SEAlink or XMODEM
+            style ACK/NAK block receipt
+
+    RESYNC BLK# - Block number in file requested by a received RESYNC packet
+
+    ARBLK8 - Block # (0-255) received in a SEAlink style ACK/NAK packet
+
+    ARBLK - Block # in file (calculated from ARBLK8) which is the actual
+            block being referenced in the SEAlink ACK/NAK packet
+
+    blocknum - Block # (0-255) sent in a SEAlink style ACK/NAK packet
+
+    WriteBLK - Block # in file to write next correctly received data block.
+               Note: Block 1 is the first byte of the file.
+
+    CHR - Temp holding variable for received character during send operation
+
+
+ B. Application Layer : the System from the User's View
+
+    This is unchanged from FTS-0001.
+
+
+ C. Presentation Layer : the User from the System's View
+
+    This is unchanged from FTS-0001.
+
+
+ D. Session Layer Protocol : Connecting to Another FidoNet Machine
+
+    A session is a connection between two FidoNet machines.  It is currently
+    assumed to be over the DDD telephone network via modems.  The calling
+    machine starts out as the sender and the called machine as the receiver.
+    The pickup feature is described by the sender and receiver changing
+    roles midway through the session, after the sender has transferred the
+    message packet and any attached files.  Due to the lack of security in
+    the pickup protocol (danger of pickup by a fake node), extensions to the
+    basic Session protocol have been developed.  This document describes only
+    the minimum Session Layer protocol (as in FTS-0001).
+
+    Once a connection has been established, each system should ensure that
+    the physical connection remains throughout the session.  For physical
+    layers implemented through modems, this means monitoring the carrier
+    detect signal, and terminating the session if it is lost.
+
+    Error detection at the physical layer should be monitored for both sent
+    and received characters.  Parity, framing, and other physical errors
+    should be detected.
+
+    The only change to the Session Layer state tables from FTS-0001 is in the
+    Sender state "S1", Predicate "1" (S1.1) entry.
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                             8
+    Sender
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | S0  | SendInit |                         | dial modem              | S1  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S1  | WaitCxD  |1| carrier detected      | delay 1-5 seconds       | S2  |
+    |     |  (*1)    | |                       | Set SLO if > 2400bps,   |     |
+    |     |          | |                       | Reset SLO if <= 2400bps |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| busy, etc.            | report no connection    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| voice                 | report no carrier       | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| carrier not detected  | report no connection    | exit|
+    |     |          | | within 60 seconds     |                         |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S2  | WhackCRs |1| over 30 seconds       | report no response <cr> | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ?? <cr>s received     | delay 1 sec             | S3  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| <cr>s not received    | send <cr> <sp> <cr> <sp>| S2  |
+    |     |          | |                       |   delay ??? secs        |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S3  | WaitClear|1| no input for 0.5 secs | send TSYNCH = AEH       | S4  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| over 60 seconds       | hang up, report garbage | exit|
+    |     |          | | and line not clear    |                         |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S4* | SendMail |                         | (XMODEM send packet XS0)| S5  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S5  | CheckMail|1| XMODEM successful     | (Fido registers success)| S6  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| XMODEM fail or timeout| hang up, report mail bad| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S6* | SendFiles|                         | (BATCH send files BS0)  | S7  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S7  | CheckFile|1| BATCH send successful |                         | S8  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| BATCH send failed     | hang up, rept files fail| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S8  | TryPickup|1| wish to pickup        | note send ok            | R2* |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| no desire to pickup   | delay 5 secs            | exit|
+    |     |          | |                       |   hang up, rept send ok |     |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    Although the above shows the sender emitting only one TSYNCH, it is
+    recommended that a timeout of 5-20 seconds should initiate another TSYNCH.
+    The receiver should tolerate multiple TSYNCHs.
+
+    *1 - The action for (S1.1) is the only change from the corresponding
+         FTS-0001 state table.
+
+
+
+
+
+
+
+
+
+
+
+                                                                             9
+    Receiver
+
+    The receiving FSM is given an external timer, the expiration of which
+    will cause termination with a result of 'no calls' (R0.2).
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R0  | WaitCxD  |1| carrier detected      |                         | R1  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| external timer expires| report no calls         | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R1  | WaitBaud |1| baud rate detected    | send signon with <cr>s  | R2  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| no detect in ?? secs  | hang up, report no baud | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R2  | WaitTsync|1| TSYNCH received       | ignore input not TSYNCH | R3  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| 60 seconds timeout    | hang up, report not Fido| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R3* | RecMail  |                         | (XMODEM rec packet XR0) | R4  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R4  | XRecEnd  |1| XMODEM successful     | delay 1 second          | R5  |
+    |     |          | |                       |   flush input           |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| XMODEM failed         | hang up, rept mail fail | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R5* | RecFiles |                         | (BATCH rec files BR0)   | R6  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R6  | ChkFiles |1| BATCH recv successful | delay 2 secs            | R7  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| BATCH recv failed     | hang up, report bad file| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R7  | AllowPkup|1| have pickup for sender| receiver becomes sender | S3* |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| nothing to pickup     | hang up, rept recv ok   | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    There is no change in the Session Layer Receiver state table from FTS-0001.
+
+
+ E. Transport Layer : ?????
+
+    This is unchanged from FTS-0001.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            10
+ F. Network Layer : the Network's View of the System, Routing and Packets
+
+   1. Network Layer Data Definition : the Packet Header
+
+      This is unchanged from FTS-0001.
+
+
+   2. Network Layer Data Description : a File with Attributes
+
+      The BATCH protocol uses the MODEM7 filename and/or SEAlink/TeLink/XMODEM
+      file transfer protocols to transfer the file with attributes.
+
+      When a file is transferred via FidoNet, an attempt is made to also
+      pass the operating system's attributes for the file such as length,
+      modification date, etc.  FidoNet does this via a special prefix block
+      to the XMODEM file transfer using a protocol known as TeLink.  As the
+      TeLink protocol relies on a modification to the XMODEM file transfer
+      protocol, it is documented at the data link layer level.  Optionally,
+      if both sender and receiver implement the SEAlink extension, file
+      information is passed using the SEAlink header block which also
+      contains feature negotiation information.
+
+      The MODEM7 file name is redundant if there is also a TeLink or SEAlink
+      block, in which case the name may be taken from either or both.  In this
+      extended implementation, the MODEM7 file name is never required.  It
+      is sent, however, if it appears that the other node is using a strict
+      FTS-0001 implementation.  This implementation will adapt to an FTS-0001
+      variant which only sends the TeLink header without the MODEM7 filename
+      also so that it is compatible with all know variants of FTS-0001 which
+      are currently in the FidoNet network.
+
+
+                          FileName as Sent by MODEM7
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |                   fileName                    |
+              ~                   8  bytes                    ~
+              |           left adjusted blank filled          |
+              +-----------------------------------------------+
+        8   8 |                    fileExt                    |
+              ~                    3  bytes                   ~
+              |           left adjusted blank filled          |
+              `-----------------------------------------------'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            11
+ 3. Network Layer Protocol : BATCH File Finite State Machines
+
+    BATCH File Sender
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS0 | MoreFiles|1| more files to send    |                         | BS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| no more files to send |                         | BS4 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS1 | WaitType |1| rec NAK               | (MODEM7 FName send MS0) | BS2 |
+    |     |    (*1)  +-+-----------------------+-------------------------+-----+
+    |     |          |2| rec 'C'               | (SEAlink send file XS0) | BS3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| rec other char        | eat character           | BS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| > 20 sec in BS1       | report name send bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS2 | CheckFNm |1| MODEM7 Filename ok    | (TeLink send file XS0T) | BS3 |
+    |     |    (*2)  +-+-----------------------+-------------------------+-----+
+    |     |          |2| MODEM7 Filename bad   | report name send bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS3 | CheckFile|1| File send ok          |                         | BS0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| File send bad         | report file send bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS4 | EndSend  |1| rec NAK or 'C'        | send EOT, report send ok| exit|
+    |     |    (*3)  +-+-----------------------+-------------------------+-----+
+    |     |          |2| 10 secs no NAK or 'C' | send EOT, report no NAK | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - Note: Filenames must be upper case ASCII.  The data link layer uses
+         lower case "u" as a control character during MODEM7 name transmission.
+
+    *2 - Note: SEAdog (through version 4.51b) does not possess a state "XS0T".
+         It therefore calls XS0 from state BS2, resulting in a MODEM7 file name
+         being sent with no TeLink header on batch file transmissions when it
+         is not in SEAlink mode.
+
+    *3 - When no files remain, the sender responds to the receiver's NAK with
+         an EOT.  The EOT is not ACK/NAKed by the receiver.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            12
+   BATCH File Receiver
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | BR0 | TestSL   |                         | Send 'C',               | BR1 |
+    |     |          |                         |   Set T1 to 10 sec      |     |
+    |     |          |                         |   Set T2 to 120 sec     |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BR1 | CheckSL  |1| > 2 sec with no data  | Send 'C'                | BR1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Timer T2 expired      | (MODEM7 FName recv MR0) | BR2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Character Waiting     | "Peek" char to CHR (*1) | BR4 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| Timer T1 expired      | (MODEM7 FName recv MR0) | BR2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BR2 | CheckFNm |1| no more files         | report files recd ok    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Filename ok           | (Rcv file Telink XR0)   | BR3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Filename bad          | report name recv bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BR3 | CheckFile|1| File received ok      |                         | BR0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| File received bad     | report file recv bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BR4 | FindType |1| CHR = NUL             | eat character,          | BR1 |
+    |     |          | |                       |   Reset T1 to 20 secs   |     |
+    |     |   (*2)   +-+-----------------------+-------------------------+-----+
+    |     |          |2| CHR = SOH             | (Rcv File SEAlink XR0B) | BR3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| CHR = SYN             | (Rcv File Telink XR0B)  | BR3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| CHR = EOT or          | eat character,          | exit|
+    |     |          | | CHR = SUB             |   report files recd ok  |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| CHR = Other char      | eat character           | BR1 |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - "Peek" a character means to place it in CHR but leave it in the input
+         buffer so the next read operation will re-read it.
+
+    *2 - "Eat" a character means to remove it from the input buffer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            13
+ G. Data Link Layer : Error-Free Data Transfer
+
+   1. Data Link Layer Data Definition : XMODEM/TeLink/SEAlink Blocks
+
+      XMODEM transfers are in blocks of 128 uninterpreted data bytes
+      preceded by a three byte header and followed by either a one byte
+      checksum or a two byte crc remainder.  XMODEM makes no provision  for
+      data streams which are not an integral number of blocks long.
+      Therefore, the sender pads streams whose length is not a multiple of
+      128 bytes with the end-of-file character (^Z for MS-DOS), and uses some
+      other means to convey the true data length to the receiver (e.g.
+      SEAlink or TeLink file info header block).
+
+      Data blocks contain sequence numbers so the receiver can ensure it has
+      the correct block.  Data block numbers are sequential unsigned eight bit
+      integers beginning with 01H and wrapping to 00H.  A TeLink or SEAlink
+      header block is given sequence number 00H.
+
+      For files which are attached to the mail packet (but not the mail packet
+      itself), if the sending system is aware of the file attributes as they
+      are known to the operating system, then the first block of the XMODEM
+      transfer may be a special TeLink block to transfer that information.
+      This block differs in that the first byte is a SYN character as
+      opposed to an SOH, and it is always sent checksum as opposed to CRC.
+      Should the receiver be unwilling to handle such information, after four
+      NAKs (or "C"s), the sender skips this special block and goes on to the
+      data itself.
+
+      In this extended protocol the TeLink header block may be replaced by
+      the SEAlink header block which conveys protocol negotiation information
+      in addition to the file attributes if both nodes implement SEAlink.
+
+
+
+                        XMODEM Data Block (CRC mode)
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |        SOH  -  Start Of Header -  01H         |
+              +-----------------------------------------------+
+        1   1 |                 BlockNumber                   |
+              +-----------------------------------------------+
+        2   2 |               BlockComplement                 |
+              +-----------------------------------------------+
+        3   3 |                128 bytes  of                  |
+              ~                uninterpreted                  ~
+              |                    data                       |
+              +-----------------------------------------------+
+      131  83 |             CRC high order byte               |
+              +-----------------------------------------------+
+      132  84 |             CRC  low order byte               |
+              `-----------------------------------------------'
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            14
+                      XMODEM Data Block (Checksum mode)
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |        SOH  -  Start Of Header -  01H         |
+              +-----------------------------------------------+
+        1   1 |                 BlockNumber                   |
+              +-----------------------------------------------+
+        2   2 |               BlockComplement                 |
+              +-----------------------------------------------+
+        3   3 |                128 bytes  of                  |
+              ~                uninterpreted                  ~
+              |                    data                       |
+              +-----------------------------------------------+
+      131  83 |                Checksum byte                  |
+              `-----------------------------------------------'
+
+
+                       TeLink File Descriptor Block
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       SYN  -  File Info Header -  16H         |
+              +-----------------------------------------------+
+        1   1 |                     00H                       |
+              +-----------------------------------------------+
+        2   2 |                     FFH                       |  dec  hex
+              +-----------------------------------------------+
+        3   3 |     File Length, least significant byte       |  0    0
+              +-----------------------------------------------+
+        4   4 | File Length, second to least significant byte |  1    1
+              +-----------------------------------------------+
+        5   5 |  File Length, second to most significant byte |  2    2
+              +-----------------------------------------------+
+        6   6 |      File Length, most significant byte       |  3    3
+              +-----------------------------------------------+
+        7   7 |            Creation Time of File              |  4    4
+              |                "DOS Format"                   |
+              +-----------------------------------------------+
+        9   9 |            Creation Date of File              |  6    6
+              |                "DOS Format"                   |
+              +-----------------------------------------------+
+       11   B |                 File  Name                    |  8    8
+              ~                  16 chars                     ~
+              |        left justified  blank filled           |
+              +-----------------------------------------------+
+       27  1B |                    00H                        | 24   18
+              +-----------------------------------------------+
+       28  1C |            Sending Program Name               | 25   19
+              ~                  16 chars                     ~
+              |         left justified  Null filled           |
+              +-----------------------------------------------+
+       44  2B |            01H (for CRC) or 00H               | 41   29
+              +-----------------------------------------------+
+       45  2C |                    fill                       | 42   2A
+              ~                  86 bytes                     ~
+              |                  all zero                     |
+              +-----------------------------------------------+
+      131  83 |                Checksum byte                  |
+              `-----------------------------------------------'
+
+
+
+
+
+                                                                            15
+      Offset           SEAink File Descriptor Block
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       SOH  -  Start of Header -   01H         |
+              +-----------------------------------------------+
+        1   1 |                     00H                       |
+              +-----------------------------------------------+
+        2   2 |                     FFH                       |  dec  hex
+              +-----------------------------------------------+
+        3   3 |         File Length, (4 bytes, LSB first)     |  0    0
+              +-----------------------------------------------+
+        7   7 |            Creation Date/Time of File         |  4    4
+              |   (4 bytes, LSB first, seconds since 1979)    |
+              +-----------------------------------------------+
+       11   B |                 File  Name                    |  8    8
+              ~                  17 chars                     ~
+              |        left justified   Null filled           |
+              +-----------------------------------------------+
+       28  1C |            Sending Program Name               | 25   19
+              ~                  15 chars                     ~
+              |         left justified  Null filled           |
+              +-----------------------------------------------+
+       43  2B |            > 0 if SLO Requested               | 40   28
+              +-----------------------------------------------+
+       44  2C |           > 0 if RESYNC Supported             | 41   29
+              +-----------------------------------------------+
+       45  2D |           > 0 if MACFLOW Supported            | 42   2A
+              +-----------------------------------------------+
+       46  2E |                    fill                       | 43   2B
+              ~                  85 bytes                     ~
+              |                  all zero                     |
+              +-----------------------------------------------+
+      131  83 |            CRC high order byte                |
+              +-----------------------------------------------+
+      132  84 |            CRC  low order byte                |
+              `-----------------------------------------------'
+  
+
+      Offset                SEAlink RESYNC packet
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       SYN - Start of RESYNC packet - 16H      |
+              +-----------------------------------------------+
+        1   1 |     ASCII Decimal 128 byte block number in    |
+              ~     file to restart sending.  (No leading     ~
+        n     |     or trailing blanks, MSD first).           |
+              +-----------------------------------------------+
+        n+1   |       ETX -  End of RESYNC packet  - 03H      |
+              +-----------------------------------------------+
+        n+2   |     (*1)     CRC  low order byte              |
+              +-----------------------------------------------+
+        n+3   |     (*1)     CRC high order byte              |
+              `-----------------------------------------------'
+
+              *1 - CRC does not include the SYN or ETX and is
+                   in the reverse byte order from the CRC in a
+                   normal XMODEM data packet.  The following is
+                   a sample RESYNC packet for file block 27 (1BH).
+
+                     SYN   '2'   '7'   ETX  CRCLO CRCHI 
+                   .-----+-----+-----+-----+-----+-----.
+                   | 16H | 32H | 37H | 03H | 43H | 25H |
+                   `-----+-----+-----+-----+-----+-----'
+
+
+                                                                            16
+    Data Description language definitions of block types:
+
+      XMODEMData   =   XMODEMBlock    (* block of data with hdr and trailer *)
+                     | SEALinkBlock   (* SEALink File Descriptor Block *)
+                     | TeLinkBlock    (* TeLink File Descriptor Block *)
+                     | ReSyncBlock    (* SEAlink RESYNC request packet *)
+                     | ACK            (* acknowledge data received ok *)
+                     | NAK            (* negative ACK & poll 1st block *)
+                     | SEAlinkACK     (* acknowledge data received ok *)
+                     | SEAlinkNAK     (* negative ACK & poll 1st block *)
+                     | EOT            (* end of xfer, after last block *)
+                     | "C"            (* 43H *)
+
+
+      XMODEMBlock  = SOH              (* Start of Header, XMODEM Block *)
+                     blockNumber[1]   (* sequence, i'=mod( i+1, 256 ) *)
+                     blockCompl[1]    (* one's complement of blockNumber *)
+                     data[128]        (* uninterpreted user data block *)
+                     (CRC | Checksum) (* error detect/correction code *)
+
+
+      TeLinkBlock  = SYN              (* File Info Header *)
+                     00H              (* block no, must be first block *)
+                     FFH              (* one's complement of block no *)
+                     fileLength[4]    (* length of data in bytes *)
+                (*2) CreationTime[2]  (* time file last modified or zero *)
+                (*2) CreationDate[2]  (* date file last modified or zero *)
+                     fileName(16)     (* name of file, not vol or dir *)
+                     00H              (* header version number *)
+                     sendingProg(16)  (* name of program on send side *)
+                (*1) crcMode[1]       (* 01H for CRC 00H for Checksum *)
+                     fill[87]         (* zeroed *)
+                     Checksum         (* error detect/correction code *)
+
+    *1 -  Note that the crcMode is always set to 01H in current implementations
+          as all TeLink/XMODEM implementations use the CRC method.  Therefore,
+          it is always set to 01H by the sender, and is ignored by the receiver.
+
+    *2 -  CreationDate and CreationTime are MS-DOS format as follows:
+
+      CreationDate = year[.7]         (* 7 bits, years since 1980, 0-127  *)
+                     month[.4]        (* 4 bits, month of year, 1-12 *)
+                     day[.5]          (* 5 bits, day of month, 1-31 *)
+
+      CreationTime = hour[.5]         (* 5 bits, hour of day, 0-23 *)
+                     minute[.6]       (* 6 bits, minute of hour, 0-60 *)
+                     biSeconds[.2]    (* 6 bits, seconds/2, 0-29 *)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            17
+    Data Description Language definition of the block types added by this
+    extended protocol specification:
+
+     SEALinkBlock  = SOH              (* File Info Header *)
+                     00H              (* block no, must be first block *)
+                     FFH              (* one's complement of block no *)
+                     fileLength[4]    (* length of data in bytes *)
+              (*1)   Creation[4]      (* Seconds since 1979 file last chgd *)
+                     fileName(17)     (* name of file, not vol or dir *)
+                     sendingProg(15)  (* name of program on send side *)
+                     SLO[1]           (* 01H for Overdrive supported *)
+                     RESYNC[1]        (* 01H for file Restart supported *)
+                     MACFLOW[1]       (* 01H for Macintosh flow supported *)
+                     fill[85]         (* zeroed *)
+                     CRC              (* error detect/correction code *)
+
+    *1 - Creation is a long integer number of seconds since January 1, 1979.
+
+     SEAlinkACK    = ACK              (* indicator data block received ok *)
+                     blockNumber[1]   (* sequence, i'=mod( i+1, 256 ) *)
+                     blockCompl[1]    (* one's complement of blockNumber *)
+
+     SEAlinkNAK    = NAK              (* indicator block not received ok *)
+                     blockNumber[1]   (* sequence, i'=mod( i+1, 256 ) *)
+                     blockCompl[1]    (* one's complement of blockNumber *)
+
+     ReSyncBlock   = SYN              (* File Restart Position *)
+                (*1) RestartBlock<20> (* ASCII decimal file block # *)
+                     ETX              (* End of block number text *)
+                     CRC(rev order)   (* error detection code *)
+
+     *1 - RestartBlock is a text ASCII version of the decimal block number
+          in the file desired.  Note:  The first block of the file is block 1.
+
+
+    Definitions of Single byte Character values used in protocol:
+
+      ACK          = 06H              (* acknowledge data received ok *)
+      NAK          = 15H              (* negative ACK & poll 1st block *)
+      SOH          = 01H              (* start of header, begins block *)
+      SYN          = 16H              (* start of TeLink file info blk *)
+      EOT          = 04H              (* end of xfer, after last block *)
+      ETX          = 03H              (* end of RESYNC request data field*)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            18
+    Block Verification calculated values used by this protocol:
+
+      CRC          = crc[2]           (* CCITT Cyclic Redundancy Check *)
+
+      Checksum     = checksum[1]      (* low 8 bits of sum of data bytes
+                                         using unsigned 8 bit arithmetic *)
+
+    Calculating Checksum
+    --------------------
+
+    For blocks which use a checksum to do error detection, the checksum is
+    calculated by initializing an accumulator to zero and doing successive
+    addition of each character in the data field.  Carry is discarded on
+    each addition.  The resulting 8 bit value is the checksum.
+
+    Calculating CRC
+    ---------------
+
+    For blocks which use CRC to do error detection, the CRC is calculated
+    using the CCITT V.41 generator polynomial.  An accumulator is initialized
+    to zero, and then each character of the data field is processed by the
+    CRC generator polynomial.  This process can be quite complex to explain,
+    but is not so complex in practice.  The following CRC routine is
+    given here as an aid to understanding the CRC generation process.
+
+    8086 assembler routine to implement CCITT V.41 CRC algorithm
+    ;---------------------------------------------------------------+
+    ;       CRCUPD - Update CRC value from character in AL          |
+    ;                                                               |
+    ;  CRC is calculated using the CCITT V.41 generator polynomial. |
+    ;    That polynomial is: X^16 + X^12 + X^5 + 1 (X^0)            |
+    ;                                                               |
+    ;  As an aid to understanding, remember that XOR is bitwise     |
+    ;    addition without carry.                                    |
+    ;---------------------------------------------------------------+
+    CRCVAL  DW      0                   ;16 bit CRC accumulator
+    ;
+    CRCUPD: PUSH    AX                  ;All registers preserved
+            PUSH    CX
+            PUSH    DX
+            MOV     DX,[CRCVAL]
+            XOR     DH,AL               ;init X^16 term
+            XOR     DL,DL
+            MOV     CX,8
+    CRCUP1: SHL     DX,1
+            JNC     CRCUP2
+            XOR     DX,1021h            ;X^12 + X^5 + 1
+    CRCUP2: LOOP    CRCUP1
+            XOR     DH,BYTE PTR[CRCVAL] ;finish X^16 term
+            MOV     [CRCVAL],DX         ;update CRC accumulator
+            POP     DX
+            POP     CX
+            POP     AX
+            RET
+
+
+
+
+
+
+
+
+
+
+
+                                                                            19
+ 2. Data Link Layer Protocol : XMODEM/TeLink/SEAlink Finite State Machines
+
+    The protocol is receiver driven, the receiver polling the sender for
+    each block.  If the receiver polls for the first block using a "C"
+    (43H) as  the poll character, it would prefer to have the CRC-CCITT V.41
+    polynomial remainder error detection code at the end of each block as
+    opposed to a one byte unsigned checksum.  The sender will respond to
+    the "C" poll if it can  comply. If the sender chooses checksum as
+    opposed to CRC, it waits for the receiver to poll with  NAK (15H).
+    Should the checksum method be preferable to the receiver, it polls
+    with NAK rather than "C".
+
+    The sender returns an EOT instead of a data block when no data remain.
+
+    With this extended implementation, the sender and the receiver may send
+    blocks or ACK/NAK responses while there is data being received, once the
+    SEAlink protocol has been negotiated.  This full duplex operation allows
+    the throughput gains of a sliding window protocol.  When SEAlink is not
+    set the window size of 1 prohibits data being sent at the same time and
+    restores the attributes of a standard XMODEM protocol.
+
+    ------------------
+    In this extended protocol, the FTS-0001 single state table
+    "XMODEM Sender" is replaced by two state tables.
+
+    The top level table is equivalent to the FTS-0001 XMODEM Sender table.
+    It in turn calls the new state table named "Transmitter ACK/NAK Check"
+    which implements the full duplex adaptive SEAlink/XMODEM dynamic switching
+    along with the Overdrive and file Restart sending features of the extended
+    protocol.
+
+    -----------------
+    In this extended protocol, the FTS-0001 single state table
+    "XMODEM Receiver" is replaced by three state tables.
+
+    The top level table is equivalent to the FTS-0001 XMODEM Receiver table.
+    It in turn calls the two new state tables named "Send NAK" and "Send ACK"
+    which implement the full duplex adaptive SEAlink/TeLink/XMODEM dynamic
+    switching along with the Overdrive and file Restart receiving features of
+    the extended protocol.
+
+
+    Caution!!!!
+    -----------
+    Many current implementations keep file block numbers as 16 bit numbers.
+    This limits the max file size to either 4 megabytes (if number is signed)
+    or 8 megabytes (if number is unsigned).  To handle files up to the maximum
+    size DOS allows (4 gigabytes) at least 25 bits plus sign are required for
+    these numbers.  Good practice is to make file block numbers 32 bit values.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            20
+    XMODEM/TeLink/SEAlink - Sender
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XS0 | XmtStart |  Normal Entry Point     | reset SEAlink flag,     | XS1 |
+    |     |          |  for file send          |   SendBLK=1, ACKST=0,   |     |
+    |     |          |                         |   ACKBLK= -1, WINDOW=1, |     |
+    |     |          |                         |   ACKs Rcvd=0,          |     |
+    |     |          |                         |   NumNAK=0,             |     |
+    |     |          |                         |   T1=30 seconds,        |     |
+    |     |          |                    (*1) |   Build SEAlink hdr blk |     |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XS0T| XmTeStrt |  Alternate entry from   | reset SEAlink flag,     | XS1 |
+    |     |          |  Batch Send if TeLink   |   SendBLK=1, ACKST=0,   |     |
+    |     |          |  mode send required     |   ACKBLK= -1, WINDOW=1, |     |
+    |     |          |                         |   ACKs Rcvd=0,          |     |
+    |     |          |                         |   NumNAK=0,             |     |
+    |     |          |                         |   T1=30 seconds,        |     |
+    |     |          |                         |   Build TeLink hdr blk  |     |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XS1 | CheckACK |                         | (Check ACK/NAK AC0)     | XS2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XS2 | SendBlk  |1| NumNAK > 4 &          | If header = SEAlink     | XS0T|
+    |     |   (*2)   | |   SendBLK = 0         +-------------------------+-----+
+    |     |          | |                       | If header = TeLink,     | XS2 |
+    |     |          | |                       |   NumNAK = 0,           |     |
+    |     |          | |                       |   Incr ACKBLK,          |     |
+    |     |          | |                       |   Incr SendBLK          |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| NumNAK > 10           | report too many errors  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Timer T1 expired      | report fatal timeout    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| SendBLK > Last Blk+1  |                         | XS3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| SendBLK >ACKBLK+Window|                         | XS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |6| SendBLK = Last Blk+1  | Send EOT, Incr SendBLK, | XS1 |
+    |     |          | |                       |   Set T1 to 30 seconds  |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |7| SLO set & SEAlink set | Send SendBLK, (*3)      | XS1 |
+    |     |          | |                       |   ACKBLK = SendBLK,     |     |
+    |     |          | |                       |   Incr SendBLK,         |     |
+    |     |          | |                       |   Set T1 to 60 seconds  |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |8| SLO reset or          | Send SendBLK, (*3)      | XS1 |
+    |     |          | |     SEAlink reset     |   Incr SendBLK,         |     |
+    |     |          | |                       |   Set T1 to 30 seconds  |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XS3 | WaitEnd  |1| ACKBLK < Last Blk+1   |                         | XS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACKBLK = Last Blk+1   | report send success     | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - Build SEAlink Header block with RESYNC set.  Set SLO if line speed >
+         2400 bps, reset SLO otherwise.
+
+    *2 - State (XS2.1) allows the receiver to refuse one or both header blocks.
+
+    *3 - If SendBLK = 0, then send the SEAlink (or TeLink) header block.
+         If SendBLK > 0, send the corresponding 128 byte file data block where
+                         block #1 begins with the first byte of the file.
+
+                                                                            21
+    XMODEM/TeLink/SEAlink - Transmitter ACK/NAK Check
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC0 | ChkRcvd  |1| No character waiting  |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Character waiting     | Read character to CHR   | AC1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC1 | SLCheck  |1| ACKST > 2             |                         | AC2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACKST <=2             |                         | AC6 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC2 | SLVerify |1| ARBLK8 = 1's comp(CHR)| ARBLK = SendBLK -       | AC3 |
+    |     |          | |                       | ((SendBLK-ARBLK8)&0FFh) |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ARBLK8 # 1's comp(CHR)| Reset SEAlink flag,     | AC6 |
+    |     |          | |                       |   WINDOW=1,             |     |
+    |     |          | |                       |   ACKST=0               |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC3 | SLACKNAK |1| ARBLK not valid (*1)  |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACKST = 3             | Set SEALink flag,       | AC5 |
+    |     |     (*2) | |                       |   WINDOW = 6,           |     |
+    |     |          | |                       |   ACKBLK = ARBLK,       |     |
+    |     |          | |                       |   Incr ACKs Rcvd,       |     |
+    |     |          | |                       |   ACKST=0               |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| ACKST = 4             | SendBLK = ARBLK,        | AC4 |
+    |     |          | |                       |   ACKST=0               |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC4 | XMCheck  |1| NumNAK < 4            | Set SEAlink Flag,       | exit|
+    |     |          | |                       |   WINDOW = 6            |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| NumNAK >= 4           | Reset SEAlink flag,     | exit|
+    |     |          | |                       |   WINDOW = 1            |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC5 | SLOCheck |1| SLO Reset             |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACKs Rcvd < 10        |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| ACKs Rcvd >= 10       | Reset SLO               | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC6 | SL1Check |1| ACKST = 1 or 2        | ARBLK8 = CHR,           | AC6 |
+    |     |          | |                       |   ACKST = ACKST+2       |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink reset         |                         | AC7 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| ACKST = 0             |                         | AC7 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| ACKST > 2             |                         | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+                            (Continued on next page)
+
+    *1 - ARBLK is valid only if all of the following are true:
+
+         a. ARBLK >= 0
+         b. ARBLK <= SendBLK
+         c. ARBLK >  SendBLK-128
+
+    *2 - Software error if ACKST is not 3 or 4 in state AC3
+
+
+                                                                            22
+    XMODEM/TeLink/SEAlink - Transmitter ACK/NAK Check
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC7 | ACKNAK   |1| CHR = ACK             | ACKST = 1               | AC8 |
+    |     |          | |                       |   NumNAK = 0            |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| CHR = NAK or 'C'      | Set CRC/Chksm if 1st,   | AC9 |
+    |     |     (*1) | |                       |   ACKST = 2,            |     |
+    |     |          | |                       |   Incr NumNAK,          |     |
+    |     |          | |                       |   Delay 0.6 seconds     |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |     (*1) |3| CHR = SYN             | Receive RESYNC packet,  | AC10|
+    |     |          | |                       |   ACKST = 0             |     |
+    |     |     (*2) +-+-----------------------+-------------------------+-----+
+    |     |          |4| CHR = other           |                         | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC8 | XMACK    |1| SEAlink set           |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink reset         | Incr ACKBLK             | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC9 | XMNAK    |1| SEAlink set           |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink reset         | SendBLK = ACKBLK+1      | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC10| RESYNC   |1| RESYNC pkt invalid    | Send NAK                | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| RESYNC pkt valid      | Set SEAlink flag,       | exit|
+    |     |          | |                       |   WINDOW = 6,           |     |
+    |     |          | |                       |   SendBLK = RESYNC Blk#,|     |
+    |     |          | |                       |   ACKBLK = SendBLK-1,   |     |
+    |     |          | |                       |   Send ACK              |     |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - If the output is buffered in local computer memory, any characters
+         which remain in the local buffer should be purged before leaving
+         states (AC7.2) or (AC7.3) to aid in resynchronizing the link.
+
+    *2 - If the implementation is honoring MACFLOW protocol, set the flag in
+         the SEAlink header block and add the following state to (AC7):
+
+    .-----+--------+---+-----------------------+-------------------------+-----.
+    | AC7 |        |3.5| CHR = ^S (13H) &      | Delay 10 seconds or     | exit|
+    |     |        |   |   SEAlink set &       |   until ^Q (11H) rcvd   |     |
+    |     |        |   |   ACKST = 0           |                         |     |
+    `-----+--------+---+-----------------------+-------------------------+-----'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            23
+    XMODEM/TeLink/SEAlink - Receiver
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XR0 | RecInit  |                         | reset SEAlink flag,     | XR1 |
+    |     |          |                         |   reset SLO flag,       |     |
+    |     |          |                         |   reset RESYNC flag,    |     |
+    |     |          |                         |   set CRC flag,         |     |
+    |     |          |                         |   set blocknum=0,       |     |
+    |     |          |                         |   set WriteBLK=1,       |     |
+    |     |          |                         |   reset retry cnt       |     |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XR0B| BrecInit |  Alternate Entry from   | reset SEAlink flag,     | XR2 |
+    |     |          |  Batch Receive (BR4.2)  |   reset SLO flag,       |     |
+    |     |          |  or (BR4.3)             |   reset RESYNC flag,    |     |
+    |     |          |                         |   set CRC flag,         |     |
+    |     |          |                         |   set blocknum=0,       |     |
+    |     |          |                         |   set WriteBLK=1,       |     |
+    |     |          |                         |   reset retry cnt       |     |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XR1 | RecStart |                         | (Send NAK SN0)          | XR2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XR2 | WaitFirst|1| 10 retries or 1 minute| report receive failure  | exit|
+    |     |          | |   w/o valid input     |                         |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| > 3 retries or 30 secs| reset CRC flag          | XR1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| EOT received          | (Send ACK SA0),         | exit|
+    |     |          | |                       |   report no file        |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |     (*1) |4| TeLink block recd     | (Send ACK SA0),         | XR3 |
+    |     |          | |                       |   reset retry cnt       |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |     (*2) |5| SEAlink block recd    | set SEAlink,            | XR4 |
+    |     |          | |                       |   set RESYNC as         |     |
+    |     |          | |                       |   indicated by header   |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |     (*3) |6| XMODEM data block 1   | Write block to file,    | XR3 |
+    |     |          | |   received            |   Incr WriteBLK,        |     |
+    |     |          | |                       |   Incr blocknum,        |     |
+    |     |          | |                       |   (Send ACK SA0),       |     |
+    |     |          | |                       |   reset retry cnt       |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |7| bad block or 2-10 secs| incr retry count        | XR1 |
+    |     |          | |   without input       |                         |     |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+                              (Continued on next page)
+
+    *1 - A TeLink header packet has the standard XMODEM data block format except
+         that it begins with an SYN instead of an SOH character and has a block
+         number of 0.  Note: SEAdog (through version 4.51b) does not possess
+         (XR2.4) and therefore will consider a TeLink header a bad block and
+         process it according to (XR2.7) when communicating with mailers which
+         do not do SEAlink protocol.
+
+    *2 - A SEAlink header packet has the standard XMODEM data block format
+    *3   except that is has a block number of 0. The first block is an XMODEM
+         data block if its block number is not 0.
+
+
+
+
+                                                                            24
+    XMODEM/TeLink/SEAlink - Receiver (cont.)
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XR3 | WaitBlock|1| 10 retries or 1 minute| report receive failure  | exit|
+    |     |          | |   w/o expected block  |                         |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| EOT received          | reset SLO flag,         | exit|
+    |     |          | |                       |   (Send ACK SA0)        |     |
+    |     |          | |                       |   report recd ok        | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| expected data         | Decrement blocknum,     | XR3 |
+    |     |          | |   block-1 received    |   (Send ACK SA0)        |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| expected data         | Write block to file,    | XR3 |
+    |     |          | |   block received      |   Incr WriteBLK,        |     |
+    |     |          | |                       |   (Send ACK SA0),       |     |
+    |     |          | |                       |   reset retry cnt       |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| SEAlink set &         | Discard block - resync  | XR3 |
+    |     |          | |   expected block+1 to |   in progress,          |     |
+    |     |          | |   expected block+127  | Send Conditional NAK(*5)|     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |6| bad block or 2-10 secs| (Send NAK SN0),         | XR3 |
+    |     |          | |   without input       |   incr retry cnt        |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XR4 | Restart  |1| Want entire file      | (Send ACK SA0),         | XR5 |
+    |     |          | |   or RESYNC not set   | reset retry cnt         |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Want to resume an     |  WriteBLK = file restart| XR5 |
+    |     |          | |   interrupted xfer    |    block number,        |     |
+    |     |          | |   and RESYNC is set   |  blocknum=WriteBLK&0FFh,|     |
+    |     |          | |                       |    (Send NAK SN0)       |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XR5 | SetOvrdr |                         | Set SLO as indicated    | XR3 |
+    |     |          |                         |   by SEAlink header     |     |
+    `-----+----------+-------------------------+-------------------------+-----'
+    Note: The routine that receives a header/data block should do the following:
+
+    1. Report a bad block if the checksum or CRC is not correct or if the
+       physical layer encounters errors (e.g. parity, framing, etc.) regardless
+       of checksum or CRC.  Report a bad block if the length of the block is
+       less than expected (Use a 5 second timeout to detect short blocks).
+    2. If the block's sequence number does not match the complement, then
+       report a bad block if not in SEAlink. If in SEAlink mode don't report
+       this as a bad block, just restart the block search looking for SOH.
+       Check for SOH, BLK, ~BLK characters in a "sliding" fashion and keep
+       cycling until a valid start of block (or timeout) is detected before
+       assembling the remainder of the block.  This procedure makes a resync
+       occur much more rapidly, and with far fewer errors reported.
+    3. If the sequence number and block are good but not the expected number,
+       report state (XR3.3) if previous block.  If not in SEAlink, abort on any
+       other out of sequence block.  If in SEAlink, report back state (XR3.5)
+       or (XR3.6) as indicated by the out of sequence received block number.
+    4. If an EOT is received on a data block prior to the filesize specified
+       in the SEAlink or TeLink header block, a NAK should be issued to ensure
+       that spurious data did not cause a premature EOF.  A NAK should also
+       be issued for the first EOT received in an Xmodem transfer when the
+       final file size is not known.  A second EOT without intervening data
+       would ensure that the file really has been sent, and should be ACK'd.
+    5. If you last sent an ACK, then send a NAK here.  If you last sent a NAK
+       then only NAK evry 32 blocks after the first NAK.  This allows buffer
+       drain in overdrive.  Use (Send NAK SN0) to send the NAK.
+                                                                            25
+    XMODEM/TeLink/SEAlink - Send NAK
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SN0 | ClearLine|1| RESYNC flag set       | Send RESYNC packet      | SN3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink flag set      |                         | SN1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| > 30 sec contin data  | report failure          | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| character waiting     | eat character           | SN0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| clear line            |                         | SN1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SN1 | SendNAK  |1| CRC flag set          | Send "C"                | SN2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| CRC flag reset        | send NAK                | SN2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SN2 | SEAlink  |1| SEAlink flag reset    |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink flag set      | send blocknum, ~blocknum| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SN3 | AckResync|1| Rcv ACK               |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv NAK               | Resend RESYNC packet    | SN3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv Other Char        | eat character           | SN3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| No char for 10 secs   | Resend RESYNC packet    | SN3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| 30 seconds in SN3     |                         | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    Note: RESYNC packet should send WriteBLK as its desired block number.
+
+
+    XMODEM/TeLink/SEAlink - Send ACK
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SA0 | ClearLine|1| SLO flag set          |                         | SA3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink flag set      |                         | SA1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| > 30 sec contin data  | report failure          | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| character waiting     | eat character           | SA0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| No char waiting       |                         | SA1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SA1 | SendACK  |                         | Send ACK                | SA2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SA2 | SEAlink  |1| SEAlink flag reset    |                         | SA3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink flag set      | send blocknum, ~blocknum| SA3 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SA3 | IncBlk   |                         | Incr blocknum           | exit|
+    `-----+----------+-------------------------+-------------------------+-----'
+
+
+
+
+                                                                            26
+ 3. Data Link Layer Protocol : MODEM7 Filename Finite State Machines
+    (There is no change to the MODEM7 state tables from FTS-0001).
+
+    MODEM7 Filename Sender
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MS0 | WaitNak  |1| 20 retries or 1 minute| filename send failed    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| NAK received          | send ACK & 1st ch of fn | MS1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MS1 | WaitChAck|1| ACK rcd, fname done   | send SUB = 1AH          | MS2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACK rcd, fname ~done  | send next ch of fname   | MS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| other char or 1 sec   | send "u", incr retry cnt| MS0 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MS2 | WaitCksm |1| cksum recd and ok     | send ACK, report fn ok  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| cksum recd but bad    | send "u", incr retry cnt| MS0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| no cksum in 1 sec     | send "u", incr retry cnt| MS0 |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+
+    MODEM7 Filename Receiver
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MR0 | SendNak  |1| 20 tries or 1 minute  | report filename failure | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2|                       | send NAK, incr try cnt  | MR1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MR1 | WaitAck  |1| rcd ACK               |                         | MR2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| rcd EOT               | report no files remain  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| 5 secs & no ACK/EOT   |                         | MR0 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MR2 | WaitChar |1| recd EOT (can happen?)| report no files remain  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| recd SUB              | send checksum byte      | MR3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| recd "u"              |                         | MR0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| recd char of name     | send ACK                | MR2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| no char in 1 second   |                         | MR0 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MR3 | WaitOkCk |1| recd ACK within 1 sec | report recd filename ok | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| recd "u" or other char|                         | MR0 |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    SUB  is the ASCII character ^Z or 1AH.  The checksum is the unsigned low
+    order eight bits of the sum of the characters in the transferred filename
+    including the SUB.
+
+    Although 1 second timeouts are used successfully by Fido and SEAdog, some
+    fear that this is too small a value for some satellite and packet networks.
+
+                                                                            27
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0008.html b/html/ftsc/fts-0008.html new file mode 100755 index 00000000..f0fdccf8 --- /dev/null +++ b/html/ftsc/fts-0008.html @@ -0,0 +1,485 @@ + + +Bark file-request protocol extension. + + + + +
+Document: FTS-0008
+Version:  003
+Date:     15-Oct-1990
+Updates:  FTS-0001
+
+
+
+                  An Enhanced FidoNet(r) Technical Standard
+                 Extending FTS-0001 to include Bark requests
+
+                            October 15, 1990
+
+
+
+
+Status of this document:
+
+    This document specifies an optional standard for the FidoNet community.
+    Implementation of the protocols defined in this document is not mandatory,
+    but all implementations of these protocols are expected to adhere to this
+    standard.  Distribution of this document is subject to the limitations of
+    the copyright notice displayed below.
+
+
+    Copyright 1989-90 by Philip L. Becker.  Portions of this document are
+    copyright 1986-90 by Randy Bush and are incorporated with his consent.
+    All rights reserved.  A right to distribute only without modification and
+    only at no charge is granted.  Under no circumstances is this document to
+    be reproduced or distributed as part of or packaged with any product or
+    other sales transaction for which any fee is charged.  Any and all other
+    reproduction or excerpting requires the explicit written consent of the
+    copyright holders.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A. Introduction
+
+ 1. This Document
+
+    This document describes the standard for "Bark" type FidoNet file
+    request operation.  Bark file requests are an extension to the basic
+    FTS-0001 mail session, and this document presents these requests as a
+    modification to that document.
+
+ 2. What are File Requests?
+
+    File Requests are a way of requesting that a specific file be sent during
+    a FidoNet mail session.  This has many advantages over simply logging on to
+    a BBS and downloading a file:
+
+       o  You need not be a validated user
+
+       o  You don't have to spend time searching for the file on the BBS
+
+       o  You can schedule the file request to take place at any time without
+          your being near your computer.
+
+    There are two commonly used types of file requests on FidoNet today, WaZOO
+    and Bark requests.  WaZOO requests are used by Opus and BinkleyTerm, and
+    are not documented here.  See the document FTS-0006 by V. Perriello for a
+    description of these.   Bark requests were the first file request extension
+    to the FTS-0001 protocol, and are supported (at least partially) by many
+    mailers, including SEAdog, Dutchie, BinkleyTerm, and to a certain extent
+    Opus.  This document describes how to implement Bark-type file requests.
+
+
+ B. Terms Used in this Document
+
+ 1. The diagrams and notations used in this document are the same as those used
+    in the FTS-0001 document.  Please see FTS-0001 for a description of these.
+    This document should be considered as an extension to the FTS-0001 session
+    layer protocol, and you will require FTS-0001 in addition to this document
+    to fully understand what is presented here.
+  
+    In addition to the data description language described in FTS-0001 section
+    A.4, one extra terminal used in this notation:
+  
+    (* terminals *)
+    someName - String of up to max chars, NOT null terminated
+ C. Performing File Requests
+
+ 1. Introduction
+
+    A Bark request consists of transmitting a special Bark Request packet which
+    contains a filename, a date (used for update requests), and optionally a
+    password.  The system receiving the request then decides if it can send the
+    requested file or not, and if it can does so using the same protocol used
+    to send attached files.  Bark request handling is always controlled by the
+    answering system, and consists of two phases.  In phase one, the receiving
+    system asks the calling system to honor requests it may have to ask for
+    files from the caller.  In phase two, the receiving system allows the
+    calling system to request files from it.
+
+    Update file requests are the same as normal file requests, with one
+    exception.  If the date in the Bark Request packet (described below) is
+    greater than or equal to the date of the actual file requested, the file
+    will not be sent.  The requestor should set the date to the date of the
+    the actual file on its own end if an update request is desired.
+
+
+ D. The Bark Request Packet
+
+ 1. Data Link Layer Data Definition.
+ 
+    The Bark Request packet is a variable-sized packet containing a header, a
+    filename, a date (which is used only for update requests - in a normal file
+    request it's 0) and an optional password. When receiving a Bark Request
+    packet, the ETX may be used to determine the end of the data portion. Note
+    that the CRC is sent in the reverse byte order of a normal CRC XMODEM data
+    block (see FTS-0001 section G.1).
+
+    Note: some systems will send a password in the data block even if none is
+    needed.  Incoming passwords should be ignored unless the other system is
+    trying to request a passworded file.
+
+  
+
+                          Bark File Request Packet
+      Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       ACK - Start of Bark Request - 06H       |
+              +-----------------------------------------------+
+        1   1 |     Filename - Packed DOS file format         |
+              +-----------------------------------------------+
+        n   n |              SPACE - 20H                      |
+              +-----------------------------------------------+
+        n   n |              Date (0 if not Update Request)   |
+              +-----------------------------------------------+
+        n   n |      SPACE - 20H  (only if pswd follows)      |
+              +-----------------------------------------------+
+        n   n |         Password (optional)                   |
+              +-----------------------------------------------+
+        n   n |       ETX -  End of RESYNC packet  - 03H      |
+              +-----------------------------------------------+
+        n   n |     (*1)     CRC  low order byte              |
+              +-----------------------------------------------+
+        n   n |     (*1)     CRC high order byte              |
+              `-----------------------------------------------'
+
+              *1 - CRC does not include the ACK or ETX and is
+                   in the reverse byte order from the CRC in a
+                   normal XMODEM data packet.
+ 2. Data Description Notation of Bark Request Packet
+
+    DataBlock (no password) = ACK
+                              Filename<12>
+                              Space
+                              Date<11>
+                              ETX
+                              CRC
+  
+    DataBlock (with password) = ACK
+                                Filename<12>
+                                Space
+                                Date<11>
+                                Space
+                                Password<6|8>
+                                ETX
+                                CRC
+  
+    ACK   = 06H       (* Header for file request block *)
+    Space = 20H       (* Space character *)
+    ETX   = 03H       (* End of block *)
+  
+    Filename          (* Name of file requested *)
+    Date              (* ASCII string; the number of seconds
+                         since midnight, January 1, 1970 *)
+    Password          (* The password needed to request this
+                         file, if any.  Maximum length is 6 for
+                         BinkleyTerm and Opus, 8 for SEAdog
+                         and Dutchie. *)
+  
+    CRC = crc[2]      (* CCITT Cyclic Redundancy Check.  The
+                         same algorithm as used for XModem
+                         CRCs.  The CRC is calculated on
+                         all data in the block between but
+                         not including the ACK and the ETX *)
+ E. Session Layer Protocol:
+
+    This section describes the modified FTS-0001 session layer protocol.  This
+    is the only area of FTS-0001 which is modified to implement Bark style file
+    requests.  File Requests are performed at the end of the normal FidoNet
+    mail session, after any mail pickup is performed.
+
+    The diagrams below desribe the session level protocol with Bark file
+    requests implemented.  The state tables have been broken into subroutines
+    but the FTS-0001 portion is not functionally changed.  FTS-0001 sender
+    states S4 through S7 are now table "Send Mail SM0".  FTS-0001 receiver
+    states R3 through R6 are now table "Receive Mail RM0".  They are not
+    functionally changed in any way from FTS-0001, they are just broken out
+    to allow them to be used as subroutines.  Finally Sender states S0 through
+    S3 are unchanged, as are Receiver states R0 through R2.
+
+    The remaining FTS-0001 states are enhanced to implement the Bark file
+    request protocol. In addition, the subroutine state tables "Send Bark SB0"
+    and "Receive Bark RB0" have been added to handle the actual file requests.
+ 
+    The following diagrams fully replace the Session Layer protocol state
+    tables in FTS-0001.  No other changes to FTS-0001 are required to implement
+    the Bark File request feature.
+    Sender  (Top level)
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | S0  | SendInit |                         | dial modem              | S1  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S1  | WaitCxD  |1| carrier detected      | delay 1-5 seconds       | S2  |
+    |     |  (*1)    | |                       | Set SLO if > 2400bps,   |     |
+    |     |          | |                       | Reset SLO if <= 2400bps |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| busy, etc.            | report no connection    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| voice                 | report no carrier       | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| carrier not detected  | report no connection    | exit|
+    |     |          | | within 60 seconds     |                         |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S2  | WhackCRs |1| over 30 seconds       | report no response  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ?? s received     | delay 1 sec             | S3  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| s not received    | send    | S2  |
+    |     |          | |                       |   delay ??? secs        |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S3  | WaitClear|1| no input for 0.5 secs | send TSYNCH = AEH       | S4  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| over 60 seconds       | hang up, report garbage | exit|
+    |     |          | | and line not clear    |                         |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S4  | SendMail |                         | (Send Mail SM0)         | S5  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S5  | TryPickup|1| Rcv TSYNC             | (Receive Mail RM0)      | S5  |
+    |     |   (*2)   +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv SYN               | (Receive Bark Req RB0)  | S5  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv ENQ               | (Do Bark Requests SB0)  | S5  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| Rcv 'C' or NAK        | Send EOT                | S5  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| Rcv Other Char        | Send SUB                | S5  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |6| No Data for 45 secs   | Hang Up                 | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - This state is shown for the extended SEAlink protocol.  Omit the
+         set/reset SLO actions if adding Bark to a strict FTS-0001 protocol
+         implementation, or if not implementing overdrive in SEAdog.
+   
+    *2 - To refuse to pickup mail (S5.1) may send a CAN and stay in (S5).
+
+    Note: Although the above shows the sender emitting only one TSYNCH, it is
+    recommended that a timeout of 5-20 seconds should initiate another TSYNCH.
+    The receiver should tolerate multiple TSYNCHs.
+    Receiver (Top Level)
+
+    The  receiving FSM is given  an external timer, the expiration of  which
+    will cause termination with a result of 'no calls' (R0.2).
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R0  | WaitCxD  |1| carrier detected      |                         | R1  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| external timer expires| report no calls         | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R1  | WaitBaud |1| baud rate detected    | send signon with s  | R2  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| no detect in ?? secs  | hang up, report no baud | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R2  | WaitTsync|1| TSYNCH received       | ignore input not TSYNCH | R3  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| 60 seconds timeout    | hang up, report not Fido| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R3  | RecMail  |                         | (Receive Mail RM0)      | R4  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R4  | AllowPkup|1| Have pickup for sender| Send Tsync,             | R5  |
+    |     |          | |                       |   Set T1=1 sec          |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| No pickup for sender  |                         | R6  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R5  | WtPickup |1| Rcv NAK or 'C'        | (Send Mail SM0)         | R6  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv SUB               | Send Tsync,             | R5  |
+    |     |          | |                       |   Set T1=1 sec          |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv CAN               | Report Mail Refused     | R6  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| T1 expired            | Send Tsync,             | R5  |
+    |     |          | |                       |   Set T1=1 sec          |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| 45 secs in R5         | Hang Up, report error   | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R6  | AskBark  |1| Wish to make requests | Send SYN                | R7  |
+    |     |   (*1)   +-+-----------------------+-------------------------+-----+
+    |     |          |2| No requests to make   |                         | R8  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R7  | DoRequest|1| Rcv CAN               | Report Requests Refused | R8  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv ENQ               | (Send Bark SB0)         | R8  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv SUB               | Send SYN                | R7  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| Rcv NAK or 'C'        | Send EOT                | R6  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| Rcv Other             | eat character           | R7  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |6| 5 sec, no input       | Send SYN                | R7  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |7| 45 secs in R7         |                         | R8  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R8  | WtPickup |1| Allow File Request    | (Receive Bark RB0),     | exit|
+    |     |          | |                       |   Hang Up               |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Disallow Requests     | Hang Up                 | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    *1 - Some implementations always do (R6.1) even if they have no requests.
+    Sender - Send Mail
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | SM0 | SendMail |                         | (XMODEM send packet XS0)| SM1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SM1 | CheckMail|1| XMODEM successful     | (Fido registers success)| SM2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| XMODEM fail or timeout| hang up, report mail bad| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SM2 | SendFiles|                         | (BATCH send files BS0)  | SM3 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SM3 | CheckFile|1| BATCH send successful | report success          | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| BATCH send failed     | hang up, rept files fail| exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+
+
+    Sender - Send Bark
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SB0 | SendBark |1| File to request       | Build Bark Request Pkt, | SB1 |
+    |     |          | |                       |   Set tries = 0         |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| No more files to req  | Send ETB                | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SB1 | AskFile  |                         | Send Bark Packet        | SB2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SB2 | RcvFile  |1| Rcv ACK               | (Batch Receive BR0)     | SB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Tries > 5             | Send ETB, report failed | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv Other             | Purge input, Incr tries | SB1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| 10 sec w/o ACK        | Incr tries              | SB1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SB3 | NxtFile  |1| Rcv ENQ               |                         | SB0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv Other             | Purge Input             | SB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| 5 sec, no input       | Send SUB                | SB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| 45 sec in SB3         | Hang up, report error   | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    Sender & Receiver - Receive Mail
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | RM0 | RecMail  |                         | (XMODEM rec packet XR0) | RM1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RM1 | XRecEnd  |1| XMODEM successful     | delay 1 second          | RM2 |
+    |     |          | |                       |   flush input           |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| XMODEM failed         | hang up, rept mail fail | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RM2 | RecFiles |                         | (BATCH rec files BR0)   | RM3 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RM3 | ChkFiles |1| BATCH recv successful | delay 2 secs, rprt good | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| BATCH recv failed     | hang up, report bad file| exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+
+    Sender & Receiver - Receive Bark
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB0 | HonorReq |1| Ok to honor request   | Purge Input, Send ENQ,  | RB1 |
+    |     |          | |                       |   Set T1 = 2 seconds    |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Don't wish to honor   | Send CAN                | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB1 | WaitBark |1| Got ACK               | Rcv Bark Packet (*1)    | RB2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Got ETB               | Report done             | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Got ENQ               | Send ETB                | RB0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| T1 expired            | Purge Input, Send ENQ,  | RB1 |
+    |     |          | |                       |   Set T1 = 2 seconds    |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| 20 seconds in RB1     | Hang Up, Report error   | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB2 | AckBark  |1| Bark Pkt Rcvd Good    | Send ACK                | RB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Bark Pkt Rcv Error    | Send NAK                | RB1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB3 | WaitStrt |1| Got 'C' or NAK        |                         | RB4 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| No data for 3 seconds | Send ACK                | RB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| 15 seconds in RB3     | Hang Up, Report Error   | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB4 | SendFile |1| Can snd requested file| (Batch Send File BS0)   | RB0 |
+    |     |   (*2)   +-+-----------------------+-------------------------+-----+
+    |     |          |2| Can't send file       | Send EOT                | RB0 |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    *1 - If SUB (16H) received before ETX go to RB0 to resync bark receive
+
+    *2 - While deciding if file exists, and if the password allows it to be
+         sent etc., a NUL may be sent to buy 20 seconds more on the timeout
+         on the other end if it is using the SEAlink extended FTS-0001
+         specification protocol.  Sending a NUL is harmless for a strict
+         FTS-0001 session, but will not buy more time.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0009.html b/html/ftsc/fts-0009.html new file mode 100755 index 00000000..5bba0b50 --- /dev/null +++ b/html/ftsc/fts-0009.html @@ -0,0 +1,104 @@ + + +Message identification and reply linkage. + + + + +
+Document: FTS-0009
+Version:  001
+Date:     17-Dec-91
+
+
+
+
+                               MSGID / REPLY
+                  A standard for unique message identifiers
+                          and reply chain linkage
+
+                            17 December, 1991
+
+                                 jim nutt
+                             1:114/30@fidonet
+
+
+
+
+Status of this document:
+
+     This FTS (FidoNet(r) Technical Standard) specifies an optional
+     standard for the FidoNet community.  Implementation of the
+     protocols defined in this document is not mandatory,  but all
+     implementations of these protocols are expected to adhere to this
+     standard.  Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+MSGID
+
+     A MSGID line consists of the string "^AMSGID:" (where ^A is a
+     control-A (hex 01) and the double-quotes are not part of the
+     string),  followed by a space,  the address of the originating
+     system,  and a serial number unique to that message on the
+     originating system,  i.e.:
+
+          ^AMSGID: origaddr serialno
+
+     The originating address should be specified in a form that
+     constitutes a valid return address for the originating network.   
+     If the originating address is enclosed in double-quotes,  the
+     entire string between the beginning and ending double-quotes is 
+     considered to be the orginating address.  A double-quote character
+     within a quoted address is represented by by two consecutive
+     double-quote characters.  The serial number may be any eight
+     character hexadecimal number,  as long as it is unique - no two
+     messages from a given system may have the same serial number
+     within a three years.  The manner in which this serial number is
+     generated is left to the implementor.
+
+
+REPLY
+
+     A REPLY line consists of the string "^AREPLY:" (where ^A is a
+     control-A (hex 01) and the double-quotes are not part of the
+     string),  followed by a space, and the origaddr and serialno
+     fields of the MSGID line of the message to which this message is a
+     reply,  i.e.:
+
+        ^AREPLY: origaddr serialno
+
+     The origaddr and serialno fields must be identical to the
+     corresponding fields in the MSGID of the message to which this
+     message is a reply.  A REPLY line is never generated in a 
+     message that is a reply to a message that does not contain a
+     MSGID line.
+
+
+GENERAL
+
+     MSGID and REPLY lines should be placed before the text body of the
+     message in which they appear.
+
+     Finally,  a MSGID is generated only at the time of message
+     creation.  An existing MSGID and/or REPLY should never be stripped
+     from a message passing through an intermediate system.  No system
+     should ever add an MSGID and/or REPLY to,  or modify an existing
+     MSGID / REPLY contained in,  a message not originating on that
+     system.
+ 
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-4001.html b/html/ftsc/fts-4001.html new file mode 100755 index 00000000..0bc73190 --- /dev/null +++ b/html/ftsc/fts-4001.html @@ -0,0 +1,192 @@ + + +Addessing Control Paragraphs. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FTS-4001
+Revision:       1
+Title:          ADDRESSING CONTROL PARAGRAPHS
+Author(s):      FTSC
+
+Revision Date:  1 October 2000
+Expiry Date:    1 October 2002
+----------------------------------------------------------------------
+Contents:
+                1. Credits
+                2. General
+                3. FMPT
+                4. TOPT
+                5. INTL
+----------------------------------------------------------------------
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standard (FTS).
+
+  This document specifies a Fidonet standard for the Fidonet
+  community.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+1. Credits
+----------
+
+  This document is based on the work of Randy Bush and many others.
+
+
+2. General
+----------
+
+  The general control paragraph format is specified in separate FTSC
+  documents.
+
+  The addressing control paragraphs specified in this document are
+  normally only used in netmail messages and not in echomail messages.
+
+  While it would be technically correct to use them also in echomail,
+  it is known that certain programs will misbehave if they are present
+  there. It is therefore recommended that they should not be used in
+  echomail at the present time.
+
+  If a program processing messages detects these control paragraphs in
+  an echomail message it is recommended that they are disregarded and
+  deleted from any copies of that message exported to other systems.
+
+  Addressing of and address resolution for echomail messages should
+  instead be done with the help of packet and message header
+  information. See separate FTSC documents.
+
+  To determine the address of the original sender of an echomail
+  message, the information in the Origin line should be used. See
+  separate FTSC documents.
+
+
+3. FMPT
+-------
+
+  The FMPT control paragraph shall be used to give information about
+  the point number of the original sender of a message if that point
+  number is not 0. If the point number of the original sender of a
+  message is 0 that message should not contain any FMPT control
+  paragraph.
+
+  The format of a FMPT control paragraph shall be:
+
+    <SOH>"FMPT <point number>"<CR>
+
+  where <point number> is the ASCII representation of the point number
+  of the sender. The point number shall be an unsigned integer in the
+  range 1-65535.
+
+  E.g. a message from point number 1 of a certain node shall contain
+  the following FMPT control paragraph
+
+    <SOH>"FMPT 1"<CR>
+
+  Note that the format of a FMPT control paragraph deviates from the
+  general format specified in separate FTSC documents in that it does
+  not contain any colon after the control tag.
+
+
+4. TOPT
+-------
+
+  The TOPT control paragraph shall be used to give information about
+  the point number of the ultimate addressee of a message if that
+  point number is not 0. If the point number of the ultimate addressee
+  of a message is 0 that message should not contain any TOPT control
+  paragraph.
+
+  The format of a TOPT control paragraph shall be:
+
+    <SOH>"TOPT "<point number><CR>
+
+  where <point number> is the ASCII representation of the point number
+  of the addressee. The point number shall be an unsigned integer in
+  the range 1-65535.
+
+  E.g. a message to point number 1 of a certain node shall contain the
+  following TOPT control paragraph
+
+    <SOH>"TOPT 1"<CR>
+
+  Note that the format of a TOPT control paragraph deviates from the
+  general format specified in separate FTSC documents in that it does
+  not contain any colon after the control tag.
+
+
+5. INTL
+-------
+
+  The INTL control paragraph shall be used to give information about
+  the zone numbers of the original sender and the ultimate addressee
+  of a message.
+
+  The format of an INTL control paragraph shall be:
+
+    <SOH>"INTL "<destination address>" "<origin address><CR>
+
+  where <destination address> shall be the representation of the
+  address of ultimate destination and <origin address> is the
+  representation of the address of the original sender of the message
+  in question. These addresses shall be given on the form
+  <zone>:<net>/<node> where <zone> is the ASCII representation of the
+  zone number, <net> is the ASCII representation of the net number and
+  <node> is the ASCII representation of the node number. Any point
+  number information shall be given in FMPT and TOPT control
+  paragraphs.
+
+  E.g. a message from address 1:123/4.5 to 2:345/6.7 shall contain the
+  following INTL control paragraph
+
+    <SOH>"INTL 2:345/6 1:123/4"<CR>
+
+  Note that the format of an INTL control paragraph deviates from the
+  general format specified in separate FTSC documents in that it does
+  not contain any colon after the control tag.
+
+  INTL control paragraphs are also often used even when both the
+  originating and the destination systems are in the same zone. This
+  gives both the originating system and the destination system as well
+  as any intermediate routing systems unambiguous zone information
+  even in a situation where one system may be active in a number of
+  different (possibly non-FidoNet) zones.
+
+  Although it is known that some programs may route messages
+  incorrectly if the INTL control paragraph is present in messages
+  where both the originating and the destination systems are in the
+  same zone, it is recommended that the INTL control paragraph is
+  always inserted into netmail messages in packet files.
+
+
+
+A. History
+----------
+
+   Rev.1, 20001001: Initial Release.
+                    Principal author Goran Eriksson.
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/ftscprod.html b/html/ftsc/ftscprod.html new file mode 100755 index 00000000..09161b20 --- /dev/null +++ b/html/ftsc/ftscprod.html @@ -0,0 +1,311 @@ + + +FTSC Product ID List. + + + + +

FTSC Product codes 22 jan 2000

+

+0000,Fido,MS-DOS,Packer/mailer,Tom_Jennings,1:125/111
+0001,Rover,MS-DOS,Packer/mailer,Bob_Hartman,1:104/501
+0002,SEAdog,MS-DOS,Packer/mailer,Thom_Henderson,1:107/542.1
+0003,WinDog,MS-DOS,Mailer,Solar_Wind_Computing,1:115/333
+0004,Slick-150,HP-150,Packer/mailer,Jerry_Bain,????
+0005,Opus,MS-DOS,Packer/mailer,Doug_Boone,1:124/4227
+0006,Dutchie,MS-DOS,Packer/mailer,Henk_Wevers,2:500/1
+0007,WPL_Library,Amiga,Mailer,Russell_McOrmand,1:163/109
+0008,Tabby,Macintosh,Packer/mailer,Michael_Connick,1:107/412
+0009,SWMail,OS/2,Mailer,Solar_Wind_Computing,1:115/333
+000A,Wolf-68k,CPM-68k,Packer/mailer,Robert_Heller,1:321/153
+000B,QMM,QNX,Packer/mailer,Rick_Duff,1:167/201
+000C,FrontDoor,MS-DOS,Packer/mailer,Joaquim_Homrighausen,2:270/17
+000D,GOmail,MS-DOS,Packer,Scott_Green,????
+000E,FFGate,MS-DOS,Packer,Ruedi_Kneubuehler,2:301/580
+000F,FileMgr,MS-DOS,Packer,Erik_van_Emmerik,2:281/611
+0010,FIDZERCP,MS-DOS,Packer,Thorsten_Seidel,2:242/55
+0011,MailMan,MS-DOS,Packer,Ron_Bemis,1:124/1113
+0012,OOPS,MS-DOS,Packer,Tom_Kashuba,1:322/379
+0013,GS-Point,Atari_ST,Packer/mailer,Harry_Lee,1:124/4230
+0014,BGMail,????,????,Ray_Gwinn,1:265/104
+0015,ComMotion/2,OS/2,Packer/mailer,Michael_Buenter,2:301/602
+0016,OurBBS_Fidomailer,MS-DOS/Unix/Coherent,Packer/mailer,Brian_Keahl,1:133/524
+0017,FidoPcb,MS-DOS,Packer,Matjaz_Koce,2:380/100
+0018,WimpLink,Archimedes,Packer/mailer,Remco_de_Vreugd,2:283/307
+0019,BinkScan,MS-DOS,Packer,Shawn_Stoddard,1:362/101
+001A,D'Bridge,MS-DOS,Packer/mailer,Chris_Irwin,1:18/68
+001B,BinkleyTerm,MS-DOS,Mailer,Vince_Perriello,1:343/491
+001C,Yankee,MS-DOS,Packer,Randy_Edwards,????
+001D,uuGate,MS-DOS,Packer,Geoff_Watts,3:690/710
+001E,Daisy,Apple_][,Packer/mailer,Raymond_&_Ken_Lo,3:700/1
+001F,Polar_Bear,????,Packer/mailer,Kenneth_McLeod,1:101/190
+0020,The-Box,MS-DOS/Atari_ST,Packer/mailer,Jac_Kersing/Arjen_Lentz,2:283/333
+0021,STARgate/2,OS/2,Packer/mailer,Shawn_Stoddard,1:362/101
+0022,TMail,MS-DOS,Packer,Larry_Lewis,3:713/600.1701
+0023,TCOMMail,MS-DOS,Packer/mailer,Mike_Ratledge,1:372/888
+0024,GIGO,MS-DOS,Packer,Jason_Fesler,1:203/7707,,940228
+0025,RBBSMail,MS-DOS,Packer,Jan_Terpstra,2:512/10
+0026,Apple-Netmail,Apple_][,Packer/mailer,Bill_Fenner,1:129/87
+0027,Chameleon,Amiga,Mailer,Juergen_Hermann,2:241/2.12
+0028,Majik_Board,MS-DOS,Packer/mailer,Dale_Barnes,1:3601/14.20
+0029,QM,MS-DOS,Packer,George_Peace,1:270/101
+002A,Point_And_Click,Amiga,Packer,Rob_Tillotson,1:201/40.302
+002B,Aurora_Three_Bundler,MS-DOS,Packer,Oliver_McDonald,????
+002C,FourDog,MS-DOS,Packer,Shay_Walters,1:376/12
+002D,MSG-PACK,MS-DOS,Packer,Tom_Hendricks,1:261/662
+002E,AMAX,MS-DOS,Packer,Alan_Applegate,1:104/36
+002F,Domain_Communication_System,????,????,Hal_Duprie,1:101/106
+0030,LesRobot,????,Packer,Lennart_Svensonn,2:501/2
+0031,Rose,MS-DOS,Packer/mailer,Glen_Jackson,1:100/617
+0032,Paragon,Amiga,Packer/mailer,Jon_Radoff,1:322/545
+0033,BinkleyTerm/oMMM/ST,Atari_ST,Packer/mailer,Bill_Scull,1:363/112,,19951209
+0034,StarNet,Atari_ST,Mailer,Eric_Drewry,1:322/566
+0035,ZzyZx,MS-DOS,Packer,Jason_Steck,1:124/424
+0036,QEcho,MS-DOS,Packer,The_QuickBBS_Group,1:363/1701
+0037,BOOM,MS-DOS,Packer,Andrew_Farmer,1:243/1
+0038,PBBS,Amiga,Packer/mailer,Todd_Kover,1:261/1028
+0039,TrapDoor,Amiga,Mailer,Maximilian_Hantsch,2:310/6
+003A,Welmat,Amiga,Mailer,Russell_McOrmand,1:163/109
+003B,NetGate,Unix-386,Packer,David_Nugent,3:632/348
+003C,Odie,MS-DOS,Mailer,Matt_Farrenkopf,1:105/376
+003D,Quick_Gimme,CPM-80/MS-DOS,Packer/mailer,Laeeth_Isaacs,2:254/18
+003E,dbLink,MS-DOS,Packer/mailer,Chris_Irwin,1:18/68
+003F,TosScan,MS-DOS,Packer,Joaquim_Homrighausen,2:270/17
+0040,Beagle,MS-DOS,Mailer,Alexander_Holy,2:310/90
+0041,Igor,MS-DOS,Mailer,Harry_Lee,1:124/4230
+0042,TIMS,MS-DOS,Packer/mailer,Bit_Bucket_Software,1:104/501
+0043,Phoenix,MS-DOS,Packer/mailer,International_Telecommunications,1:296/5,,19930624
+0044,FrontDoor_APX,MS-DOS,Packer/mailer,Joaquim_Homrighausen,2:270/17
+0045,XRS,MS-DOS,Packer,Mike_Ratledge,1:372/888
+0046,Juliet_Mail_System,Amiga,Packer,Gregory_Kritsch,1:163/109.30
+0047,Jabberwocky,Macintosh,Packer,Eric_Larson,1:2605/620
+0048,XST,MS-DOS,Packer,Wayne_Michaels,1:380/100
+0049,MailStorm,Amiga,Packer,Russel_Miranda,1:268/106
+004A,BIX-Mail,????,Mailer,Bob_Hartman,1:104/501
+004B,IMAIL,MS-DOS,Packer,IMAIL_INC.,2:246/47
+004C,FTNGate,MS-DOS,Packer,Jason_Steck,1:104/424
+004D,RealMail,MS-DOS,Packer,Taine_Gilliam,1:372/42
+004E,Lora-CBIS,MS-DOS,Mailer,Marco_Maccaferri,2:332/402
+004F,TDCS,PDP-11,Packer/mailer,Terry_Ebdon,2:254/6
+0050,InterMail,MS-DOS,Packer/mailer,Peter_Stewart,1:369/35
+0051,RFD,MS-DOS,Packer,Doug_Belkofer,1:234/10
+0052,Yuppie!,MS-DOS,Packer,Leo_Moll,2:242/2
+0053,EMMA,MS-DOS,Packer,Johan_Zwiekhorst,2:292/100
+0054,QBoxMail,QDOS,Packer/mailer,Jan_Bredenbeek,2:283/500
+0055,Number_4,MS-DOS,Packer/mailer,Ola_Garstad,2:502/15
+0056,Number_5,MS-DOS,Packer/mailer,Ola_Garstad,2:502/15
+0057,GSBBS,MS-DOS,Packer,Michelangelo_Jones,1:260/244
+0058,Merlin,MS-DOS,Packer/mailer,Mark_Lewis,2:258/25
+0059,TPCS,MS-DOS,Packer,Mikael_Kjellstrom,2:201/211
+005A,Raid,MS-DOS,Packer,George_Peace,1:270/101
+005B,Outpost,MS-DOS,Packer/mailer,Mike_Dailor,????
+005C,Nizze,MS-DOS,Packer,Tomas_Nielsen,2:205/202
+005D,Armadillo,Macintosh,Packer,Erik_Sea,1:221/109
+005E,rfmail,Unix,Packer/mailer,Per_Lindqvist,2:201/332
+005F,Msgtoss,MS-DOS,Packer,Mike_Zakharoff,1:343/36
+0060,InfoTex,MS-DOS,Packer/mailer,Jan_Spooren,2:292/852
+0061,GEcho,MS-DOS,Packer,Gerard_van_der_Land,2:283/555,951209
+0062,CDEhost,MS-DOS,Packer,Dennis_D'Annunzio,1:379/28
+0063,Pktize,MS-DOS,Packer,Joaquim_Homrighausen,2:270/17
+0064,PC-RAIN,MS-DOS,Packer/mailer,Ray_Hyder,1:272/40
+0065,Truffle,MS-DOS/OS2,Mailer,Mike_Rissa,2:504/59
+0066,Foozle,Amiga,Packer,Peer_Hasselmeyer,2:247/4
+0067,White_Pointer,Macintosh,Packer/mailer,Alastair_Rakine,3:680/820
+0068,GateWorks,MS-DOS,Packer,Jamie_Penner,1:153/1025
+0069,Portal_of_Power,MS-DOS,Mailer,Soren_Ager,2:230/12
+006A,MacWoof,Macintosh,Packer/mailer,Craig_Vaughan,1:109/342
+006B,Mosaic,MS-DOS,Packer,Christopher_King,1:103/315
+006C,TPBEcho,MS-DOS,Packer,Gerd_Qualmann,2:242/1
+006D,HandyMail,MS-DOS,Packer/mailer,jim_nutt,1:114/30
+006E,EchoSmith,MS-DOS,Packer,Noel_Crow,1:170/409
+006F,FileHost,MS-DOS,Packer,Mark_Cole,2:252/186
+0070,SFTS,MS-DOS,Packer,Bruce_Anderson,1:3402/6
+0071,Benjamin,MS-DOS,Packer/mailer,Stefan_Graf,2:245/4.5436
+0072,RiBBS,OS9_(COCO),Packer/mailer,Ron_Bihler,1:104/54
+0073,MP,MS-DOS,Packer,Ivan_Leong,6:600/28
+0074,Ping,MS-DOS,Packer,David_Nugent,3:632/348
+0075,Door2Europe,MS-DOS,Packer/mailer,Michaela_Schoebel,2:247/14
+0076,SWIFT,MS-DOS,Packer/mailer,Hanno_van_der_Maas,2:500/2
+0077,WMAIL,MS-DOS,Packer,Silvan_Calarco,2:334/100.2
+0078,RATS,MS-DOS,Packer,Jason_DeCaro,1:260/205
+0079,Harry_the_Dirty_Dog,OS2,Mailer/packer,George_Edwards,3:632/340.7
+007A,Maximus-CBCS,MS-DOS/OS2,Packer,Scott_Dudley,1:249/106
+007B,SwifEcho,MS-DOS,Packer,Dana_Bell,1:3801/8
+007C,GCChost,Amiga,Packer,Davide_Massarenti,2:332/505.3
+007D,RPX-Mail,MS-DOS,Packer,Joerg_Wirtgen,2:241/4034
+007E,Tosser,MS-DOS,Packer,Albert_Ng,6:700/185
+007F,TCL,MS-DOS,Packer,Ulf_Hedlund,2:201/602
+0080,MsgTrack,MS-DOS,Packer,Andrew_Farmer,1:243/1
+0081,FMail,MS-DOS/DOS_DPMI/OS2/WIN32,Packer,Folkert_Wijnstra,2:283/619
+0082,Scantoss,MS-DOS,Packer,Michael_Matter,2:243/44.3443
+0083,Point_Manager,Amiga,Packer,Pino_Aliberti,2:335/602.2,,19931012
+0084,IMBINK,MS-DOS,Packer,Mike_Hartmann,2:246/48
+0085,Simplex,MS-DOS/OS2,Packer,Chris_Laforet,1:152/401
+0086,UMTP,MS-DOS,Packer,Byron_Copeland,1:272/26
+0087,Indaba,MS-DOS,Packer,Pieter_Muller,5:7102/11
+0088,Echomail_Engine,MS-DOS,Packer,Joe_Jared,1:103/200
+0089,DragonMail,OS2,Packer,Patrick_O'Riva,1:143/37
+008A,Prox,MS-DOS,Packer,Gerhard_Hoogterp,2:283/1.2
+008B,Tick,MS-DOS/OS2,Packer,Barry_Geller,1:266/12
+008C,RA-Echo,MS-DOS,Packer,Roger_Kirchhoff,2:245/4
+008D,TrapToss,Amiga,Packer,Maximilian_Hantsch,2:310/6
+008E,Babel,MS-DOS/OS2,Packer,Jorgen_Abrahamsen,2:230/100.9
+008F,UMS,Amiga,Packer,Martin_Horneffer,2:242/7.9
+0090,RWMail,MS-DOS,Packer,Remko_Westrik,2:285/309.5
+0091,WildMail,MS-DOS,Packer,Derek_Koopowitz,1:161/502
+0092,AlMAIL,MS-DOS,Packer,Alan_Leung,1:348/207
+0093,XCS,MS-DOS,Packer,Rudi_Kusters,2:512/34.4
+0094,Fone-Link,MS-DOS,Packer/mailer,Chris_Sloyan,1:269/602
+0095,Dogfight,MS-DOS,Packer,Chris_Tyson,2:256/36
+0096,Ascan,MS-DOS,Packer,Arjen_van_Loon,2:281/1.397
+0097,FastMail,MS-DOS,Packer,Jan_Berends,2:282/5
+0098,DoorMan,MS-DOS,Mailer,Christopher_Dean,1:105/70
+0099,PhaedoZap,Atari_ST,Packer,Jeff_Mitchell,1:229/422
+009A,SCREAM,MS-DOS,Packer/mailer,Jem_Miller,1:147/33
+009B,MoonMail,MS-DOS,Packer/mailer,Hasse_Wigdahl,2:206/101
+009C,Backdoor,Sinclair_QL,Packer,Erik_Slagter,2:283/500.3
+009D,MailLink,Archimedes,Packer/mailer,Jan-Jaap_v._d._Geer,2:500/133.1138
+009E,Mail_Manager,MS-DOS,Packer,Andreas_Brodowski,2:241/4006
+009F,Black_Star,Xenix_386,Packer/mailer,Jac_Kersing,2:283/333
+00A0,Bermuda,Atari_ST/MS-DOS,Packer,Jac_Kersing,2:283/333
+00A1,PT,MS-DOS,Packer/mailer,Jerry_Andrew,1:109/426
+00A2,UltiMail,MS-DOS,Mailer,Brett_Floren,1:363/1000
+00A3,GMD,MS-DOS,Packer,John_Souvestre,1:396/1
+00A4,FreeMail,MS-DOS,Packer,Chad_Nelson,1:109/536
+00A5,Meliora,MS-DOS,Packer,Erik_van_Riper,1:107/230
+00A6,Foodo,CPM-80,Packer/mailer,Ron_Murray,3:690/640.7
+00A7,MSBBS,CPM-80,Packer,Marc_Newman,1:106/601
+00A8,Boston_BBS,MS-DOS,Packer/mailer,Tom_Bradford,1:101/625
+00A9,XenoMail,MS-DOS,Packer/mailer,Noah_Wood,1:284/14
+00AA,XenoLink,Amiga,Packer/mailer,Jonathan_Forbes,1:250/642
+00AB,ObjectMatrix,MS-DOS,Packer,Roberto_Ceccarelli,2:332/305.1
+00AC,Milquetoast,Win3/MS-DOS,Mailer,Vince_Perriello,1:343/491
+00AD,PipBase,MS-DOS,Packer,Roberto_Piola,2:334/306
+00AE,EzyMail,MS-DOS,Packer,Peter_Davies,3:636/204
+00AF,FastEcho,MS-DOS,Packer,Tobias_Burchhardt,2:245/39
+00B0,IOS,Atari_ST/TT,Packer,Rinaldo_Visscher,2:280/3.1
+00B1,Communique,MS-DOS,Packer,Ian_Harris,3:620/251
+00B2,PointMail,MS-DOS,Packer,Michele_Clinco,2:331/302.11
+00B3,Harvey's_Robot,MS-DOS,Packer,Harvey_Parisien,1:249/114
+00B4,2daPoint,MS-DOS,Packer,Ron_Pritchett,1:376/74
+00B5,CommLink,MS-DOS,Mailer,Steve_Shapiro,1:382/35
+00B6,fronttoss,MS-DOS,Packer,Dirk_Astrath,2:241/5603
+00B7,SysopPoint,MS-DOS,Packer,Rudolf_Heeb,2:243/44
+00B8,PTMAIL,MS-DOS,Packer,Arturo_Krogulski,2:341/27.7
+00B9,MHS,MS-DOS/OS2/WINNT,Packer/mailer,Matthias_Hertzog,2:301/402,,19940310
+00BA,DLGMail,Amiga,Packer,Steve_Lewis,1:114/52
+00BB,GatePrep,MS-DOS,Packer,Andrew_Allen,1:382/92
+00BC,Spoint,MS-DOS,Packer,Conrad_Thompson,1:130/29.106
+00BD,TurboMail,MS-DOS,Packer,B._J._Weschke,1:2606/403
+00BE,FXMAIL,MS-DOS,Packer,Kenneth_Roach,1:208/401
+00BF,NextBBS,MS-DOS,Packer/mailer,Tomas_Hood,1:352/777
+00C0,EchoToss,MS-DOS,Packer,Mikel_Beck,1:107/218
+00C1,SilverBox,Amiga,Packer,David_Lebel,1:240/516
+00C2,MBMail,MS-DOS,Packer,Ruud_Uphoff,2:500/116.1928
+00C3,SkyFreq,Amiga,Packer,Luca_Spada,2:331/106
+00C4,ProMailer,Amiga,Mailer,Ivan_Pintori,2:335/311.21
+00C5,Mega_Mail,MS-DOS,Packer/mailer,Mirko_Mucko,2:242/94
+00C6,YaBom,MS-DOS,Packer,Berin_Lautenbach,3:620/248
+00C7,TachEcho,MS-DOS,Packer,Tom_Zacios,1:107/376
+00C8,XAP,MS-DOS,Packer,Jeroen_Smulders,2:512/1.8
+00C9,EZMAIL,MS-DOS,Packer,Torben_Paving,2:234/41
+00CA,Arc-Binkley,Archimedes,Mailer,Geoff_Riley,2:250/208
+00CB,Roser,MS-DOS,Packer,Chan_Kafai,6:700/158
+00CC,UU2,MS-DOS,Packer,Dmitri_Zavalishin,2:5020/32
+00CD,NMS,MS-DOS,Packer/mailer,Michiel_de.Bruijn,2:285/505.2
+00CE,BBCSCAN,Archimedes,Packer/mailer,E._G._Snel,2:512/222.17
+00CF,XBBS,MS-DOS,Packer,Mark_Kimes,1:380/16
+00D0,LoTek_Vzrul,,Packer/mailer,Kevin_Gates,gates@sasknet.sk.ca,19951229,20000122
+00D1,Private_Point_Project,MS-DOS,Packer,Oliver_von_Bueren,2:301/701
+00D2,NoSnail,MS-DOS,Packer,Eddie_Rowe,1:19/124
+00D3,SmlNet,MS-DOS,Packer,Steve_T._Gove,1:106/6
+00D4,STIR,MS-DOS,Packer,Paul_Martin,2:250/107.3
+00D5,RiscBBS,Archimedes,Packer,Carl_Declerck,2:292/500.10
+00D6,Hercules,Amiga,Packer/mailer,Andrew_Gray,1:231/590
+00D7,AMPRGATE,MS-DOS,Packer/mailer,Mike_Bilow,1:323/120.1
+00D8,BinkEMSI,MS-DOS,Mailer,Tobias_Burchhardt,2:245/39
+00D9,EditMsg,MS-DOS,Packer,G._K._Pace,1:374/26
+00DA,Roof,Amiga,Packer,Robert_Williamson,1:167/104
+00DB,QwkPkt,MS-DOS,Packer,Ross_West,1:250/412
+00DC,MARISCAN,MS-DOS,Packer,Mario_Elkati,2:341/14.9
+00DD,NewsFlash,MS-DOS,Packer,Chris_Lueders,2:241/5306
+00DE,Paradise,MS-DOS,Packer/mailer,Kenneth_Wall,1:300/5
+00DF,DogMatic-ACB,N/A,Packer/mailer,Martin_Allard,2:245/48
+00E0,T-Mail,MS-DOS,Packer/mailer,Andy_Elkin,2:5030/15
+00E1,JetMail,Atari_ST/STE/TT,Packer,Daniel_Roesen,2:243/93.8
+00E2,MainDoor,MS-DOS,Packer/mailer,Francisco_Sedano,2:341/20
+00E3,Starnet_Products,MS-DOS/OS2,Mailer/Packer,Starnet_Software_Development,1:102/925,,19951209
+00E4,BMB,Amiga,Packer,Dentato_Remo,2:335/311.33
+00E5,BNP,MS-DOS,Packer,Nathan_Moschkin,1:109/427
+00E6,MailMaster,MS-DOS,Packer/mailer,Gary_Murphy,1:130/85
+00E7,Mail_Manager_+Plus+,MS-DOS,Packer,Chip_Morrow,1:226/1240
+00E8,BloufGate,Atari_ST/Unix,Packer,Vincent_Pomey,2:320/100.2
+00E9,CrossPoint,MS-DOS,Packer/mailer,Peter_Mandrella,2:2454/97.80,19920713,19960601
+00EA,DeltaEcho,MS-DOS,Packer,Mikael_Staldal,2:201/337
+00EB,ALLFIX,MS-DOS,Packer,Harald_Harms,2:512/145
+00EC,NetWay,Archimedes,Mailer,Steve_Haslam,2:250/116.3
+00ED,MARSmail,Atari_ST,Packer,Folkert_val_Heusden,2:285/750.2,,19940122
+00EE,ITRACK,MS-DOS/OS2,Packer,Frank_Prade,2:2480/55,,19990119
+00EF,GateUtil,MS-DOS,Packer,Michael_Skurka,1:397/2.1
+00F0,Bert,MS-DOS,Packer/mailer,Arnim_Wiezer,2:241/2104.9
+00F1,Techno,MS-DOS,Packer,Patrik_Holmsten,2:203/133
+00F2,AutoMail,MS-DOS,Packer,Mats_Wallin,2:201/239
+00F3,April,Amiga,Packer,Nick_de_Jong,2:282/309.3
+00F4,Amanda,MS-DOS,Packer,David_Douthitt,1:121/99.14
+00F5,NmFwd,MS-DOS,Packer,Alberto_Pasquale,2:332/504
+00F6,FileScan,MS-DOS,Packer,Matthias_Duesterhoeft,2:241/4512.2
+00F7,FredMail,MS-DOS,Packer,Michael_Butler,3:712/515
+00F8,TP_Kom,MS-DOS,Packer/mailer,Per_Sten,2:201/124
+00F9,FidoZerb,MS-DOS,Packer,Ulrich_Schlechte,2:241/3410.12
+00FA,!!MessageBase,MS-DOS,Packer/mailer,Holger_Lembke,2:240/500.20
+00FB,EMFido,Amiga,Packer,Gary_Glendown,2:249/3.999
+00FC,GS-Toss,MS-DOS,Packer,Marco_Bungalski,2:241/2021
+00FD,QWKDoor,Atari_ST,Packer,Christian_Limpach,2:270/20.1
+00FE,No_product_id_allocated,Any,Packer,No_Author,3:3/20
+00FF,16-bit_product_id,Any,Packer/Mailer,No_Author,3:3/20
+0100,Reserved,None,None,No_Author,3:3/20,19951209
+0101,The_Brake!,Mailer,John_Gladkih,2:5051/16,19951209
+0102,Zeus_BBS,Amiga,Mailer,Alex_May,2:441/58.0,19951209
+0103,XenoPhobe-Mailer,Msdos/Windows/OS2/Linux,Mailer,Peter_Kling,1:374/969.0,19951209
+0104,None,None,None,None,0:0/0,
+0105,Terminate,Msdos/Os2/Windows,Mailer/Packer,SerWiz_Comm_&_Bo_Bendtsen,2:254/261,19951209
+0106,TeleMail,Msdos,Mailer/Packer,Juergen_Weigelt,2:2453/900,19951209
+0107,CMBBS,Msdos/Os2,Mailer/Packer,Christof_Engel,2:2490/5110,19951209
+0108,Shuttle,Windows,Mailer/Packer,MCH_Development_&_Marvin_Hart,1:106/500,19951209
+0109,Quater,Amiga,Mailer,Felice_Murolo,2:335/206,19951209
+010A,Windo,Windows,Mailer,Alan_Chavis,1:147/55,19951209
+010B,Xenia,Msdos/Os2,Mailer,Arjen_Lentz,2:283/512,19960601
+010C,GMS,AmigaOS,Mailer,Mirko_Viviani,2:331/213,19960601
+010D,HNET,Msdos,???,Pedro_Jaramillo,1:102/160,19960601
+010E,Shotgun_Professional,Msdos,???,Brent_Shellenberg,1:140/146,19960621
+010F,SLIPgate,Msdos,???,Kieran_Morrissey,3:634/376,19960723
+0110,BBBS,MSDOS/OS2/NT/Amiga/Unix,Mailer/Packer,Kim_Heino,2:22/222,19980216
+0111,NewsGate,Windows/NT,Packer/Gateway,Leilo_denna_Pietra,2:335/244,19980216
+01FF,BBBS,MSDOS/OS2/NT/Amiga/Unix,Mailer/Packer,Kim_Heino,2:22/222,19980216
+02FF,NewsGate,Windows/NT,Packer/Gateway,Leilo_denna_Pietra,2:335/244,19980216
+03FF,Ravel,Macintosh,Mailer/Packer,Cyril_Moorzin,2:5030/700,19980310
+04FF,Beemail,Windows,Mailer/Packer,Andrius_Cepaitis,2:470/1,19980310
+05FF,QuickToss,DOS,Packer,Sandra_Godinez,1:387/601.3,19980310
+06FF,SpaceMail,???,Mailer,Andreas_Habicht,2:244/6121,19980710
+07FF,Argus,Windows/NT,Mailer,Max_Masyutin,2:469/84,19990216
+08FF,Hurricane,Windows/NT/Solaris,Packer,Paul_Walker,2:254/175.44,19990216
+09FF,Hub_Mailer,OS2,Mailer,Viatcheslav_Odintsov,2:5020/181,19990216
+0AFF,FDInt,MSDOS,Packer,Colin_Turner,2:443/13,19990216
+0BFF,GPMail,OS2,Mailer,Igor_Vanin,2:5030/448,19990216
+0CFF,FTrack,NT/OS2,Tracker,Fyodor_Ustinov,2:5020/79,19990313
+0DFF,Nice_Tosser,DOS/OS2/Win32,Tosser,Robert_Agababyan,2:5020/234.1,19990518
+0EFF,LuckyGate,DOS/OS2/Linux,Packer,Pavel_Gulchouck,2:463/68,19990709
+0FFF,McMail,DOS,Mailer,Simon_Slater,2:443/777,20000102
+
+ +Back Go Back + + + + diff --git a/html/ftsc/index.htm b/html/ftsc/index.htm new file mode 100644 index 00000000..34343c7c --- /dev/null +++ b/html/ftsc/index.htm @@ -0,0 +1,99 @@ + + + + + + + + +Fidonet Standard Commitee documents. + + + +
+
Last update 08-Jun-2001
+

 

+ +

Fidonet Technical Standards

+ +

Introduction

+

+This is an overview of used documents for the development of the MBSE BBS +package. Note that there are more documents, but only the relevant and valid +documents are present here. Also note that these documents are just imported +into html documents without any changes. +

+Michiel Broek. +

+ +


+

FSC Documents

+ + +

+ +

FSP Documents

+ + + +

+

FTA Documents

+ + + +

+

FTS Documents

+ + +
+ +IndexBack to Index +
+ + + diff --git a/html/gwnews.html b/html/gwnews.html new file mode 100755 index 00000000..708339d3 --- /dev/null +++ b/html/gwnews.html @@ -0,0 +1,381 @@ + + + + + + + + +MBSE BBS - Internet gateway - INN. + + + +
+
Last update 10-Apr-2001
+

 

+ +

MBSE BBS - Internet Gateway - INN.

+

+ +

SETUP INND

+

+Below are the files that you need to setup for INN news. I used inn-2.2.2 on +my system. It is configured to install in /opt/news with the command +./configure --prefix=/opt/news during the installation of +inn. +

+


+
+
+##  $Revision$
+##  inn.conf -- inn configuration data
+##  Format:
+##	:
+##
+##  See the inn.conf(5) man page for a full description of each
+##  of these options
+##
+##  Blank values are allowed for certain parameters
+## ---------------------------------
+# All parameters must exist
+#
+organization:		MBSE BBS Development Site
+server:			localhost
+pathhost:		news.mbse.nl
+moderatormailer:
+domain:			mbse.nl
+fromhost:		news.mbse.nl
+pathalias:
+complaints:		abuse@f2802.n280.z2.fidonet.org
+mta:			/usr/sbin/sendmail -oi %s
+mailcmd:		/opt/news/bin/innmail
+checkincludedtext:	false
+maxforks:		10
+maxartsize:		1000000
+nicekids:		4
+nicenewnews:		0
+verifycancels:		false
+logcancelcomm:		false
+wanttrash:		false
+remembertrash:		true
+linecountfuzz:		0
+peertimeout:		3600
+clienttimeout:		600
+allownewnews:		true
+localmaxartsize:	1000000
+logartsize:		true
+logipaddr:		true
+logsitename:		true
+maxconnections:		50
+artcutoff:		14
+icdsynccount:		10
+hiscachesize:		0
+readertrack:		false
+strippostcc:		false
+status:			0
+timer:			0
+readerswhenstopped:	false
+noreader:		false
+extendeddbz:		false
+nnrpdoverstats:		false
+storeonxref:		true
+nnrpdcheckart:		true
+storemsgid:		true
+usecontrolchan:		false
+mergetogroups:		false
+backoffauth:		false
+backoffdb:		/opt/news/db/backoff
+backoffpostfast:	0L
+backoffpostslow:	1L
+backofftrigger:		10000L
+mimeversion:
+mimecontenttype:
+mimeencoding:
+refusecybercancels:	false
+activedenable:		false
+activedupdate:		30
+activedport:		1119
+nnrpperlauth:		false
+#
+# 
+# These options are unlikely to need changing in most situations
+#
+chaninacttime:		600
+chanretrytime:		300
+pauseretrytime:		300
+nntplinklog:		false
+nntpactsync:		200
+badiocount:		5
+blockbackoff:		120
+#
+# ---------------------------------
+# Changing these options can have an effect on the way articles are
+# stored and may require recreating the spool and/or database files
+#
+wireformat:		false
+xrefslave:		false
+nnrpdposthost:
+nnrpdpostport:		119
+spoolfirst:		false
+writelinks:		true
+storageapi:		false
+articlemmap:		false
+overviewmmap:		true
+bindaddress:		all
+sourceaddress:		any
+port:			119
+#
+## Keywords-in-overview options
+## Enabling this without stopping innd and deleting the existing overview
+## database and adding  will probably confuse a lot of things. You must 
+## have compiled this support in too.
+#
+keywords:		false
+keylimit:		512
+keyartlimit:		100000
+keymaxwords:		250
+#
+# Other options
+innflags:		
+doinnwatch:		true
+innwatchsleeptime:	600
+pgpverify:		false
+controlfailnotice:	false
+logcycles:		3
+innwatchpauseload:	1500
+innwatchhiload:		2000
+innwatchloload:		1000
+innwatchspoolspace:	8000
+innwatchbatchspace:	800
+innwatchlibspace:	25000
+innwatchspoolnodes:	200
+docnfsstat:		false
+#
+# ---------------------------------
+# Paths to various aspects of the news system
+#
+pathnews:		/opt/news
+pathbin:		/opt/news/bin
+pathfilter:		/opt/news/bin/filter
+pathcontrol:		/opt/news/bin/control
+pathdb:			/opt/news/db
+pathetc:		/opt/news/etc
+pathrun:		/opt/news/run
+pathlog:		/opt/news/log
+pathhttp:		/opt/news/log
+pathtmp:		/opt/news/tmp
+pathspool:		/opt/news/spool
+patharticles:		/opt/news/spool/articles
+pathoverview:		/opt/news/spool/overview
+pathoutgoing:		/opt/news/spool/outgoing
+pathincoming:		/opt/news/spool/incoming
+patharchive:		/opt/news/spool/archive
+pathuniover:		/opt/news/spool/uniover
+overviewname:		.overview
+#
+# ---------------------------------
+#
+
+
+
+ +
+##  $Revision$
+##  expire.ctl - expire control file
+##  Format:
+##	/remember/:<keep>
+##	<patterns>:<modflag>:<keep>:<default>:<purge>
+##  First line gives history retention; other lines specify expiration
+##  for newsgroups.  Must have a "*:A:..." line which is the default.
+##	<patterns>	wildmat-style patterns for the newsgroups
+##	<modflag>	Pick one of M U A -- modifies pattern to be only
+##			moderated, unmoderated, or all groups
+##	<keep>		Mininum number of days to keep article
+##	<default>	Default number of days to keep the article
+##	<purge>		Flush article after this many days
+##  <keep>, <default>, and <purge> can be floating-point numbers or the
+##  word "never."  Times are based on when received unless -p is used;
+##  see expire.8
+
+##  If article expires before 14 days, we still remember it for 14 days in
+##  case we get offered it again.  Depending on what you use for the innd
+##  -c flag and how paranoid you are about old news, you might want to
+##  make this 28, 30, etc.
+/remember/:14
+
+##  Keep for 1-10 days, allow Expires headers to work.
+*:A:1:10:never
+
+fido.*:A:1:30:60
+comp.*:A:1:30:60
+local.*:A:1:30:60
+nl.*:A:1:30:60
+
+##  Some particular groups stay forever.
+# Keep FAQ's for a month, so they're always available
+#*.answers:M:1:35:90
+news.announce.*:M:1:35:90
+
+# Some other recommendations.  Uncomment if you want
+# .announce groups tend to be low-traffic, high signal.
+# *.announce:M:1:30:90
+# Weather forecasts
+# *.weather:A:1:2:7
+# test posts
+# *.test:A:1:1:1
+
+##  Some particular groups stay forever.
+# dc.dining*:A:never:never:never
+# uunet*:A:never:never:never
+
+
+
+##  $Revision$
+##  Mailing addresses for moderators.
+##  Format:
+##	<newsgroup>:<pathname>
+##  First match found is used.
+##	<newsgroup>	Shell-style newsgroup pattern or specific newsgroup
+##	<pathname>	Mail address, "%s" becomes newgroup name with dots
+##			changed to dashes.
+
+## Russian hierarchies
+fido7.*:%s@fido7.ru
+medlux.*:%s@news.medlux.ru
+relcom.*:%s@moderators.relcom.ru
+
+## Direct all public hierarchies to the master moderator database.
+*:%s@moderators.isc.org
+
+
+
+##  $Revision$
+##  newsfeeds - determine where Usenet articles get sent
+##  Format:
+##	site[/exclude,exclude...]\
+##		:pattern,pattern...[/distrib,distrib...]\
+##		:flag,flag...\
+##		:param
+##  Summary of flags:
+##	<size		Article must be less then size bytes.
+##	>size		Article must be more then size bytes.
+##	Aitems		Article checks -- d (must have Distribution header)
+##			p (don't check for site in Path header)
+##			c (no control messages) C (only control messages)
+##			e (all groups must exist).
+##	Bhigh/low	Internal buffer size before writing to output.
+##	Fname		Name of the spool file.
+##	Gcount		Crossposts limited to count groups.
+##	H[count]	Article must have less then count hops; default is 1.
+##	Isize		Internal buffer size (if a file feed)
+##	Nm		Only moderated groups that match the patterns.
+##	Nu		Only unmoderated groups that match the patterns.
+##	Ppriority	Nice priority of channel or program feed.
+##	Ooriginator	First field of X-Trace must match originator (wildmat).
+##	Ssize		Start spooling if more than size bytes get queued.
+##	Ttype		Feed types -- f (file) m (funnel; param names the
+##			real entry) p (pipe to program) c (send to stdin
+##			channel of param's sub-process) x (like c, but
+##			handles commands on stdin) x (log entry only).
+##	Witems		What to write -- b (article bytesize) f (full path)
+##			g (first newsgroup) h (Message-ID hash) 
+##			m (Message-ID) n (relative path) p (posted time)
+##			s (site that fed article) t (time received)
+##			* (names of funnel feed-in's or all sites that get
+##			the article) N (Newsgroups header) D (Distribution
+##			header) H (all headers) O (overview data)
+##			P (path header) R (replication information)
+##  Param field depends on T flag.  For Tf, relative paths are from the
+##  out.going directory.  For Tp and Tc, it is a shell command to execute.
+##  If a Tm refers to this entry (which will have its own T param) then "*"
+##  is expanded to all the funnel sites that triggered this one.  Useful
+##  for spawning one mail process, e.g.
+##
+##  This file is complicated -- see newsfeeds.5!
+
+##  This is the local site.
+##  The "pattern" field gives the initial subscription list for
+##  all other sites.  You might want to put "!control,!junk,!.*"
+##  there.  The "distrib" subfield limits incoming articles.
+##
+##  You can also have ME/bad.site: to refuse articles from a particular
+##  site (by matching the Path: entry).  Other pseudo-sites may be put
+##  in here, to REFUSE certain types of 3rd-party cancel messages
+##  (See the "Cancel FAQ" news.admin.net-abuse.misc):
+##	cyberspam	Spam cancels, munged articles, binary postings
+##	spewcancel	just munged articles from runaway gateways
+##	bincancel	just binary postings to non-binaries groups
+##
+##  Note that refusing articles means you won't offer them to sites you feed
+
+## Default of  everything to everybody except for junk, control, anything
+## with "local" as the newsgroup prefix (i.e. matches "localhost.stuff") or
+## groups under foo. Articles posted to any group under alt.binaries.warez
+## will not get propagated, even if they're cross posted to something that
+## is.
+ME\
+	:*,!junk,!control*,!foo.*/fido,local\
+	::
+
+## news.wxs.nl via rpost (suck)
+news.wxs.nl/news.wxs.nl:*,!control,!junk,!fido.*,!iba.*,!local.*/!local,!fido::
+
+##  News overview
+# use this flag if storage api is used
+#overview!:*:Tc,Ao,WhR,S30000:/opt/news/bin/overchan
+# else
+overview!:*:Tc,WO,S30000:/opt/news/bin/overchan
+
+
+
+
+##  $Revision$
+##  distrib.pats -- specify default Distribution header for newsgroups
+##  Format:
+##	<weight>:<pattern>:<value>
+##  All articles are matched against all patterns, value to be used is the
+##  one with the highest weight.
+##	<weight>	The weight assigned to this match, integer
+##	<pattern>	Newsgroup name or single wildmat(3) pattern
+##	<value>		Value of Distribution header.
+##
+##
+## Uncomment to default all local.* groups to a distribution of local.
+#10:local.*:local
+10:local.*:local
+10:fido.*:fido
+
+
+
+##  $Revision$
+##  nnrp.access - access file for on-campus NNTP sites
+##  Format:
+##	<host>:<perm>:<user>:<pass>:<groups>
+##	<host>:</path/file>
+##  Connecting host must be found in this file; the last match found is
+##  used, so put defaults first.
+##	<host>		Wildcard name or IP address
+##	<perm>		R to read; P to post
+##	<user>		Username for authentication before posting
+##	<pass>		Password, for same reason
+##	<groups>	Newsgroup patterns that can be read or not read
+##	</path/file>	A second file to scan in the same format as this
+##  To disable posting put a space in the <user> and <pass> fields, since
+##  there is no way for client to enter one.
+##
+## Default is no access, no way to authentication, and no groups.
+*::::!*
+stdin:Read Post:::*
+localhost:Read Post:::*
+127.0.0.1:Read Post:::*
+*.mbse.nl:Read Post:::*
+
+
+ +BackGo back +HomeGo to main + +
+ + + diff --git a/html/images/b_arrow.gif b/html/images/b_arrow.gif new file mode 100644 index 00000000..4a28444c Binary files /dev/null and b/html/images/b_arrow.gif differ diff --git a/html/images/connec.gif b/html/images/connec.gif new file mode 100644 index 00000000..acb1f160 Binary files /dev/null and b/html/images/connec.gif differ diff --git a/html/images/domains.gif b/html/images/domains.gif new file mode 100644 index 00000000..687bee5d Binary files /dev/null and b/html/images/domains.gif differ diff --git a/html/images/e_menu.gif b/html/images/e_menu.gif new file mode 100644 index 00000000..466932f9 Binary files /dev/null and b/html/images/e_menu.gif differ diff --git a/html/images/emareas.gif b/html/images/emareas.gif new file mode 100644 index 00000000..bdb0346f Binary files /dev/null and b/html/images/emareas.gif differ diff --git a/html/images/emgroup.gif b/html/images/emgroup.gif new file mode 100644 index 00000000..af7326c7 Binary files /dev/null and b/html/images/emgroup.gif differ diff --git a/html/images/fdb.gif b/html/images/fdb.gif new file mode 100644 index 00000000..e8fbb413 Binary files /dev/null and b/html/images/fdb.gif differ diff --git a/html/images/fegroup.gif b/html/images/fegroup.gif new file mode 100644 index 00000000..901b6563 Binary files /dev/null and b/html/images/fegroup.gif differ diff --git a/html/images/fileecho.gif b/html/images/fileecho.gif new file mode 100644 index 00000000..8013ef70 Binary files /dev/null and b/html/images/fileecho.gif differ diff --git a/html/images/filefind.gif b/html/images/filefind.gif new file mode 100644 index 00000000..5603b328 Binary files /dev/null and b/html/images/filefind.gif differ diff --git a/html/images/files.gif b/html/images/files.gif new file mode 100644 index 00000000..49beb6a8 Binary files /dev/null and b/html/images/files.gif differ diff --git a/html/images/go_to.gif b/html/images/go_to.gif new file mode 100644 index 00000000..c1b38483 Binary files /dev/null and b/html/images/go_to.gif differ diff --git a/html/images/hatch.gif b/html/images/hatch.gif new file mode 100644 index 00000000..64e70146 Binary files /dev/null and b/html/images/hatch.gif differ diff --git a/html/images/language.gif b/html/images/language.gif new file mode 100644 index 00000000..239e5fdf Binary files /dev/null and b/html/images/language.gif differ diff --git a/html/images/larrow.gif b/html/images/larrow.gif new file mode 100644 index 00000000..5e19567e Binary files /dev/null and b/html/images/larrow.gif differ diff --git a/html/images/magic.gif b/html/images/magic.gif new file mode 100644 index 00000000..7b91e6de Binary files /dev/null and b/html/images/magic.gif differ diff --git a/html/images/mbse.jpg b/html/images/mbse.jpg new file mode 100644 index 00000000..370c02e2 Binary files /dev/null and b/html/images/mbse.jpg differ diff --git a/html/images/mbsetup0.gif b/html/images/mbsetup0.gif new file mode 100644 index 00000000..356a7249 Binary files /dev/null and b/html/images/mbsetup0.gif differ diff --git a/html/images/mbsetup1.6.S.gif b/html/images/mbsetup1.6.S.gif new file mode 100644 index 00000000..19f68893 Binary files /dev/null and b/html/images/mbsetup1.6.S.gif differ diff --git a/html/images/mbsetup1.6.gif b/html/images/mbsetup1.6.gif new file mode 100644 index 00000000..84698e51 Binary files /dev/null and b/html/images/mbsetup1.6.gif differ diff --git a/html/images/mbsetup2.gif b/html/images/mbsetup2.gif new file mode 100644 index 00000000..c0c7c56d Binary files /dev/null and b/html/images/mbsetup2.gif differ diff --git a/html/images/modems0.gif b/html/images/modems0.gif new file mode 100644 index 00000000..f04e8c4c Binary files /dev/null and b/html/images/modems0.gif differ diff --git a/html/images/newfiles.gif b/html/images/newfiles.gif new file mode 100644 index 00000000..961e269f Binary files /dev/null and b/html/images/newfiles.gif differ diff --git a/html/images/newgroups.gif b/html/images/newgroups.gif new file mode 100644 index 00000000..e5f1d133 Binary files /dev/null and b/html/images/newgroups.gif differ diff --git a/html/images/nodelist.gif b/html/images/nodelist.gif new file mode 100644 index 00000000..361fb05d Binary files /dev/null and b/html/images/nodelist.gif differ diff --git a/html/images/nodelist1.gif b/html/images/nodelist1.gif new file mode 100644 index 00000000..7d2bc179 Binary files /dev/null and b/html/images/nodelist1.gif differ diff --git a/html/images/nodelist2.gif b/html/images/nodelist2.gif new file mode 100644 index 00000000..ecdce8d1 Binary files /dev/null and b/html/images/nodelist2.gif differ diff --git a/html/images/nodelist3.gif b/html/images/nodelist3.gif new file mode 100644 index 00000000..b064d659 Binary files /dev/null and b/html/images/nodelist3.gif differ diff --git a/html/images/nodelist4.gif b/html/images/nodelist4.gif new file mode 100644 index 00000000..b722e8f4 Binary files /dev/null and b/html/images/nodelist4.gif differ diff --git a/html/images/nodelist5.gif b/html/images/nodelist5.gif new file mode 100644 index 00000000..ea5b7195 Binary files /dev/null and b/html/images/nodelist5.gif differ diff --git a/html/images/nodes.gif b/html/images/nodes.gif new file mode 100644 index 00000000..29d530c1 Binary files /dev/null and b/html/images/nodes.gif differ diff --git a/html/images/nodes1.gif b/html/images/nodes1.gif new file mode 100644 index 00000000..ef162724 Binary files /dev/null and b/html/images/nodes1.gif differ diff --git a/html/images/nodes2.gif b/html/images/nodes2.gif new file mode 100644 index 00000000..a29e5410 Binary files /dev/null and b/html/images/nodes2.gif differ diff --git a/html/images/nodes3.gif b/html/images/nodes3.gif new file mode 100644 index 00000000..b0dbcc37 Binary files /dev/null and b/html/images/nodes3.gif differ diff --git a/html/images/nodes4.gif b/html/images/nodes4.gif new file mode 100644 index 00000000..a9d8882e Binary files /dev/null and b/html/images/nodes4.gif differ diff --git a/html/images/nodes5.gif b/html/images/nodes5.gif new file mode 100644 index 00000000..78ee5af7 Binary files /dev/null and b/html/images/nodes5.gif differ diff --git a/html/images/oneliner.gif b/html/images/oneliner.gif new file mode 100644 index 00000000..6592864a Binary files /dev/null and b/html/images/oneliner.gif differ diff --git a/html/images/protocol.gif b/html/images/protocol.gif new file mode 100644 index 00000000..63e542ae Binary files /dev/null and b/html/images/protocol.gif differ diff --git a/html/images/rarrow.gif b/html/images/rarrow.gif new file mode 100644 index 00000000..27a25e78 Binary files /dev/null and b/html/images/rarrow.gif differ diff --git a/html/images/security.gif b/html/images/security.gif new file mode 100644 index 00000000..74e41826 Binary files /dev/null and b/html/images/security.gif differ diff --git a/html/images/taskmgr.gif b/html/images/taskmgr.gif new file mode 100644 index 00000000..14d41c18 Binary files /dev/null and b/html/images/taskmgr.gif differ diff --git a/html/images/tty.gif b/html/images/tty.gif new file mode 100644 index 00000000..042d7a56 Binary files /dev/null and b/html/images/tty.gif differ diff --git a/html/images/tty1.gif b/html/images/tty1.gif new file mode 100644 index 00000000..168412ef Binary files /dev/null and b/html/images/tty1.gif differ diff --git a/html/images/tty2.gif b/html/images/tty2.gif new file mode 100644 index 00000000..df2e9ee4 Binary files /dev/null and b/html/images/tty2.gif differ diff --git a/html/images/tty3.gif b/html/images/tty3.gif new file mode 100644 index 00000000..19c787f5 Binary files /dev/null and b/html/images/tty3.gif differ diff --git a/html/images/uarrow.gif b/html/images/uarrow.gif new file mode 100644 index 00000000..9b89e805 Binary files /dev/null and b/html/images/uarrow.gif differ diff --git a/html/images/users.gif b/html/images/users.gif new file mode 100644 index 00000000..983e8ec7 Binary files /dev/null and b/html/images/users.gif differ diff --git a/html/index.htm b/html/index.htm new file mode 100755 index 00000000..a7aa940d --- /dev/null +++ b/html/index.htm @@ -0,0 +1,136 @@ + + + + + + + + +Running a BBS under Linux. + + + +
+
+

MBSE BBS System Guide v0.33.17

+
+ +
Last update 07-Jul-2001

+ + +

Introduction

+ + +

 

+ +

Release Notes

+ + +

 

+ +

MBSE BBS Reference Manual

+ +
    +
  1. Running a BBS under Linux
  2. +
  3. Which distribution to use
  4. +
  5. Basic installation MBSE BBS
  6. +
  7. Finishing installation of MBSE BBS
  8. +
  9. Configuring the bbs with mbsetup
  10. +
      +
    1. Edit Global configuration +
    2. Edit Fido networks +
    3. Edit Archiver programs +
    4. Edit Virus scanners +
    5. Edit Modem types +
    6. Edit TTY lines info +
    7. Edit Fidonet nodes +
    8. Edit BBS setup +
        +
      1. Edit Security limits +
      2. Edit Language setup +
      3. Edit BBS menus +
      4. Edit File areas +
      5. Edit Transfer protocols +
      6. Edit BBS List data +
      7. Edit Oneliners +
      8. Edit TimeBank data +
      9. Edit Safe Cracker data +
      +
    9. Edit Mail setup +
        +
      1. Echo mail groups +
      2. Echo mail areas +
      +
    10. Edit File echo's setup +
        +
      1. Edit Fileecho groups +
      2. Edit Fileecho areas +
      3. Edit Hatch manager +
      4. Edit Magic files +
      +
    11. Edit Newfiles groups +
    12. Edit Newfiles reports +
    13. Edit Filefind setup +
    14. Edit Files database +
    15. Edit BBS users +
    16. Edit Services +
    17. Edit Domains +
    18. Edit task manager +
    19. Show software information +
    20. Create site documents +
    +
  11. Starting and Stopping the BBS
  12. +
  13. Setup mgetty for the BBS
  14. +
  15. Programs and utilities
  16. +
      +
    1. import, Import databases
    2. +
    3. mbaff, Announce newfiles and filefind
    4. +
    5. mball, Allfiles and newfiles list creator
    6. +
    7. mbchat, Sysop to user chat utility
    8. +
    9. mbcico, The Fidonet mailer ala ifcico
    10. +
    11. mbdiff, Nodelist difference processor
    12. +
    13. mbfbgen, FileBase generator utility
    14. +
    15. mbfido, Fidonet mail and files procesor
    16. +
    17. mbfile, Files database maintenance program
    18. +
    19. mbindex, Nodelist index compiler
    20. +
    21. mblang, Language datafile compiler
    22. +
    23. mbmail, Mail Transport Agent for email
    24. +
    25. mbmon, The monitor program
    26. +
    27. mbmsg, The messagebase utility program
    28. +
    29. mbout, The mailer outbound program
    30. +
    31. mbpasswd, The passwd wrapper
    32. +
    33. mbsebbs, The bbs program
    34. +
    35. mbseq, Sequence number creator
    36. +
    37. mbsetup, The setup program
    38. +
    39. mbstat, The bbs status change program
    40. +
    41. mbtask, The taskmanager for the bbs system
    42. +
    43. mbtoberep, The toberep.data lister
    44. +
    45. mbuser, The userbase maintenance program
    46. +
    47. mbuseradd, The useradd wrapper
    48. +
    +
  17. Netmail routing behaviour
  18. +
  19. Fido to Internet Gateway
  20. +
  21. Nodediff and Nodelist processing
  22. +
  23. Using UPS semafore's
  24. +
+

 

+ +

Other Notes

+ + + +
+BackBack  +TopTop +
+ + + diff --git a/html/install.html b/html/install.html new file mode 100755 index 00000000..f71dd1d6 --- /dev/null +++ b/html/install.html @@ -0,0 +1,54 @@ + + + + + + + + +Running a BBS under Linux. + + + +
+
Last update 03-Jul-2001
+

 

+ + +Installing the BBS. + + +

Installing the BBS.

+ + +

Installing the BBS.

+

+Now you have shell scripts in ~/etc, most of them are called by cron, some +are called during system startup and shutdown. You also have some default +configuration files, these are ttyinfo, modems, fidonet networks. In the +default (english) directory you now have default menu datafiles and ansi +screens. These are copies of my test system so you have to edit them to +build your own bbs.
+Editing ansi screens can be done on a Linux system with duhdraw, +this is available from 2:280/2802 as duhdraw.tgz (68 Kbytes). +The binaries are included in this archive, if you compile it yourself +it may give trouble so if the binaries work, use these.
+Another editor is available from +http://www.drastic.net/bmdraw/, +you can find the tar.gz file in +http://www.drastic.net/bmdraw/files/bmd022.tgz, it's about 36 Kbytes. +This is also a thedraw clone for Linux. Note, at my system I needed to run it as root.
+You may also want to edit ~/etc/header.txt and ~/etc/footer.txt, these +files are the top and bottom of the newfiles/allfiles listings. + +

+

the next step.

+

+The next step is the setup of the bbs. +

+ +Back to IndexBack to Index +

+ + + diff --git a/html/intergate.html b/html/intergate.html new file mode 100644 index 00000000..bb1ef0b4 --- /dev/null +++ b/html/intergate.html @@ -0,0 +1,102 @@ + + + + + + + + +MBSE BBS - Internet gateway. + + + +
+
Last update 26-Apr-2001
+

 

+ +

MBSE BBS - Internet Gateway.

+

+ +

WARNING: THIS IS DIFFERENT FROM VERSION 0.33.14 AND UP

+

+ +

Introduction.

+

+Since version 0.33.14 the email gateway is build into MBSE BBS and since +version 0.33.15 the newsgateway is build into MBSE BBS. Since version 0.33.16 the +newsgateway to UUCP nodes is added. To route +email trafic to and from the internet you need a internet MTA. I stopped using +sendmail for this because it gave too much trouble setting it +up together with MBSE BBS. +Today I use Postfix, +a well documented, secure and easy to setup MTA. For the actual gate from +Postfix to the BBS you I use mbmail which you need to add to the +Postfix configuration.

+

+There may be two reasons to create a gateway, one is to gate internet news and +email to the Fidonet bbs users, another reason may be that you want to make +echomail as news available on your system so that users can connect to your +bbs with their favourite browser an get the mail and news using pop3 and +nntp protocols. The setup is the same for both reasons so I will make one +description for the whole setup. +

 

+ +

Setup a newsgate node with inn.

+

+If you only want to gate internet news to your bbs users and not want to +make echomail available as news, and you have a permament internet connection +then you don't need your own news server. Just configure MBSE BBS to use the +newsserver of your ISP in screen 1.14 with mbsetup. All other users need +to run a newsserver on the bbs machine or another networked machine. You +could use inn news for a newsserver. +To connect a small feed with your ISP you could use suck. +

+In each echomail area you want to gate you need to fill in the newsgroup +name of that area and echomail received in that area will automatic be +posted to that newsgroup. The command mbfido news will check all +configured newsgroups for new newsarticles. If you set it up for the first +time you need to run mbfido news -learn to fill the dupes +database for news with all the already excisting news articles. If you skip +that, you may get a lot of old articles that will be gated. Just run that +command once after you have set this up. Later when you receive fresh articles +the command mbfido news will only gate new arrived articles. +See the configuration of INN news configuration. +

 

+ +

Setup a newsgate with rnews.

+

+This is the setup if you don't want an NNTP newsserver like inn, but a simple +cnews setup for UUCP links only. In mbsetup menu 1.14 you need +to set this up. You need to fill in the path to the rnews program so that +mbfido can post articles to cnews. MORE INFO NEEDED. +

+In each echomail area you want to gate you need to fill in the newsgroup +name of that area and echomail received in that area will automatic be +posted to that newsgroup. +

 

+ +

Setup a newsgate via UUCP.

+

+With this setup you don't run a local newsserver, only your bbs users and +Fidonet links can then use news. You need to install uucp +on your system. With mbsetup menu 1.14 you need to set this +up. Suppose your ISP's nodename is xs4all the you probably need to set the +UUCP path to /var/spool/uucp/xs4all and the UUCP node to +xs4all. Your own nodename will be your system's hostname without +the domain part. +

+In each echomail area you want to gate you need to fill in the newsgroup +name of that area and echomail received in that area will automatic be +posted to that newsgroup. +

 

+ +

Setup a email gate.

+

+See Postfix (email) configuration +

+ +Back Go Back +

+ + + diff --git a/html/intro.html b/html/intro.html new file mode 100644 index 00000000..56443d68 --- /dev/null +++ b/html/intro.html @@ -0,0 +1,99 @@ + + + + + + + + +Running a BBS under Linux. + + + +
+
Last update 28-Jan-2001
+

 

+

Introduction to MBSE BBS.

+

+ +

Distribution.

+

+There are only five official distribution sites for the mbse bbs package. They are: +

    +
  1. http://mbse.sourceforge.net Primary site +
  2. http://mbse.freezer-burn.org Mirror site +
  3. http://www.telematique.org/mbse Mirror site +
  4. fidonet node 2:280/2802 (+31-255-515973). +
  5. fidonet node 2:280/2801 (+31-255-533858). +
+If you find mbse bbs on another site it may be out of date. I have no control over these sites. +New versions of mbse bbs are announced in the fidonet area LINUX_BBS. On the official fidonet +nodes you can request the latest version with the magic MBSEBBS. You will then get a zip file, +in this zip file is the original tar.gz file. This is to let systems who only support 8.3 +filenames to pickup the distribution package. You can also subscribe to the mailinglist +mbse-announce@lists.sourceforge.net to receive announcements. This will also work for fidonet +systems if you send your netmail via the official fido/internet gateway. You can also +subscribe online at sourceforge +

 

+ +

History.

+

+At the end of 1997 I was looking for several BBS systems that could run on +Linux and it must be capable to run Fidonet mail. After reviewing almost +all packages that were available at that time I found that there were no +packages that suited my needs. Some had the plain user interfaces that +my bbs users were used to but no Fidonet capabilities, others looked +awfull or were difficult to use by normal bbs users without Unix experience. +I also didn't want to run shareware anymore, one day you pay for some program, +and the next day support is over because the writer of that program decided +to stop development or simply dissapears from the Fidonet stage. With all +Y2K problems ahead the solution should be Open Software so that you have +the sources in case something goes wrong. +One package was very interesting and had the look and feel of RemoteAcces, +that package was RapidBBS. There was only one problem, it had no Fidonet +capabilities. I rewrote the data structures and created a deamon that should +control all bbs acivities. In march 1998 I started writing the mbfido program +that should handle all Fidonet mail and .tic files. In june 1998 the final +message base format became JAM using the LoraBBS sources as a guide to create +the JAM libraries. The original JAMapi was not stable enough to do all the work +that needed to be done. +

+In Juli 1998 the first version of MBSE BBS was installed on the bbs I have, +on the second line. The first line was running McMail, GEcho and RA on a +Novell client while on the Linux box the mars_nwe emulator from Martin Stower +was running. In november 1998 mbcico was created from ifcico from Eugene M. +Crosser. In Januari 1999 it did also compile and run on a Sun Sparcstation 2 +system. +

+In April 1999 the motherboard of the Linux server died, I replaced it with +the MOBO of one of the client machines. From that day on, MBSE BBS became the +only bbs running on my system, because I was short on serial port boards at +that time. McMail and RA became history and MBSE BBS was on its own. From that +day on, updates were almost daily, all users and up and downlinks showed that +there were plenty of bugs to solve. One month later most problems were solved. +

+In juli 1999 Jan van de Werken started beta testing MBSE BBS on his system. +In September 1999 MBSE BBS was public released for the first time. +

 

+ +

Is it Y2K ready?

+

+There have been no problems since 1 januari 2000 with MBSE BBS. I do run +pktdate by Tobias Ernst in the tosser, this solves problems with incoming +mail. Due to the internal date format, this program should run until 2038, +just as long as Unix/Linux and the internet will function without changing +the date format. +

 

+ +

Future plans.

+

+Plans are to complete integrate news, email, www and chat into MBSE BBS. It +should work for browsers about the same as with ANSI character terminals. +

 

+ + +Back Go Back +

+ + + diff --git a/html/invoking.html b/html/invoking.html new file mode 100644 index 00000000..f6c5ac7f --- /dev/null +++ b/html/invoking.html @@ -0,0 +1,70 @@ + + + + + + + + +Starting and stopping the BBS. + + + +
+
Last update 06-Jun-2001
+

 

+ +

Starting and Stopping the BBS.

+

+Now it is time to check the starting and stopping of the BBS. As you have +installed everything, setup the BBS etc, you must check if the shutdown and +reboot work properly. As root type shutdown -r now and +watch the console. You should see messages that the BBS is closing while +the systems shuts down. This should be one of the first things to happen. +Because Slackware up to version 7.0.0 is tricky to automatic install the shutdown scripts, +you won't see this happen on older Slackware versions. If you want, you can edit +/etc/rc.d/rc.6 and /etc/rc.d/rc.K and insert the line /opt/mbse/etc/rc.shutdown +at the proper places.

+ +When your system comes up again, one of the last messages before the login +prompt appears or just before X-windows starts, you should see messages that +the BBS is started.

+ +Login as user mbse and check the logfiles if everything looks +good. If something is wrong, reread the previous documentation and check if +you did everything right.

+ +Next logon to your BBS locally using the account "bbs". You will then create +the first user of your BBS, this will be you, the sysop of course. +After you logout the BBS start as user +mbse the program mbsetup and edit your user record +to set your level to that of the sysop. One more thing, the unix account you +must create when you logon as new BBS user may not be mbse +as this is the normal Admin account the BBS and its utilities use.

+ +Now login with your unix account and see if everything still works. After all +this and if you have setup mgetty you may want to test if +users really can login with a modem. Also check a mailer session, can you +dialout, ie. poll other nodes and can they call you. There is a lot that can +go wrong with unix permissions if you are not precise in wat you are doing.

+ +If everything is working it is time to create poll events, and adjust other +scripts to your local needs to get your BBS full up and running.

+ +To do this you must install a crontab for user mbse As user +mbse go to the directory ~/mbsebbs-0.33.xx. +In that directory type +sh ./CRON.sh and a default crontab will be installed.

+ +To add poll events, edit the crontab with the command crontab -e + At the bottom of that file there is an example of how to do that. +Now that the crontab is installed, all maintenance will now work, automatic +dialout, scanning and tossing mail etc. In other words, the bbs is up and +running. +

+ +Back Go Back +

+ + + diff --git a/html/known_bugs.html b/html/known_bugs.html new file mode 100644 index 00000000..56034619 --- /dev/null +++ b/html/known_bugs.html @@ -0,0 +1,37 @@ + + + + + + + + +Running a BBS under Linux. + + + +
+
Last update 28-Jan-2001
+

 

+

MBSE BBS - Known bugs.

+

+ +There are always more bugs, but these are known.... + +

    +
  • Reading of function keys in mbsebbs doesn't work always good, especially on +slow links and over PPP. + +
  • Memory leaks in mbfido during mailtoss. + +
  • Problems with D'Bridge [1a] mailers. + +
  • Sometimes binkp sessions hang on sending files during bidirectional transfers. + +
  • mbsetup crashes at several places if in system aka's the domain name is 12 characters long. +
+ +Back Go Back + + + diff --git a/html/license/copying.html b/html/license/copying.html new file mode 100644 index 00000000..ebf91634 --- /dev/null +++ b/html/license/copying.html @@ -0,0 +1,360 @@ + + +GNU General Public License. + + + + +
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, 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) 19yy  
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the 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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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.
+
+ +Back Go Back + + + + diff --git a/html/license/hydracom.html b/html/license/hydracom.html new file mode 100644 index 00000000..49a8a742 --- /dev/null +++ b/html/license/hydracom.html @@ -0,0 +1,120 @@ + + +Hydracom License. + + + + +
+                              HydraCom Version 1.00
+
+                         A sample implementation of the
+                   HYDRA Bi-Directional File Transfer Protocol
+
+                             HydraCom was written by
+                   Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT
+                  COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED
+
+                       The HYDRA protocol was designed by
+                 Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT and
+                             Joaquim H. Homrighausen
+                  COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED
+
+
+  DISCLAIMER
+
+  This program is provided "as is" and comes with no warranties of any
+  kind, either expressed or implied. In no event shall the authors be
+  liable to you or anyone else for any damages, including any lost
+  profits, lost savings or other incidental or consequential damages
+  arising out of the use or inability to use this software.
+
+
+  HYDRACOM / SOURCE LICENSE
+
+  HydraCom, its associated utilities (HydraCfg) and the HydraCom
+  sourcecode may be freely distributed, copied and used, no fee charged.
+  All files, executables and sourcecode remain the copyrighted property
+  of Arjen G. Lentz and LENTZ SOFTWARE-DEVELOPMENT.
+  The distribution archives should remain intact with no files removed
+  or modified. For special purposes, it is allowed to repack the
+  archives using a different compression system.
+
+  HydraCom may be bundled up with for instance terminal or BBS packages,
+  even commercial ones, provided the buyer/user is clearly informed
+  about the fact that Hydra and HydraCom are free, not owned by the
+  distributor/retailer in question, and is not included in any possible
+  charge regarding the rest of the package. This documentation must also
+  be present so the user can inform himself about Hydra and HydraCom.
+  The same rules apply to inclusion in shareware and CD-ROM libraries.
+  In all cases, the author of HydraCom must be given credit in any
+  informational screens and literature that contain such information.
+
+  The Hydra/HydraCom sourcecode may also be freely used and integrated
+  into other software or library, provided this is clearly stated in any
+  informational screens and literature pertaining to this program, and
+  credit is given to the original author. If the sourcecode of that
+  program or library is released or otherwise published, the notices
+  present at the top of every Hydra/HydraCom source file must be
+  retained in their original unmodified form.
+
+  In addition to the above license, everyone using any part of the
+  sourcecode, programs or files is fully bound by the general license of
+  the Hydra protocol as present in the Hydra protocol description
+  document. For easy reference, the paragraph in question is reprinted
+  below.
+
+  Any use of, or operation on (including copying/distributing) any of
+  the above mentioned files implies full and unconditional acceptance of
+  this license and disclaimer.
+
+
+  HYDRA PROTOCOL LICENSE 
+
+  You are granted a license to implement the HYDRA file transfer
+  protocol, HYDRA hereafter, in your own programs and/or use the sample
+  source code and adapt these to your particular situation and needs;
+  subject to the following conditions:
+
+   -  You must refer to it as the HYDRA file transfer protocol, and you
+      must give credit to the authors of HYDRA in any information
+      screens or literature pertaining to your programs that contains
+      other such information (credits, your own copyrights, etc.).
+
+   -  HYDRA will always remain backwards compatible with previous
+      revisions. HYDRA allows for expansion of its features without
+      interfering with previous revisions. It is, however, important
+      that different people do not expand the protocol in different
+      directions. We therefore ask you to contact us if you have any
+      needs/ideas regarding HYDRA, so development can be synchronized
+      and beneficial to all.
+
+   -  If your implementation cannot converse with past or future
+      revisions as supplied by us, then you must refer to it as "HYDRA
+      derived", or as "a variation of HYDRA", or words to that effect.
+
+
+  Hydra protocol design and HydraCom driver:         Hydra protocol design:
+  Arjen G. Lentz                                     Joaquim H. Homrighausen
+  LENTZ SOFTWARE-DEVELOPMENT                         389, route d'Arlon
+  Langegracht 7B                                     L-8011 Strassen
+  3811 BT  Amersfoort                                Luxembourg
+  The Netherlands
+  FidoNet 2:283/512, AINEX-BBS +31-33-633916         FidoNet 2:270/17
+  arjen_lentz@f512.n283.z2.fidonet.org               joho@ae.lu
+
+  Please feel free to contact us at any time to share your comments about our
+  software and/or licensing policies.
+
+ +Back Go Back + + + + diff --git a/html/license/index.htm b/html/license/index.htm new file mode 100644 index 00000000..eec8b7f2 --- /dev/null +++ b/html/license/index.htm @@ -0,0 +1,39 @@ + + + + + + + + +Licenses. + + + +
+
Last update 29-Jan-2001
+

 

+ +

Licenses.

+ +

Introduction

+

+This is an overview of the licenses that are valid for the use of MBSE BBS or +parts of it. +
+Michiel Broek. +

+ +

License Documents.

+ + + +IndexBack to Index +
+ + + diff --git a/html/license/jam.html b/html/license/jam.html new file mode 100644 index 00000000..80e415f9 --- /dev/null +++ b/html/license/jam.html @@ -0,0 +1,78 @@ + + +JAM License. + + + + +
+    ---------------------------------------------------------------------
+                                  JAM(mbp)
+                The Joaquim-Andrew-Mats Message Base Proposal
+    ---------------------------------------------------------------------
+            Copyright 1993 Joaquim Homrighausen, Andrew Milner,
+                           Mats Birch, Mats Wallin.
+                             ALL RIGHTS RESERVED.
+    ---------------------------------------------------------------------
+
+
+    =====================================================================
+    LEGAL NOTICE
+    ---------------------------------------------------------------------
+
+    The JAM(mbp) documentation and JAM API and information attached
+    hereto, hereafter referred to as JAM, is protected by applicable
+    copyright laws and international treaty provisions. JAM is provided
+    "as is", without warranty of any kind or fitness for a particular
+    purpose, either expressed or implied, all of are hereby explicitly
+    disclaimed. The authors only guarantees that JAM will occupy disk
+    space.
+
+    The entire risk as to the quality and performance of JAM is with you.
+    Should JAM prove defective or incorrect, you assume the entire cost
+    of all necessary servicing, repair, and/or correction. In no event
+    shall the authors be liable to the you or anyone else for any damages
+    or costs, including, but not limited to, any lost profits, lost
+    savings, lost income, lost information, loss of the right to use JAM,
+    or other incidental or consequential damages arising out of the use
+    or inability to use JAM.
+
+    All information provided in JAM is subject to change without further
+    notice.
+
+    JAM may be published and distributed to other people as long as no
+    part of it is modified by any means, this includes translation to
+    any other language (technical or social), and as long as no charges
+    are applied (including but not limited to trading). This information
+    may not be used to reverse engineer any application developed by the
+    authors.
+
+    All applications that support JAM must include one of the following
+    notices in their documentation and somewhere in the product's credit
+    section:
+
+    "JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner,
+                               Mats Birch, Mats Wallin.
+                               ALL RIGHTS RESERVED."
+
+    or
+
+    "This product uses the JAM(mbp) API -
+     Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch,
+                    Mats Wallin. ALL RIGHTS RESERVED."
+
+    All trademarks are trademarks or registered trademarks of their
+    respective holders.
+
+ +Back Go Back + + + + diff --git a/html/manual.css b/html/manual.css new file mode 100644 index 00000000..d9818384 --- /dev/null +++ b/html/manual.css @@ -0,0 +1,24 @@ +/* + * stylesheet for the MBSE BBS manual. + */ + + +BODY { background-color: white; font-family: Arial, Helvetica; font-size: 12pt; } + +/* + * H1 is the page header, H3 the paragraph header, H5 is topright update date. + */ +H1 { color: red; align: center; font-family: Arial, Helvetica; font-size: 16pt; font-weight: bold } +H2 { color: orange; align: center; font-family: Arial, Helvetica; font-size: 16pt; font-weight: bold } +H3 { color: black; margin-left: 40; font-family: Arial, Helvetica; font-size: 14pt; font-weight: bold } +H5 { color: black; align: right; font-family: Arial, Helvetica; font-size: 8pt; } + +A:link { color: blue } +A:visited { color: darkblue } +A:active { color: red } + +PRE { color: brown; font-family: fixed; } +CODE { color: brown; font-family: fixed; } +HR { border-top: solid medium navy } + + diff --git a/html/menus/control.html b/html/menus/control.html new file mode 100644 index 00000000..acc11d09 --- /dev/null +++ b/html/menus/control.html @@ -0,0 +1,127 @@ + + + + + + + + +MBSE BBS Menus - Control Codes in ANSI and ASCII files. + + + +
+
Last update 27-Jun-2001
+

 

+ +

MBSE BBS Control Codes in ANSI and ASCII files

+
+ + +

Single Control characters

+
+ Code      Description
+ ----      ---------------------------------------
+  A        Wait for a key
+  B        Print text above sec. level
+  F        Control-code F
+  K        Control-code K
+  P        Wait one second
+  U        Control-code U
+
+
+
+The control-B syntax is: ^B<seclevel>^B<The text to show>^B
+For example: ^B32000^BThis is the text^B
+

+ +

Control-F followed by:

+
+ Code      Description
+ ----      ---------------------------------------
+  !        Display transfer protocol
+  A        Number of uploads
+  B        Number of downloads
+  C        Downloads in Kilobytes
+  D        Uploads in Kilobytes
+  E        Download plus upload Kilobytes
+  F        Download Kilobyte limit
+  G        Last transfer time
+  H        Current file area number
+  I        Current file area description
+  J        Download files limit
+  K        Description of user limit
+
+
+
+

+ +

Control-K followed by:

+
+ Code      Description
+ ----      ---------------------------------------
+  A        Print date in format DD-MM-YYYY
+  B        Print time in HH:MM:SS
+  C        Print date in DD-Mmm
+  D        Print date in DD-Mmm-YYYY
+  E        Print locked port baudrate
+  F        Last caller
+  G        Total users in userlist
+  H        Number of system calls
+  I        Current message area number
+  J        Current message area description
+  K        Print random oneliner
+  L        Print number of messages in current area.
+  M        Print users LastRead pointer of current message area.
+  N        Print users current e-mail mailbox name.
+  O        Print number of messages in current e-mail box.
+  P        Print users LastRead pointer of current e-mail box.
+
+
+
+

+ +

Control-U followed by:

+
+ Code      Description
+ ----      ---------------------------------------
+  A        User's full name
+  B        User's location
+  C        User's voice phone
+  D        User's data phone
+  E        User's last login date
+  F        User's first login date
+  G        User's last login time
+  H        User's security level
+  I        User's total calls
+  J        User's time used today
+  K        User's connect time this session
+  L        User's time left today
+  M        User's screen length
+  N        User's first name
+  O        User's last name
+  P        User's graphics mode (On/Off)
+  Q        User's news bulletins (On/Off)
+  R        User's hot-keys (On/Off)
+  S        User's daily time limit
+  T        User's date of birth
+  U        User's messages posted
+  X        User's language
+  Y        User's handle
+  Z        User's do not disturb flag (On/Off)
+  1        User's check for new mail (On/Off)
+  2        User's check for new files (On/Off)
+  3        User's fullscreen editor (On/Off);
+
+
+
+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/index.htm b/html/menus/index.htm new file mode 100644 index 00000000..e9cf81d5 --- /dev/null +++ b/html/menus/index.htm @@ -0,0 +1,149 @@ + + + + + + + + +MBSE BBS Menu System. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS Menu System

+

Menus sections: +Global menus  +File areas  +Message areas  +User settings  +Onliners  +BBS lists  +ANSI Control Codes +

+

+


+

+ +

Introduction.

+

+One of the most powerfull features of the BBS is it's menu system. You +have complete control over each individual menu item which can be restricted +according to criteria such as security levels. +

 

+ +

ANSI Screens.

+

+For the menus to work properly you must also draw ANSI screens, this +is what the users will see. For Linux there is "Duh DRAW" written by Ben +Fowler, see sunsite.unc.edu /pub/Lunux/docs. +If you can't find it or have no internet access, you can also use +THEDRAW. This utility can be found on many BBS'es around the world. Unfortunatly +it is a DOS program so you will need dosemu on your Linux box or a seperate +DOS computer. You can define main screens and include screens for each +menu, the include screen may for example show the keys that you have available +in every menu. See the list of control codes. +

 

+ +

Automatic commands.

+

+A menu function is usually executed when a user presses the hot-key +assigned to that particular menu item. But menu functions can also be executed +automatically. Each menu item contains an AutoExec field. By default this +field is set to No, but by toggling it to Yes, the menu item can be made +to execute when it is played back (displayed) by the BBS.

+

+As you read through the menu function types outlined in this chapter, +you may come to realize that this is a very powerfull feature. For example, +when used with the menu function that displays a text file, you can design +very elaborate, graphical text file menus that you wouldn't normally be +able to display in a line-by-line menu.

+

+Automatic menu execution can be used in many other instances as well. +Just to give you some ideas, it might be used to display a text file to +users who have a security level equal to or greater than a certain level. +Yet another use is to execute multiple function menus which are used to +execute several functions when a single command is entered. +

 

+ +

Multiple languages.

+

+For each language you can define a set of menus. Only for the default +language all menus must exist. It makes sense to make the filenames of +your menus for each language the same and not to translate them. If a menu +is missing for a non default language, the menu from the default language +path is used. +

 

+ +

Editing a menu.

+

+The order of the menu lines in the setup is not important except for +the autoexec menus, they must be placed in the right order from start, +ie. begin with the menu specific screen display, then the global include +display and finally show the prompt. +

+ + +

    +
  1. Selection key. This is the key a user must press to activate +this menu. This field is ignored when AutoExec is set to Yes.
  2. + +
  3. Type nr. this is the menu type to execute. For a description +of all available types see below.
  4. + +
  5. Optional data. Some menus need optional data, for example the +function goto another menu needs the name of that menu file here.
  6. + +
  7. Display. What is to be displayed to the user. This field has +no meaning yet. What you want to diplay must be done with ANSI screens. +
  8. + +
  9. Security. This is the minimum security level to execute this +selection. The security is a level number combined with 32 bitmapped flags. +NOTE: level 0 and no flags means +everyone can select this menu. Good for logout options and all other options +everyone must be able to execute.
  10. + +
  11. Min. age. The minumum age the user must be to execute this selection. +You may want to restrict access to certain areas to users older than 18 +years. If you leave this to 0, every one can execute this menu.
  12. + +
  13. Max. lvl. The maximum level a user must have to execute this +menu. If you leave this at 0 then the maximum level has no effect.
  14. + +
  15. Password. You can protect the menu selection with a password. +If this field is empty, no password check is done.
  16. + +
  17. Credit. How much credit a user must have to execute this menu +selection. This field is not in use yet.
  18. + +
  19. Colors. The display color for the display line, not in use yet. +
  20. + +
  21. AutoExec. If this is an automatic executed selection.
  22. + +
  23. Menu open. Will be implemented later, you will be able to set +opening hours for this menu selection.
  24. +
  25. No door.sys Suppress writing of a door.sys file in the users +home directory. This item is only visible with menu type 7.
  26. +
  27. Y2K style Writes the dates in the door.sys file in the new style, +with 4 digit year numbers, else the old 2 digit style is used. This item +is only visible with menu type 7.
  28. +
+

 

+ +

Final warning.

+

+If a submenu is missing, the BBS falls back to the main menu. This menu +must be called "main" (or else set another name in the global +setup) or your BBS won't start and complain. Submenus may be nested 50 +levels deep. +

+ +Back Back +

+ + diff --git a/html/menus/menu0.html b/html/menus/menu0.html new file mode 100644 index 00000000..b7cb38a2 --- /dev/null +++ b/html/menus/menu0.html @@ -0,0 +1,176 @@ + + + + + + + + +MBSE BBS Menus - Global Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS Global Menus

+
+ +
    + +
  1. Goto another menu: This will start the execution + of another menu. The current menu level is not stored on the stack.
    + Optional data: The name of the new menu.
    +

    + +

  2. Gosub another menu: This will start the execution + of another menu. The current menu level is stored on the stack. Gosub's may + be nested 50 levels deep.
    + Optional data: The name of the new menu.
    +

    + +

  3. Return from Gosub: This will go back one + gosub level. If you are already at the top level nothing happens.
    + Optional data: None.
    +

    + +

  4. Return to top menu: Return to the top (main) + menu. The name of this menu is set in the global setup. + Default is main.mnu
    + Optional data: None.
    +

    + +

  5. Display .a?? file with controlcodes: This will + display an ANSI file to the user. If the user has Graphics No set + then the ASCII version is shown. Search is done first in the users language + path and if that fails the default language path is used. + Control codes in the + file are substituted with the current values the represent.
    + Optional data: The name of the file to display. Do not + give the filename extension!
    +

    + +

  6. Show menu prompt: Display the menu prompt.
    + Optional data: The prompt to display. This string may + contain some control characters that are replaced with information. The + prompt is displayed in White on Black and is hardcoded at the moment. +
      +
    • ~ This will insert the number of minutes the user + has left. +
    • @ This will insert the name of the current file area. +
    • ^ This will insert the name of the current message area. +
    • # This will insert the current local time. +
    +

    + +

  7. Run external program: This will execute + external programs.
    + Optional data: The full path and filename of the external + program. This can be a shell too. Look for a lot of programs, for example + if you want to give your users internet mail with elm, the user can get a + shell prompt by typing !/bin/sh. If you want this look for + anyway you might consider using a restricted shell.
    +

    + +

  8. Show product information: This will show + copyright information about MBSE BBS.
    + Optional data: None.
    +

    + +

  9. Display todays callers: This will display a + list of todays callers to the BBS.
    + Optional data: "/H" Show handles instead of real names.
    +

    + +

  10. Display userlist: Display all users in the + users database except those that are hidden.
    + Optional data: "/H" Show handles instead of real names.
    +

    + +

  11. Time statistics: Display the users time + statistics.
    + Optional data: None.
    +

    + +

  12. Page Sysop: Page sysop for a chat.
    + Optional data: A message to the user
    + The message to the user could be something like "Calling sysop, please + wait ..." or "I will see if Michiel wants to chat with you, please wait!" + As sysop you will know best what to put in that line. +

    + +

  13. Terminate call: Terminale this call and + hangup.
    + Optional data: None. +

    + +

  14. Make a log entry: This will write a line in + the logfile.
    + Optional data: The information you want in the logfile.
    +

    + +

  15. Print text to screen: Write text to the users + screen.
    + Optional data: The text that must appear on the users + screen. The @ character is replaced with a newline.
    +

    + +

  16. Who is online: Displays the who is online + list and what they are doing. Users that are hidden are not displayed.
    + Optional data: "/H" Show handles instead of real names.
    +

    + +

  17. Comment to sysop: Enter the texteditor and + let the user write a message to the sysop. The area is predefined in the + global setup.
    + Optional data: None.
    +

    + +

  18. Send online message: Send an online message + to a user on another line.
    + Optional data: "/H" Use handles instead of real names.
    +

    + +

  19. Display textfile with more: This will display + a textfile to the user. After each full screen the user is prompted with + More Y/n/=.
    + Optional data: The full path and filename to the file.
    +

    + +

  20. Display .a?? file with control codes and wait: + This will display a ANSI or ASCII file to the user with + control codes and wait for Enter when it is finished.
    + Optional data: The filename without extension of the + file to display.
    +

    + +

  21. Expert mode .a?? Not of any use anymore. + This one will be removed.
    + Optional data: The name of the file without extension + to display.
    +

    + +

  22. Nextuser door: This runs the message to next + user door.
    + Optional data: None.
    +

    + +

  23. Timebank door: This runs the time bank door.
    + Optional data: None.
    +

    + +

  24. Safe cracker door: This runs the Safe Cracker + door.
    + Optional data: None.
    +
+ +
+Index + Main Index  +Back + Menus Index +
+ + + diff --git a/html/menus/menu100.html b/html/menus/menu100.html new file mode 100644 index 00000000..95e18066 --- /dev/null +++ b/html/menus/menu100.html @@ -0,0 +1,147 @@ + + + + + + + + +MBSE BBS Menus - File Area Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS File Area Menus

+
+ +
    + +
  1. Select another area: This option will show + a list of available areas and let the user select a new area. If there is + optional data the new area will be selected without user intervention.
    + Optional data: If there is an option the area is direct + selected. Current options are: F+ goto next available area. + F- goto previous available area.
    +

    + +

  2. File List: This option will display a list + of files with their dates, sizes and description. During the display of the + list the user can select (Tag) files for later download.
    + Optional data: None.
    +

    + +

  3. View File: Not yet implemented.
    + Optional data: None.
    +

    + +

  4. Download File(s): This option will start to + transmit files to the user if he has tagged files for download. Tagging files + for download can be done during File List, Keyword Scan, Filename Scan or + Newfile Scan. If a user didn't select a transfer protocol before now he will be + forced to select a file transfer protocol.
    + Optional Data: None.
    +

    + +

  5. Raw Directory: This option will display the + contents of a directory in raw format.
    + Optional data: If the option is /F the + contents of the current directory is shown. If the option is the full path + to a directory, the contents of that directory is shown.
    +

    + +

  6. Keyword Scan: This option will search for + files in the files database for a matching keyword. The search is not case + sensitive. If there are files found the user is able to select (Tag) these + files for later download.
    + Optional data: None.
    +

    + +

  7. Filename Scan: This option will search for + a filename match in the files database. The search is not case sensitive. + If there are files found the user is able to select (Tag) these files for + later download.
    + Optional data: None.
    +

    + +

  8. Newfiles Scan: This option will scan for new + files available for download since the last time the user was online. As + option the user can change that date from which to start the search. Any files + found the user may select (Tag) for later download.
    + Optional data: None.
    +

    + +

  9. Upload: This option will let the user upload + files to the bbs. If the current area has an alternate upload area, the upload + will end up in that area. If the user uses X-modem or another ancient protocol + he will first be asked for a filename. Normal modern protocols don't need this. + The filename is checked before the transfer is done to protect the bbs. Further + the files the user will upload will at first be placed under the users home + directory ~/upl. After the upload(s) the files are checked + for virusses. If all is well, the file is imported in the bbs. If the file + contains a valid FILE_ID.DIZ file inside the archive, that file will be used + for the description of the upload, if not, the uploader will have to describe + the file.
    + Optional data: None.
    +

    + +

  10. Edit Taglist: This option is for the user to + edit the list of files he has tagged for later download.
    + Optional data: None.
    +

    + +

  11. View file in homedir: Not yet implemented.
    + Optional data: None.
    +

    + +

  12. Download Direct: Download a file direct.
    + Optional data: The full path and filename to the file to + download.
    +

    + +

  13. Copy file to Homedir: This option will copy + a file from a download directory to the users home directory. It will be + checked if the user has enough room in his directory, the default Quota for + users is 10 MBytes.
    + Optional data: None.
    +

    + +

  14. List Homedir: This option will list the files + in the users home directory.
    + Optional data: None.
    +

    + +

  15. Delete in Homedir: This option will let the + user delete one or more files from his home directory.
    + Optional data: None.
    +

    + +

  16. Unpack file in Homedir: Not yet implemented.
    + Optional data: None.
    +

    + +

  17. Pack files in Homedir: Not yet implemented.
    + Optional data: None.
    +

    + +

  18. Download Homedir: This option will let the + user download from his home directory.
    + Optional data: None.
    +

    + +

  19. Upload Homedir: This option will let the user + upload files to his home directory.
    + Optional data: None.
    +
+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/menu200.html b/html/menus/menu200.html new file mode 100644 index 00000000..ba4ca392 --- /dev/null +++ b/html/menus/menu200.html @@ -0,0 +1,138 @@ + + + + + + + + +MBSE BBS Menus - Message Area Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS Message Area Menus

+
+ +
    + +
  1. Select another area: This option will show + a list of all available areas and let the user select a new area. If there + is optional data the area will be selected without user intervention.
    + Optional data: If there is an option the area is direct + selected. Current options are M+ goto the next available + area. M- goto the previous available area.
    +

    + +

  2. Post a Message: This option lets the user + post a new message.
    + Optional data: None.
    +

    + +

  3. Read Messages: This option lets the user + read messages. If he has done that before in that area he will be suggested + to start after the message he has last read. During reading of messages + the user can reply to other messages.
    + Optional data: None.
    +

    + +

  4. Check for Mail: Check for new arrived mail.
    + Optional data: None.
    +

    + +

  5. Quickscan Messages: Make a quick overview + list of all messages in that area.
    + Optional data: None.
    +

    + +

  6. Delete a Message: This option will let the + user delete a specific message. He must the the owner or recipient of that + message or have sysop rights in that area to be able to delete a message.
    + Optional data: None.
    +

    + +

  7. Mail Status: This gives a complete overview + of all available mail at the bbs.
    + Optional data: None.
    +

    + +

  8. OLR: Tag Area: This option lets + the user tag one or more areas to be included in his offline mail packet.
    + Optional data: None.
    +

    + +

  9. OLR: Untag Area: This option lets + the user untag one or more areas not to be included in his offline mail + packet.
    + Optional data: None.
    +

    + +

  10. OLR: View Tags: This option lets + the user view which areas will be included in his offline mail packet.
    + Optional data: None.
    +

    + +

  11. OLR: Restrict Date: Not yet + implemented.
    + Optional data: None.
    +

    + +

  12. OLR: Upload Mail: Let the user upload + mail or a new offline reader setup. The packet format is automatic detected. + Currently BlueWave is supported. QWK support will be added later.
    + Optional data: None.
    +

    + +

  13. OLR: Download BlueWave: Download mail in + BlueWave version 2 format.
    + Optional data: None.
    +

    + +

  14. OLR: Download QWK: Download mail in QWK + format.
    + Optional data: None.
    +

    + +

  15. OLR: Download ASCII: Download mail in flat + ASCII format. Not yet implemented.
    + Optional data: None.
    +

    + +

  16. Read Email Read users private email.
    + Optional data: None.
    +

    + +

  17. Write Email Post an email message.
    + Optional data: None.
    +

    + +

  18. Trash Email Put email in the trashcan. + Not Yet implemented.
    + Optional data: None.
    +

    + +

  19. Choose Mailbox Choose another private + mailbox. Valid boxes are: mailbox (normal in/out), archive and trash.
    + Optional data: If there is an option the area is direct + selected. Current options are M+ goto the next mailbox. + M- goto the previous mailbox.
    +

    + +

  20. Quickscan Email Make a quick overview + list of all messages in the selected e-mail area.
    + Optional data: None.
    +

    +

+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/menu300.html b/html/menus/menu300.html new file mode 100644 index 00000000..3fd35ae1 --- /dev/null +++ b/html/menus/menu300.html @@ -0,0 +1,99 @@ + + + + + + + + +MBSE BBS Menus - User Settings Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS User Settings Menus

+
+ +
    + +
  1. Change Transfer Protocol: Let the user + select a new file transfer protocol.
    + Optional data: None.
    +

    + +

  2. Change Password: Let the user change + his FidoNet password.
    + Optional data: None.
    +

    + +

  3. Change Location: Let the user change + his location.
    + Optional data: None.
    +

    + +

  4. Change Graphics: Let the user toggle + graphics mode on or off.
    + Optional data: None.
    +

    + +

  5. Change Voicephone: Let the user change + his voice phonenumber.
    + Optional data: None.
    +

    + +

  6. Change Dataphone: Let the user change + his data phonenumber.
    + Optional data: None.
    +

    + +

  7. Change Expertmode: This command will be + removed.
    + Optional data: None.
    +

    + +

  8. Change Scrennlength: This command will + let the user set a new screenlength, the default is 24.
    + Optional data: None.
    +

    + +

  9. Change Date of Birth: Let the user set a + new date of birth. Check's are done if the date is more or less realistic. + This command should not be made available users if you use the regular + date of birth validation check.
    + Optional data: None.
    +

    + +

  10. Change Language: Let the user select a new + default language.
    + Optional data: None.
    +

    + +

  11. Change Hotkeys: Let the user toggle the + use of Hotkeys on or off..
    + Optional data: None.
    +

    + +

  12. Change Handle: Let the user select a new + handle (nickname).
    + Optional data: None.
    +

    + +

  13. Change Don't Disturb: Let the user toggle + the "do not disturb" flag.
    + Optional data: None.
    +

    + +

+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/menu400.html b/html/menus/menu400.html new file mode 100644 index 00000000..68b341a9 --- /dev/null +++ b/html/menus/menu400.html @@ -0,0 +1,60 @@ + + + + + + + + +MBSE BBS Menus - Oneliner Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS Oneliner Menus

+
+ +
    + +
  1. Oneliner Add: Let the user add a new + oneliner.
    + Optional data: None.
    +

    + +

  2. Oneliner List: Let the user list all the + available oneliners.
    + Optional data: None.
    +

    + +

  3. Oneliner Show: Let the user show a + specific oneliner.
    + Optional data: None.
    +

    + +

  4. Oneliner Delete: Let the user delete a + oneliner. In order to do so he must be the owner of that oneliner or + he must have sysop access level. The oneliner is not really removed, only + marked for deletion.
    + Optional data: None.
    +

    + +

  5. Oneliner Print: Show a random chosen + oneliner on the screen. If you make this command automatic, each time that + this menu is executed a new oneliner will popup.
    + Optional data: None.
    +

    + +

+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/menu500.html b/html/menus/menu500.html new file mode 100644 index 00000000..bc2972b9 --- /dev/null +++ b/html/menus/menu500.html @@ -0,0 +1,56 @@ + + + + + + + + +MBSE BBS Menus - BBS List Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS BBS List Menus

+
+ +
    + +
  1. Add a BBS: Let the user add a BBS to the + BBS advertising database.
    + Optional data: None.
    +

    + +

  2. List BBS'es: Show a list of BBS'es in the + BBS database.
    + Optional data: None.
    +

    + +

  3. Show BBS: Show a specific BBS.
    + Optional data: None.
    +

    + +

  4. Delete BBS: Delete a specific BBS. The BBS + must have been entered by the user or the user must have sysop rights to + be able to delete a BBS.
    + Optional data: None.
    +

    + +

  5. Search BBS: Search for a specific BBS.
    + Optional data: None.
    +

    + +

+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/mgetty.html b/html/mgetty.html new file mode 100644 index 00000000..0b7e6c23 --- /dev/null +++ b/html/mgetty.html @@ -0,0 +1,172 @@ + + + + + + + + +Setup mgetty for MBSE BBS. + + + +
+
Last update 29-Jan-2001
+

 

+ +

Setup mgetty for MBSE BBS

+

+To handle incoming calls you can use mgetty written by +Gert Doering, (gert@greenie.muc.de). Others may work. You have to compile +mgetty with the -DFIDO flag to accept Fidonet mailer calls. +If you want incoming PPP calls as well, add the -DAUTO_PPP as well. Below +you can see the mgetty.config and login.config for mgetty that I use. I +have also included a part of my /etc/inittab to show how mgetty + will spawn from init. +

+ +


+
+# inittab       This is only a part of my /etc/inittab!
+#               In this example it runs in runlevel 3 and 4.
+#
+# Serial lines
+s1:34:respawn:/usr/local/sbin/mgetty -i /opt/mbse/etc/issue ttyS0
+#
+# End of /etc/inittab
+
+
+
+# mgetty configuration file: mgetty.config
+#
+# ----- global section -----
+#
+# In this section, you put the global defaults, per-port stuff is below
+#
+# set the global debug level to "4" (default from policy.h)
+debug 4
+#
+# set the local fax station id
+fax-id ++31-255-515973
+#
+# access the modem(s) with 38400 bps
+speed 38400
+#
+#  use these options to make the /dev/tty-device owned by "uucp.uucp" 
+#  and mode "rw-rw-r--" (0664). *LEADING ZERO NEEDED!*
+port-owner uucp
+port-group uucp
+port-mode 0664
+#
+#  use these options to make incoming faxes owned by "root.uucp" 
+#  and mode "rw-r-----" (0640). *LEADING ZERO NEEDED!*
+fax-owner root
+fax-group uucp
+fax-mode 0640
+#
+#
+# ----- port specific section -----
+# 
+# Here you can put things that are valid only for one line, not the others
+#
+# Dynalink 1428EXTRA faxmodem at port 0 (COM1).
+#
+port ttyS0
+speed 57600
+switchbd 19200
+modem-type cls2
+init-chat "" \d\dAT&F&C1&D3X4W2B0M0Q0V1H0&K3S0=0 OK
+#
+# end of mgetty.config
+
+
+
+# login.config
+#
+# This is a sample "login dispatcher" configuration file for mgetty
+#
+# Format:
+#	username userid utmp_entry login_program [arguments]
+#
+# Meaning:
+#       for a "username" entered at mgettys login: prompt, call
+#	"login_program" with [arguments], with the uid set to "userid",
+#	and a USER_PROCESS utmp entry with ut_user = "utmp_entry"
+#
+#
+# Use this one for fido calls (login name /FIDO/ is handled specially)
+#
+#  mgetty has to be compiled with "-DFIDO", otherwise a fido call won't
+#  be detected.
+#
+/FIDO/	mbse	fido	/opt/mbse/bin/mbcico @
+#
+#
+# Automatic PPP startup on receipt of LCP configure request (AutoPPP).
+#  mgetty has to be compiled with "-DAUTO_PPP" for this to work.
+#  Warning: Case is significant, AUTOPPP or autoppp won't work!
+#  Consult the "pppd" man page to find pppd options that work for you.
+#  See also PPP-HOWTO on how to set this up.
+#
+/AutoPPP/ -	a_ppp	/etc/ppp/paplogin
+#
+# This is the "standard" behaviour - *dont* set a userid or utmp
+#  entry here, otherwise /bin/login will fail!
+#  This entry isn't really necessary: if it's missing, the built-in
+#  default will do exactly this.
+#
+*	-	-	/bin/login @
+#
+# You might use this instead, it will directly start the BBS when the call
+# is not a PPP call and not a Fidonet mailer. Use only one of these two!
+# THIS IS NOT YET TESTED!
+#
+*	-	-	/opt/mbse/bin/mbsebbs
+#
+# end of login.config
+
+
+ +

+If you use /bin/login the users can get confused by the Unix login prompt. +Most of them are used to DOS based bbs systems and will try to login with +two names which won't work of course. For this reason I have added the +-i /opt/mbse/etc/issue options to the mgetty +line in /etc/inittab. The file /opt/mbse/etc/issue is a plain textfile +explaining users how to login to start the bbs. It could look like this:
+

+
+      .--.     Welcome at MBSE BBS Development.
+     |o_o |    --------------------------------
+     |:_/ |
+    //   \ \   This may or may not work today...
+   (|     | )
+  /'\_   _/`\
+  \___)=(___/  
+Powered by Linux.
+
+To start the bbs login with "bbs" without quotes.
+Voor het bbs login met "bbs" zonder aanhalingstekens.
+
+There is a default /opt/mbse/etc/issue installed by the installation script. +You need to edit this to insert your bbs name in it or even completely replace +this file for a nicer one. Don't make it too big, don't put control characters +in it as this may prevent some mailers to connect to your system. +

+I discovered that some systems don't have the right permissions on the serial +port for MBSE BBS. To fix this type the following commands: +

+su
+password: enter root password here
+chmod 666 /dev/ttyS0
+chown uucp.uucp /dev/ttyS0
+exit
+
+Note that /dev/ttyS0 is for COM1, /dev/ttyS1 for COM2 etc. +

+ +Back Go Back +

+ + + diff --git a/html/misc/dropfile.html b/html/misc/dropfile.html new file mode 100644 index 00000000..f4e86ebc --- /dev/null +++ b/html/misc/dropfile.html @@ -0,0 +1,117 @@ + + + + + + + + +BBS doors dropfiles. + + + +
+
Last update 02-Feb-2001
+

 

+ +

BBS doors dropfiles.

+

+ +

Dropfiles for Unix BBS systems.

+

+Not all options that are available under DOS or OS/2 can be used with Unix +BBS systems and must be faked. +

 

+ +

DOOR.SYS format.

+

+The door.sys format is a 52 lines ascii textfile, each line is terminated with +a cr/lf pair. In the setup it is possible to force the creation of MM-DD-YYYY +dates instead of the MM-DD-YY style. Newer doors sometimes need that. +

+Line	Description
+-----	-----------------------------------------------------------------
+1	Port, 2 characters in DOS format, p.e. COM1
+2	Effective Baudrate
+3	Databits
+4	Nodenumber, 1..9999
+5	Locked baudrate
+6	Screen display, Y=snoop on, N=snoop off. On Linux allways N.
+7	Printer Y=on N=off
+8	Page Bell Y=on N=off
+9	Caller alarm Y=on N=off
+10	Users first name and lastname
+11	Users location
+12	Voice/Home phone
+13	Work/Dataphone
+14	Password, empty if not available (stored coded).
+15	Security level, 0..32768
+16	Users number of calls
+17	Users last call date MM-DD-YY
+18	Seconds remaining this call
+19	Time left in minutes
+20	ANSI, "GR" is yes, otherwise ?
+21	Screen length
+22	User mode, always N
+23	Always blank
+24	Always blank
+25	Subscription expire date MM-DD-YY
+26	Users record number
+27	Default protocol
+28	Users total number of uploads
+29	Users total number of downloads
+30	Users daily download kilobytes total
+31	Daily download kilobyte limit
+32	Users date of birth MM-DD-YY
+33	Path to users database files   Cannot be used on Linux.
+34	Path to message database files
+35	Sysop first and last name
+36	Users handle
+37	Next event starting time or "none"
+38	Error-free connection Y=Yes or N=No
+39	Always set to N
+40	Always set to Y
+41	Text color as defined in setup 7 = gray.
+42	Always 0
+43	Last new files scan date MM-DD-YY
+44	Time of this call HH:MM
+45	Time of last call HH:MM
+46	Always set to 32768
+47	Number of files downloaded today
+48	Total kilobytes uploaded
+49	Total kilobytes downloaded
+50	Comment stored in users record
+51	Always set to 0
+52	Total number of messages posted
+
+

 

+ +

DORINFOn.DEF dropfile.

+

+The DORINFOn.DEF file is a 12 lines ascii textfile, each line terminated with +a cr/lf pair. All characters in the file are uppercase. The n in the filename +represents the current line number and will be between 1 and 9. Using number +1 seems always fine. +

+Line	Description
+------	------------------------------------------------------------------
+1	System name
+2	Sysop's first name
+3	Sysop's last name
+4	Port name, like COM1, COM2 etc. COM0 = local
+5	Baudrate format: "19200 BAUD-R,N,8,1"
+6	Always 0
+7	Users firstname
+8	Users lastname
+9	Users location
+10	Graphics mode: 0=no, 1=ANSI, 2=Avatar, 3=ANSI+Avatar
+11	Security level, 0..32767
+12	Time left in minutes
+
+

+ +Back Go Back +

+ + + diff --git a/html/misc/filefind.html b/html/misc/filefind.html new file mode 100644 index 00000000..a76c38ff --- /dev/null +++ b/html/misc/filefind.html @@ -0,0 +1,331 @@ + + +Implementation and Usage of FileFind Utilities. + + + + +
+ Document:   fsc-00xx
+ Version:    0.6
+ Date        Aug 30, 1995
+ Title:      Implementation and Usage of FileFind Utilities
+ Authors:    Robert Williamson FidoNet#1:167/104.0  robert@ecs.mtlnet.org
+
+  Intro
+
+    A portion of the document is derived from information in
+      AllFix.DOC by Harald Harms @ 2:281/910
+    with  additional  sections  from
+      FQuery.DOC by Robert Williamson @ 1:167/104
+
+        The  MSdos program ALLFIX by Harald Harms first introduced the idea
+    of searching for files via echomail.  The term applied to this function
+    is  'FileFind'.   A FileFind system allows sysops, points and BBS users
+    to  search  for  files  by  placing  a  message  to 'ALLFIX' in an echo
+    designated  for  the purpose of finding files.  All FTN sites running a
+    FileFind  processor which is configured to scan that echo will reply to
+    that  user if there any files matching his query.  This system provides
+    a  method  for  searching  many  FTN sites throughout the world, with a
+    single message.
+
+        FileFind  programs  work by either scanning through defined message
+    bases or scanning packets for defined AREA tagnames for messages to the
+    default  name  ALLFIX.   All FileFind programs MUST respond to the name
+    ALLFIX,  but  may also respond to the name FILEFIND and the name of the
+    particular  FileFind  program  in  use  or  defined  for the echo.  The
+    FileFind  program  will  process  these messages, examining the Subject
+    field  for  search  queries.  If any valid query is found, the FileFind
+    program  will  search  the  sites files database for files matching the
+    users's query.
+
+        If the FileFind program finds any matches, it will generate a reply
+    containing  a list of the files found, and some basic information ABOUT
+    the  system  posting  the reply.  When the user who initially wrote the
+    request  reads  the reply, he will then be able to decide if any of the
+    reported  files  meet  his  needs,  and  from the ABOUT included in the
+    reply, learn where and how he may get those files.
+
+
+  FileFind Query Message Structure
+
+    To: name_of_FileFind program
+
+    The  message  must be addressed to ALLFIX so that all FileFind programs
+    can  respond.   To  use  features  specific  to  a  particular FileFind
+    program,  or  to  limit  the  responses  to  a particular platform, the
+    message  should  be  addressed  to  that program's name.  Some FileFind
+    programs  will  respond  to more than two names.
+
+    Subject:
+    A  space-separated  list  of  file  specifications,  keywords or quoted
+    strings.
+
+    keyword     - single word preceeded by a '/' with no intervening spaces,
+                  must be at least 3 characters, not including the '/'.
+                  a keyword search is in actually a substring search of the
+                  site's filelist.
+
+    description - string enclosed in double-quotes,
+                  if a single word, must be more than 3 characters.
+
+    filespec    - single word, no spaces, no double-quotes or preceding /,
+                  must be at least 3 characters, not including any wildcard
+                  or pattern matching charcaters, such as '*'.
+                  Messages addressed to ALLFIX must not have any embedded
+                  pattern matching characters.
+
+
+        The  minimum  number  of  characters  for  description, keyword and
+    filespec  queries  is an implementation detail of the FileFind program.
+    These  values  should  be configurable, but should never be settable to
+    values of less than 3.
+
+        Each  implementation  should  allow  the  operator  the  ability to
+    configure a list of disallowed keywords.
+
+  NetMail Queries
+
+        Some  FileFind  programs  may also have the ability to process file
+    search  queries  received  as  netmail and addressed to the name of the
+    particular  FileFInd  program  with this capability.  In this case, all
+    replies are via netmail also.
+
+  NetMail Commands
+        FileFind   Netmail   commands  are  identifed  by  a  leading  '%'.
+    Implementation  of  netmail  commands  is  optional.   If  implemented,
+    compliant  FileFind  utilities  should be able to process the following
+    minimum NetMail command set.
+
+
+    %HELP       - netmail only, returns an extended help text for the
+                  FileFind program, the ABOUT of the the site and a list
+                  of MAGIC freqable names.
+    %ABOUT      - netmail only, returns the ABOUT of the site and a full
+ or %MAGIC        list of MAGIC names.
+
+    %NEWFILES   - netmail only, returns the NEWFILES list of the site
+ or %NEW          via netmail.
+
+    Extended NetMail Commands:
+        Implementation  of  the  following netmail commands is optional and
+    not required for compliance with the FileFind NetMail Command set.
+
+    %REPORT 
+                - sends a configuration report for echo 
+                  this allows an echo moderator to check if a site running
+                  a  FileFind  utility  is  compliant with the rules of the
+                  filefind echo.
+
+    %REQUEST 
+                - if found, will place requested file on hold for remote
+                  site
+
+    %UUREQUEST 
+                - if  found,  and  the filesize after uuencoding is less
+                  than 60K, it will be sent as multiple netmail messages
+
+
+  The Site ABOUT
+
+        Obviously,  a  system that neither accepts file requests nor allows
+    users  to  download  on  their  first  call should not be responding to
+    FileFind  messages.   If  there  are  any limitations for the caller to
+    acquire  any  of  the  files  that  the  site  has  advertised as being
+    available  in  it's FileFind response, these limitations MUST be listed
+    in  the  reply.   This information should be included in the ABOUT file
+    that the FileFind program user creates.
+
+        The  site  ABOUT  should  contain  the  following information.  The
+    FileFind  program  implementor  should  instruct  his  users  on  these
+    requirements.
+
+      - sitename
+      - site operator's name
+      - complete phonenumber
+      - baud rate
+      - hours during which filerequests are accepted, if at all
+      - hours during which users can download
+      - conditions for file requests and user downloads
+      NOTE: the above information should be within the first 14 lines.
+      optional:
+      - a list a MAGIC names
+      - an indication if magic names are also available to terminal users.
+
+  Searching for Files and Creating Replies
+
+        The  method  used by the FileFind program to search for requests is
+    up  to  the  implementor.   However,  if searching a list, the FileFind
+    program should confirm the actual existance of all files that match the
+    query specification.
+
+        The  FileFind  program  should  only  process  description strings,
+    filespecs  or  keywords  that  contain more than 3 valid characters and
+    should  have configuration options to define greater minimum lengths on
+    a per-echo basis.
+
+        For  filespecs,  the  wildcard  character '*' IS considered a valid
+    specification  as  well  as the '?' wildcard, but only the '?' is to be
+    counted  as  a  character  when  determining the length of query.  File
+    extensions  are  not necessary and any characters AFTER a '*' are to be
+    ignored.   The  FileFind  program should be configurable so as to allow
+    replacement  all  of the file extensions with '.*' or '#?' dependant on
+    platform.   This  results  in  queries being independant of the various
+    archivers in use.
+
+    Replies
+
+        Replies  created  by  FileFind  utilities  are  expected  to  be in
+    compliance with the following FTN specifications:
+        FTS-0001    -  packed message format
+        FTS-0009    -  MSGID/REPLY
+        FSC-0046    -  PID and tear line
+
+        In  addition, a FileFind utility may use the FID:  control line for
+    any  information needed that cannot be put in a PID:  without violating
+    that specification.
+
+        ^AFID: ascii text CR
+
+    Must be less than 80 characters including ^A and terminating CR.
+
+    There  are three ways in which the FileFind program can create replies:
+        - write the replies in the echo in which the query appeared.
+        - write the replies in an echo that has been specifically
+          designated for that purpose in the particular FTN or for
+          a gorup of echos in that FTN.
+        - reply via routed netmail.
+
+        Since each FTN site connected to a particular FileFind program area
+    is  capable  of creating an information reply, there is much concern as
+    to  the  amount  of  traffic  that  can  be generated, FileFind program
+    developers  must  be sensitive to these concerns by providing the means
+    to  their users to limit the traffic on a per-echo basis.  For example,
+    various  FileFind  echos  have  rules  limiting  the  size or number of
+    replies,  or  the length of the system information that may be included
+    in a reply.
+
+  Limiting replies
+
+    It is strongly suggested that some default limitations be built-in.
+
+    Limiting Site Header (ABOUT):
+
+        If the site's ABOUT, (the text that has been configured in order to
+    add  the  system's  information  and Magic names list to the reply), is
+    greater  than  14  lines,  the  remainder should NOT be posted.  A line
+    should  be  added  to  the response indicated this, and the user may be
+    invited to either Freq or download the MAGIC name's ABOUT or MAGIC, for
+    a  full  list of magic names.  The FileFind program may optionally send
+    the full system information and magic name list via routed netmail.
+
+    Limiting Match List due to ambiguity of query:
+
+        If  the list of matches (note:  not the size of the message itself)
+    is  greater than 32K, the FileFind program should post a message to the
+    user to indicate that his query may have been too ambiguous and perhaps
+    invite him to freq or download the MAGIC name FILES for a full list.
+
+    Splitting Match List into Multiple Messages:
+
+        If the list of matches is greater than 10K, it should be split into
+    multiple  messages  of  no more than 8K.  Although the backbone permits
+    messages  up  to  16K  in length, 8K is a more readable size.  Only the
+    first  split  message  may  contain  the ABOUT information of the site.
+    Each  message must be given both a unique Subject field (eg:  prepended
+    by  "Part n/n") and a unique MSGID:.  This because some tossers may use
+    either or both for dupe detection.
+
+    Limiting Number of Split Messages:
+
+        If  the  number of messages is greater than the preset limit of the
+    echo,  and  the FileFind Program does not have an option to forward the
+    replies  via  netmail,  the  replies  should  be discarded and the user
+    informed that his request may have been too amibiguous.
+
+
+    NetMail Reply:
+
+        The  FileFind program may have an option to forward all replies via
+    routed netmail, or to do so under certain conditions as outlined above.
+    Obviously, if the FileFind program can process netmail queries, it MUST
+    respond via netmail.
+
+    User NetMail Reply Request:
+
+        Alternativly the user can request a netmail reply for his echomail
+    query by preceeding the query with either "%" or "!".
+      eg;
+        Subject:  % /fsc /fts
+
+        If  the  FileFind  program  does  not support this feature, it must
+    ignore  any  echomail  query message that has a "%" or "!" as the first
+    WORD of the Subject field.
+
+    Second Reply or Extended Response Request:
+
+        The  FileFind  site  indicates  availablility  of  Second  Reply by
+    placing the string 'program_name 4d_address' in the From:  field of the
+    message.
+        eg: FROM: FQUERY 1:167/104.0
+
+        When a user replies to a FileFind reply, the message will be to the
+    FileFind  program  @  {network  address}.  When processing the FileFind
+    conferences, the FileFind program will treat any message to itself that
+    includes the site address as a Second Reply Request.
+
+        If  this feature is available, the FileFind program will include up
+    to  a maximum of 15 files (maximum 12K match list) in it's replies.  If
+    the  user  wants  a  more  detailed  listing,  he simply replies to the
+    FileFind  program's  reply.   Only  the system that posted the original
+    reply  will  respond to that new request.  This second, specific reply,
+    will  contain  up  to  50  files (32K of matchlist) either including or
+    SKIPPING the first 15.  These numbers may be replaced by byte limits in
+    some implementations.
+
+    No Second Reply in Designated Reply Echo:
+
+        The Designated Reply Echo method does not allow replies to be made,
+    because  the FileFind program may not be permitted to scan a Designated
+    Reply  Echo.  The FileFind program should automatically report up to 50
+    files  for any requests.  Therefore, the traffic limitaion features may
+    be  disabled for networks that require the FileFind program to reply in
+    a Designated Reply Echo, and disallow Second Reply in that echo.
+
+    Disable Local Messages:
+
+        The  FileFind  program must be able to to disable the processing of
+    local  messages.  What this means is that the FileFind program will not
+    process  any messages generated on that FTN site, including messages by
+    the  sysop  using  an  offline  reader,  or by a site's BBS or off-line
+    reader users.  This should NOT exclude messages from a site's points.
+
+
+    Limit by Age:
+
+        The  FileFind program must be configurable so that the operator can
+    limit  the  age  of an query message that is acceptable for processing.
+    This  should  be  in  number  of  days.   The  FileFind  program may be
+    configured  to  process all the FileFind requests regardless of how old
+    they are.  Age should never be greater than 365 days.
+
+    LinkMGR Support:
+        Implmentors  may choose to support the LinkMGR proposal for netmail
+    queries  and  commands.   In this proposal, the queries and commands do
+    not  appear  in  the  subject  field but rather, in the the BODY of the
+    message.  The subject field wil contain the LinkMGR password.
+        Use of the LinkMGR method allows the user to send multiple commands
+    to the fIleFind program.
+
+ +Back Go Back + + + + diff --git a/html/misc/fileid.html b/html/misc/fileid.html new file mode 100644 index 00000000..2c413751 --- /dev/null +++ b/html/misc/fileid.html @@ -0,0 +1,386 @@ + + +FILE_ID.DIZ Information. + + + + +
+FILEID.TXT v1.8 by Richard Holler [CIS 73567,1547]
+Last Revision 05/05/94
+
+This text file was prepared at the request of the ASP (Association of 
+Shareware Professionals), but the information contained in it may be of 
+value to any shareware author.
+
+
+FILE_ID.DIZ INFORMATION
+-----------------------
+Basically, the FILE_ID.DIZ file is a straight ASCII text file, distributed 
+inside your distribution archive file along with your program files, which 
+contains a description of your program. This file will be used by most BBS 
+(Bulletin Board System) softwares for the online file description of your 
+file. We recommend that the FILE_ID.DIZ file be used in all of your 
+distribution archives. 
+
+This text file contains a description of the FILE_ID.DIZ file, as well as a 
+description of the recommended distribution archive format.
+
+
+WHY SHOULD YOU USE FILE_ID.DIZ?
+-------------------------------
+The use of this file will insure that the online description of your 
+program will be in your own words (and who better to describe your program 
+than yourself?), and that it will remain the same no matter how many 
+different people upload your file to various BBS systems. 
+
+As more and more BBS software makes use of this file, you can be assured 
+that your own description will replace such online descriptions as "Cool 
+Program" or "OK utility, but needs better ..."
+
+Please note that the ASP Hub Network, the Author Direct FDN (File 
+Distribution Network), and the majority of other electronic distribution 
+services *REQUIRE* that a valid FILE_ID.DIZ file be contained in your 
+submitted distribution archive. If your file doesn't contain a valid 
+FILE_ID.DIZ file, then it simply won't be distributed by these services. 
+Furthermore, most BBS sysops will not accept uploads of files which do not 
+contain a valid FILE_ID.DIZ file, so you automatically lose out on that 
+distribution as well.
+
+
+DESCRIPTION:
+------------
+FILE_ID.DIZ was created by Clark Development for use with their PCBDescribe 
+utility, as a means for BBS callers to upload a file without having to 
+manually type in a file description. It also ensures that the online 
+description is always the same regardless of the number of different BBS 
+systems the file is posted on. It has since been accepted by the BBS 
+industry more-or-less as the "standard" file description source. (The 
+extension of "DIZ" actually stands for "Description In Zip").
+
+NOTE: The FILE_ID.DIZ file *MUST* be named exactly that, and *NOT* 
+something like .DIZ. It will *ONLY* be used if it is named 
+FILE_ID.DIZ!
+
+The FILE_ID.DIZ file is nothing more than a straight ASCII text file which 
+contains the full description of the archived file containing it. It is 
+used by most popular BBS software to describe your program, rather than 
+using the description supplied by the person that uploaded your file. It 
+should be placed *INSIDE* your distribution archive file.
+
+The BBS software will "look" inside the archive file. If a FILE_ID.DIZ file 
+is found, it will replace any existing online file description with the 
+text contained in FILE_ID.DIZ. It is an excellent method for making sure 
+that your program files are described the way that "you" want them 
+described. Even sysops who's software can't automatically make use of the 
+FILE_ID.DIZ file have found it to be an excellent source for their manually 
+added file descriptions.
+
+
+STRUCTURE:
+----------
+The file consists of straight ASCII text, up to 10 lines of text, each line 
+being no more than 45 characters long. It should *NOT* contain any blank 
+lines, any form of centering or formatting, or any Hi-ASCII or ANSI 
+characters. (i.e. it should ONLY contain alpha & numeric characters).
+
+We recommended that it consist of 5 basic parts:
+
+   1. the proper name of your program
+   2. the version number
+   3. the "ASP" identifier (optional, for ASP members)
+   4. the description separator
+   4. the description
+
+All of the above parts should be separated by a single "space".
+
+PROGRAM NAME: To set it apart from the rest, it is recommended that you use 
+ALL CAPS for the program name.
+
+VERSION NUMBER: The version number should be in the form of "v12.34". 
+
+ASP IDENTIFIER: If you are an ASP author, we recommend that an "" 
+identifying mark be added after the version number, to identify your 
+product as an ASP-authored product.
+
+DESCRIPTION SEPARATOR: To separate the actual description text, insert a 
+simple "-" (dash/minus) character after the ASP identifier (or version 
+number, if not using the ASP identifier), and in front of the description 
+text.
+
+DESCRIPTION: You should attempt to FULLY describe your product, including 
+its most important functions and features. Be sure to include anything 
+which will separate your program from it's competition, and make the BBS 
+user want to download your file. Also try to include any hardware or 
+software requirements that your product may have.
+
+You should try to use the first 2 lines of the text to give a basic 
+description of your program. This is helpful for sysops who's BBS software 
+limits them to less than 10 lines, 45 characters. Sysops who are limited to 
+using shorter descriptions can simply use the 1st two lines and truncate 
+the rest. Thus, you can basically still supply your own description for BBS 
+software which does not actually utilize the FILE_ID.DIZ feature.
+
+The remaining lines of text can be used to elaborate on the programs 
+features, enhancements from the prior version, information concerning 
+multi-file sets. Please note that older versions of some BBS software can 
+only use 8 lines of text. It is advisable that you create your FILE_ID.DIZ 
+file so that the file can be truncated to various line lengths without 
+destroying it's usefulness.
+
+
+EXAMPLE
+-------
+MY PROGRAM v1.23  - A program which will
+do anything for anybody. Will run in only 2k
+of memory. Can be run from the command line,
+or installed as a TSR. Completely menu-
+driven. Version 1.23 reduces the previous 4k
+memory requirements, and adds an enhanced
+graphical user interface. Also, MY PROGRAM 
+now contains Windows and DESQview support. 
+Coming soon - an OS/2 version.
+From Do-It-All Software, Inc. $15.00
+
+
+MULTIPLE DISK INFO
+------------------
+Please note that if your distribution archive requires multiple archive 
+files, you should create a separate, specific FILE_ID.DIZ file for each 
+archive. This can be utilized to describe the various contents of each 
+archive, and to identify each disk in the set. For example, the FILE_ID.DIZ 
+file for disk #1 could contain:
+
+   "MY PROGRAM v1.23  Program Executable 
+    Files - Disk 1 of 2"
+    [followed by detailed description text]
+
+while the FILE_ID.DIZ file for disk #2 could contain:
+
+   "MY PROGRAM v1.23  Documentation Files - 
+    Disk 2 of 2"
+    [followed by more detailed description text]
+
+Optionally, you could also create a "complete" FILE_ID.DIZ file for the 
+first disk, which would fully describe the program in detail, and identify 
+it as Disk 1 of x. Then, for each remaining file in the set, simply include 
+the Program Name, version number, ASP identifier, and the disk number (i.e. 
+"MY PROGRAM v1.23  Disk 2 of x").
+
+
+ADDITIONAL INFO
+---------------
+Please don't be tempted to use fancy graphic or ANSI sequences in the 
+FILE_ID.DIZ file, as most BBS software will not allow this, and will render 
+your FILE_ID.DIZ file useless. Also, don't be tempted to simply copy your 
+program description file to FILE_ID.DIZ. Attempting to "format" your 
+FILE_ID.DIZ file (i.e line centering, right & left justification, etc) will 
+also cause unexpected results, especially for BBS software which re-formats 
+descriptions to other than 10line/45char.
+
+Fred Hill  has written a freeware utility which interactively creates 
+a valid FILE_ID.DIZ file. The file is called DIZGEN.ZIP and can be found on 
+CompuServe (GO IBMBBS, Library 2) as well as on many fine BBS systems. I 
+highly recommend that you download a copy of this wonderful utility for 
+creating your FILE_ID.DIZ files.
+
+<*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*>
+
+The following is a recommendation for the structure and contents of 
+distribution archives prepared for use on BBS systems.
+
+
+DISTRIBUTION DISK RECOMMENDATIONS
+---------------------------------
+The following are recommendations for preparing your program files for 
+distribution to Bulletin Board Systems (BBSs) via the ASP's distribution 
+services, as well as other methods.
+
+Two varieties of program files are defined here:
+
+1) Program files which utilize an "install" utility and self-extracting 
+program archives (later referred to as "Author-Installed Programs").
+
+2) Programs files which do not use install utilities or self-extracting 
+archives (later referred to as "User-Installed Programs").
+
+
+AUTHOR-INSTALLED PROGRAMS:
+--------------------------
+These programs require a bit more work from the author, but will eliminate 
+many user mistakes, especially in programs which require complicated 
+setups.
+
+Most "installation" utility programs will make use of program files which 
+have been "archived" into Self-Extracting (SFX) archives. We will attempt 
+to define which files should be contained in the Self-Extracting archives, 
+and which files should not.
+
+1. Files which should be contained in the self-extracting program file
+archive:
+
+        a. All program-specific executable files.
+        b. Any required configuration and/or data files required by the
+           program.
+        c. Program documentation files. Optionally, these may be left
+           outside of the self-extracting archive, in order to allow
+           them to be viewed/read by the various archive viewing utlities.
+        d. Any other program-specific files that are required for the
+           operation of the program.
+
+2. The files described above should be compiled into a self-extracting 
+archive file, which will then be extracted by the install utility.
+
+NOTE: the author is required to abide by any distribution requirements 
+specified by the archive utility author, and to obtain any required 
+distribution rights necessary. Please check to see if distribution rights 
+are required for your archive utility choice.
+
+3. Files which should NOT be contained in the self-extracting program file 
+archive:
+
+        a. The install utility itself (obviously).
+        b. The FILE_ID.DIZ file. (described in detail in the section
+           preceding this one)
+        c. Any distribution/information files, such as VENDOR.TXT,
+           SYSOP.TXT, etc.
+        d. Any description or information file, such as DESCRIBE.TXT.
+        e. A user file (such as README.1ST), which should explain how
+           to use the install utility, what the user should expect
+           during the installation, and any preparation that the user
+           should make prior to the installation. This file might also
+           contain a brief description of your program, in case the user
+           is able to read the documentation files in the distribution
+           archive prior to downloading (many BBS systems offer this
+           ability to the user).
+
+4. The actual distribution archive file (described below) should then 
+contain the install utility, the self-extracting program archive, and the 
+files described in #3 above.
+
+
+USER-INSTALLED PROGRAMS:
+------------------------
+This type of distribution archive is much simpler than the Author-Installed 
+variety. It should simply be an archive file, containing all of the files 
+for the program described above.
+
+Since this type of program requires the user to do all of the installation 
+manually, it should contain very specific and detailed information 
+regarding the installation requirements (such as INSTALL.TXT).
+
+
+THE DISTRIBUTION ARCHIVE FILE:
+------------------------------
+The actual distribution archive file should merely be an archive file 
+containing the files described above. For BBS distribution, this archive 
+should be of the standard archive format, and -NOT- a self-extracting 
+archive.  Many sysops will not allow self-extracting archives, and most BBS 
+software will not allow self-extracting archives to be uploaded.
+
+There are many popular archive utilities available, such as PKZIP, LHA, 
+LHARC, ARJ, etc. Most BBS systems are capable of handling archives in 
+virtually any format. However, you should be aware that most BBS systems 
+will convert your archive format to the format of choice by the sysop. By 
+following the methods described above, this conversion process should not 
+affect your program, or any self-extracting files which are contained 
+within your distribution archive file.
+
+You should also retain the default archive file extension defined by the 
+archive utility. For example, PKZIP uses a ".ZIP", LHARC uses "LZH", etc. 
+Changing the file extension may cause the BBS software to delete your file 
+because it doesn't recognize the format.
+
+For the actual filename for your distribution archive, it is recommended 
+that the program filename be limited to 6 characters to represent the 
+program's name (i.e. MYPROG could represent "My Program"). This should be 
+followed by 2 numeric digits which will represent the version number of 
+your release. Even if this is your initial release it should include the 
+version number in the filename (i.e. MYPROG10.ZIP would indicate the 
+program called "My Program" version 1.0).
+
+Please note that CompuServe limits filenames to only 6 characters. By 
+limiting the file "name" to 6 characters, you will easily be able to rename 
+the archive for CompuServe uploading by simply removing the 2-digit version 
+identifier, to make the file compatible with CompuServe libraries.
+
+By including the 2-digit version number in the archive filename, it will be 
+very easy for both the user and the sysop (and yourself) to identify older 
+versions of your program.
+
+
+MULTIPLE DISTRIBUTION ARCHIVES
+------------------------------
+At one time, it was recommended that your final distribution archive not be 
+larger than 350k, so that it would fit on a single 360k floppy disk and 
+still leave room for any distribution files necessary for Disk Vendors. 
+(i.e. Disk Vendors will often include their own GO.BAT file, or other 
+various small files to help their customers install the software). This 
+limitation is slowly falling by the wayside as more and more computer 
+systems have 3.5" floppy disk drives as standard.
+
+If your program is large enough to require more than one distribution 
+archive, it is recommended that your filename be limited to 5 characters 
+rather than 6 as described above. Following the 5-character name should be 
+the same 2-digit version number. Then, append a single "letter" to identify 
+the disk (i.e. MYPGM10A.ZIP, MYPGM10B.ZIP, etc.). For uploading to 
+CompuServe, these filenames may then be shortened to 6 characters by 
+removing the version identifiers (i.e. MYPGMA.ZIP, MYPGMB.ZIP). However, 
+for CompuServe it is recommended that you simply create a single 
+distibution file, and eliminate the multi-part file set.
+
+If your program requires multiple distribution archives, -BE SURE- to 
+create separate FILE_ID.DIZ files for each distribution archive. Also, each 
+FILE_ID.DIZ file should contain disk number information pertaining to each 
+individual archive (i.e. Disk 1 of 3, Disk 2 of 3, etc.).
+
+
+THE DISTRIBUTION DISK
+---------------------
+It is recommended that your distribution disk simply contain a ZIPd version 
+of your product. However, If you choose to supply "unarchived" files on a 
+distribution disk for Disk Vendor use, it is _VERY_ important that you 
+specify in your documentation a suggested archive filename, so that BBS 
+sysops can create archived files with the proper author-specified 
+filenames. This information should be contained in your SYSOP.TXT (or 
+VENDOR.TXT) file. If you don't supply a suggested archive file name, the 
+sysops will be forced to create the name themselves, thus you may end up 
+with thousands of versions of your products on BBS systems all over the 
+world, but all with different filenames.
+
+Please note that the ASP Hub Network, and nearly every other electronic 
+distribution service *REQUIRE* that your files be submitted as an archived 
+file, using the ZIP format. Also note that many BBS sysops will not go to 
+the trouble of ZIPing your unarchived files for you. If you don't supply 
+them with an archived distribution version of your product, it might not 
+get distributed by BBSs.
+
+If you supply your own disk labels, it is recommended that the ASP logo, or 
+at least the initials "ASP" be included on the label, so that anyone can 
+immediately identify your disk as an ASP member's software.
+
+
+SUMMARY
+-------
+Your distribution disk should now be ready to submit to the various BBSs, 
+distribution services, and Disk Vendors.
+
+You may choose to create a separate distribution disk for use by BBSs and 
+Disk Vendors. However, if you follow the above steps in preparing your 
+distribution archive file, a separate "Disk Vendor" disk is probably not 
+necessary. The majority of disk vendors will be able to accept your 
+distribution file/disk if it is prepared in the above described format.
+
+
+ +Back Go Back + + + + diff --git a/html/misc/ftpserver.html b/html/misc/ftpserver.html new file mode 100644 index 00000000..0a817406 --- /dev/null +++ b/html/misc/ftpserver.html @@ -0,0 +1,98 @@ + + + + + + + + +Howto setup an FTP server to work with MBSE BBS. + + + +
+
Last update 06-Jun-2001
+

 

+ +

How to setup an FTP server to work with MBSE BBS.

+

+ +In order to let MBSE BBS and your FTP server to both function together you must +organize a special file structure. Note that even if you don't setup an FTP +server you must still create a structure like this for the fidonet mailer, +if you don't, mail and files will get lost! +Note that this description is written for wu-ftpd, on your distribution there +may be another ftpd installed. Don't use mbftpd yet! +

+

The filestructure I used is as follows:

+
+/var/spool/mbse/ftp/pub/dos_util/dos_4dos	- Public download areas
+               |   |   |        /dos_disk
+               |   |   |        /dos_file
+               |   |   /virnet/mcafee
+               |   |          /win16
+               |   |          /win32
+               |   /bin				- FTP bin directory
+               |   /etc				- FTP etc directory
+               |   /incoming			- FTP public upload.
+               /mail/out			- Your default outbound
+               |    /out.009			- Outbound Zone 9
+               |    /inbound			- Inbound directory
+               /raonly/upload			- Non-public download areas
+               |      /sysop
+               |      /logfiles
+               /tic_queue			- Queue for .tic files.
+
+
+ +In order to give DOS style names for fidonet sessions you must set the +DOS path and Unix path in mbsetup (1.3.11 and 1.3.12) to +"m:" and "/var/spool/mbse". Note that to get +forwarding of .tic files to work the tic_queue must be a +subdirectory of "/var/spool/mbse" too. You could actually use any drive letter for +the DOS path. +

+This means that a fidonet file attach from the dos_4dos public download +directory shall get the subject "M:\FTP\PUB\DOS_UTIL\DOS_4DOS\COMMAND.ZIP". + +

+As you can see, anonymous ftp users can't get to the mail, non-public +downloads etc. Normally, your BBS users have unix accounts and will be able +to do a ftp login and access any directory on your system. Because the bbs +users have mbsebbs as their shell and this shell is not in the file +/etc/shells the ftp daemon will not let the bbs users in. So even +your own bbs users must login as anonymous to get files from the ftp server. +

+Note the following directory permissions MUST BE SET!!!!::: See also +the man pages for the DARPA ftpd server. +

+ +

+Directory               	owner group mode perms
+------------------------------- ----- ----- ---- ----------
+/var/spool/mbse			mbse  bbs   0755 drwxr-xr-x
+/var/spool/mbse/ftp		root  wheel 0555 dr-xr-xr-x
+/var/spool/mbse/ftp/bin		root  wheel 0555 dr-xr-xr-x
+/var/spool/mbse/ftp/bin/ls	root  bin   0111 ---x--x--x
+/var/spool/mbse/ftp/etc		root  root  0555 dr-xr-xr-x
+/var/spool/mbse/ftp/etc/passwd	root  root  0444 -r--r--r--
+/var/spool/mbse/ftp/etc/group	root  root  0444 -r--r--r--
+/var/spool/mbse/ftp/pub		mbse  bbs   0775 drwxrwxr-x
+/var/spool/mbse/ftp/incoming   	ftp   users 0755 drwxr-xr-x
+
+
+Note that all subdirectories under ../pub also must be owned by mbse + and group bbs and have at least mode 775 as long +as it are real bbs subdirectories. The bbs will maintain these directories +automatic and must have the rights to do so. + +

+In the /var/spool/mbse/ftp/etc/group file, add the group bbs so that your directory +listings give the proper groupname instead of a number. +

+ +Back Go Back +

+ + + diff --git a/html/misc/index.htm b/html/misc/index.htm new file mode 100644 index 00000000..56b80af0 --- /dev/null +++ b/html/misc/index.htm @@ -0,0 +1,46 @@ + + + + + + + + +Miscellaneous Documents + + + +
+
Last update 02-Feb-2001
+

 

+ +

Miscellaneous Documents

+ +

Introduction

+

+This is an overview of used unofficial documents for the development of the +MBSE BBS package. +

+Michiel Broek. +

+


+

Documents

+ + +
+ +IndexBack to Index +
+ + + diff --git a/html/misc/ipmailer.html b/html/misc/ipmailer.html new file mode 100644 index 00000000..8faf1c1b --- /dev/null +++ b/html/misc/ipmailer.html @@ -0,0 +1,172 @@ + + +Integration of IP-Nodes in the nodelist. + + + + +
+Publication:    FSP-????
+Revision:       1
+Title:          Integration of IP-Nodes in the nodelist (FTS-0005)
+Author:         Lothar Behet, 2:2446/301
+Revision Date:  25 October 1998
+Expiry Date:
+----------------------------------------------------------------------
+
+Contents:
+1. Required fields according to FTS-0005, basic flags for ip-nodes
+2. Optional extensions
+3. Addendum
+----------------------------------------------------------------------
+
+1.  Description of the nodelist format
+--------------------------------------
+
+Every node entry contains the following 8 fields:
+
+keyword,node_number,node_name,location,sysop_name,
+phone_number,baud_rate,flags
+
+Certain fields have defined values according to FTS-0005.
+
+1.1.	Implementation for IP-connectivity
+	Because of the limited characterset in the phone_field and
+	to avoid any misinterpretion by conventional dialing, the
+	ip-specific address-information is entered in another field
+	and there are additional flags required.
+
+1.1.1.  Field #1 (keyword) is PVT for an ip-only node without
+	conventional phone number related connectivity. In this
+	case, the phone field contains "-Unpublished-" according
+	to FTS-0005.
+
+1.1.2.  Field #2 (node_number) contains the node number within his
+	net and zone.
+
+1.1.3.  Field #3 (node_name) is used for the FQDN (Fully Qualified
+	Domain Name) or the ip-address.
+
+1.1.4.  Field #4 (location) contains the geographical location of
+	the node. While some nets/regions cannot supply their
+	ip-only nodes with a adequate link, these nodes may be
+	collected in a seperate net or region, until their original
+	net/region support additional ip-connectivity. This special
+	net/region is definitely a temporary solution for routing
+	within a region or zone!
+
+1.1.5.  Field #5 (sysop_name) represants the name of the system
+	operator.
+
+1.1.6.  Field #6 (phone_number) contains the phone_number for
+	conventional connectivity. In case of an ip-only node
+	it must contain "-Unpublished-".
+
+1.1.7.  Field #7 (baud_rate) contains the maximum baud rate for
+	conventional connectivity or 300 in case of an ip_only node.
+
+1.1.8.  Field #8 (flags) represents operational definitions for the
+	node.
+	Note that these are user flags.
+	The ip-flags consist of two parts:
+	A basic transport and an optional non-standard port,
+	seperated by a colon.
+	The default port may be omitted, but is listed as optional
+	parameter in this document. In some cases, two flag names
+	are mentioned:
+	The second one is supported by some software nowadays, but
+	these values may conflict with other programs, which not
+	completely decode the length of each individual flag (i.e.
+	TELN conflicts with the T-flag for online-time)
+	Additional flags for ip-nodes are:
+
+1.1.8.1.  IBN[:24554] (Argus: BND[:24554])
+	BinkP protocol
+
+1.1.8.2.  IFC[:60179]
+	Raw protocol as used by ifcico
+
+1.1.8.3.  ITN[:23] (Argus: TEL[:23])
+	Telnet protocol. Some variants of ifcico support Telnet
+	on port 60177, which should be added as additional flag
+	ITN:60177.
+
+1.1.8.4.  IVM[:3141]
+	Vmodem protocol
+
+1.1.8.5.  IP
+	General flag for special protocol specifications, if the
+	flags conforming to 1.1.8.1. to 1.1.8.4. are not relevant.
+
+1.1.9.  Comments on the proposed nodelist flags
+	The additional flagnames in () are supported at this moment
+	by Argus, based on the use in z2r50. But the TEL[NET]-flag
+	stays in conflict with the generally in all zones and
+	regions used T-flag (online time according to FSC-0062).
+
+
+2.  Optional extensions for future use
+--------------------------------------
+
+While the above mentioned flags (1.1.8.1 to 1.1.8.4) define a
+minimum set of operational flags for ip-nodes, several additions
+are already foreseeable at this moment.
+
+2.1.	Additional sessions_handshake parameters
+	There is at least one program, which supports several
+	transport protocols according to chapter 1.1.8. on a
+	single port. If other programs should imitate this habit,
+	then the following extension to the flag suite 1.1.8.
+	(transport[:port[:handshake]])is advised:
+
+2.1.1.  FTS-0001 session handshake:   1
+2.1.2.  Yoohoo session handshake  :   Y
+2.1.3.  EMSI sessions handshake   :   E
+2.1.4.  BinkP sessions handshake  :   B
+
+2.2.	Non-handshaking protocols
+	While the definitions until this chapter describe direct
+	handshaking sessions with optional password authentification,
+	there are several other methods for the tunneling of fidonet
+	data via the internet available.
+	The setup of these connections does not rely on the nodelist
+	(at this moment of writing), but we can think of standard
+	setup procedures to use the nodelist for configuration of
+	this additional transport methods.
+	Therefore the following flags 2.2.1. to 2.2.4. are advised
+	for at least informational purpose.
+
+2.2.1.  IFT
+	FTP (File Transfer Protocol)
+
+2.2.2.  ITX
+	TransX, an Email based variant
+
+2.2.3.  IUC
+	Uuencoded packet (one packet per message)
+
+2.2.4.  IEM
+	Email based (generally, without exact specification at
+	this moment)
+
+
+3.  Addendum
+------------
+
+This proposal is based on a maximum compatibility to generally used
+definitions and standards within the Fidonet community.
+Future developments might make additions necessary, if they can not
+be expressed with the existing set of flags as defined by this FSP.
+
+ +Back Go Back + + + + diff --git a/html/misc/jam.html b/html/misc/jam.html new file mode 100644 index 00000000..c1ca8d50 --- /dev/null +++ b/html/misc/jam.html @@ -0,0 +1,638 @@ + + +JAM Message Base Proposal. + + + + +
+Filename....: JAM-001
+Rev.........: 001
+Dated.......: 93-07-01
+Status .....: Released
+Subject.....: JAM message base proposal
+Author......: Joaquim Homrighausen
+Co-Authors..: Andrew Milner, Mats Birch, Mats Wallin
+
+    ---------------------------------------------------------------------
+                                  JAM(mbp)
+                The Joaquim-Andrew-Mats Message Base Proposal
+    ---------------------------------------------------------------------
+            Copyright 1993 Joaquim Homrighausen, Andrew Milner,
+                           Mats Birch, Mats Wallin.
+                             ALL RIGHTS RESERVED.
+    ---------------------------------------------------------------------
+
+
+    =====================================================================
+    Restrictions
+    ---------------------------------------------------------------------
+    JAM may be used by any developer as long as these specifications are
+    followed exactly. JAM may be used free-of-charge by any developer
+    for any purpose, commercially or otherwise.
+
+    This document may be freely copied and distributed, but must NEVER be
+    distributed in a modified form. If you have an enhancement request,
+    please contact the author of this document; do not change it
+    yourself.
+
+    All applications that support JAM must include one of the following
+    notices in their documentation and somewhere in the product's credit
+    section:
+
+    "JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner,
+                               Mats Birch, Mats Wallin.
+                               ALL RIGHTS RESERVED."
+
+    or
+
+    "This product uses the JAM(mbp) API -
+     Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch,
+                    Mats Wallin. ALL RIGHTS RESERVED."
+
+    No organization, company, person, entity, or other being may impose
+    any fees for any reason for providing this document or the
+    accompanying API. This document and the accompanying API may not be
+    sold or otherwise transferred for personal or company gain under any
+    circumstances.
+
+    =====================================================================
+    Definitions and general notes
+    ---------------------------------------------------------------------
+    CURRENTREV                1
+
+    JAM                       The JAM message base format.
+
+    CRC                       Cyclic Redundancy Check. All CRC values
+                              calculated on strings must assume that the
+                              data within the string has been converted
+                              to lowercase (A-Z = a-z).
+
+    CRC-32                    32-bit CRC (as used in the Zmodem file
+                              transfer protocol) value. The polynom for
+                              a CRC-32 is edb88320H and the CRC-32 seed
+                              is -1L (ffffffffH).
+
+    uchar                     Unsigned 8-bit value
+
+    ushort                    Unsigned 16-bit value
+
+    ulong                     Unsigned 32-bit value
+
+    UNIX date                 An ulong representing the number of seconds
+                              since midnight, January 1, 1970. UNIX-style
+                              dates is the only form of time stamps used
+                              in JAM (1).
+
+    Message #                 The physical record number within the index
+                              file is used as a message number. The
+                              lowest message number is one (1) and the
+                              highest message number is 4294967295
+                              (ffffffffH).
+
+    FTN                       FidoNet Technology Network
+
+    FTS                       FidoNet Technical Standard
+
+    (1) All timestamps created locally (i.e. those not imported from
+        other systems) are stored in local time.
+
+    =====================================================================
+    Files
+    ---------------------------------------------------------------------
+    Each conference is made up from four files. How and where these files
+    are stored and named is implementation dependant. The only file with
+    a fixed minimum size is the .JHR (header data) file. It has a 1024-
+    byte block used to hold information about a specific message area as
+    described later.
+
+    filename.JHR - Message header data
+    filename.JDT - Message text data
+    filename.JDX - Message index
+    filename.JLR - Lastread information
+
+    A future revision of JAM may also include a file that holds the
+    following three items:
+
+      - The highest assigned user number
+      - The last generated message ID
+      - A global conference list with the conference name, description,
+        and physical location of the message base.
+
+    =====================================================================
+    .JHR file header
+    ---------------------------------------------------------------------
+    Below is the format of the 1024-byte record at the beginning of all
+    .JHR files. The first actual message header starts at offset 1024 in
+    the .JHR file.
+
+    FixedHeaderInfoStruct:
+        ulong   Signature;       //  followed by 
+        ulong   datecreated;     // Creation date
+        ulong   modcounter;      // Update counter
+        ulong   activemsgs;      // Number of active (not deleted) msgs
+        ulong   passwordcrc;     // CRC-32 of password to access
+        ulong   basemsgnum;      // Lowest message number in index file
+        uchar   RESERVED[1000];  // Reserved space
+    end;
+
+    MODCOUNTER must be incremented and updated on disk each time an
+    application modifies the contents of the message base. When it
+    reaches ffffffffH, it wraps to zero.
+
+    ---------------------------------------------------------------------
+    BaseMsgNum                        Lowest message number in index file
+    ---------------------------------------------------------------------
+    This field determines the lowest message number in the index file.
+    The value for this field is one (1) when a message area is first
+    created. By using this field, a message area can be packed (deleted
+    messages are removed) without renumbering it. If BaseMsgNum contains
+    500, the first index record points to message number 500.
+
+    BaseMsgNum has to be taken into account when an application
+    calculates the next available message number (for creating new
+    messages) as well as the highest and lowest message number in a
+    message area.
+
+    ---------------------------------------------------------------------
+    ????????.JHR                                          Message headers
+    ---------------------------------------------------------------------
+    The .JHR file contains none or more Header records. Each record
+    define one message and contains information about the message and its
+    text (if any). The Header record is of variable length. The layout of
+    the Header record follows.
+
+    MessageHeader:
+        MessageFixedHeader:
+            ulong  Signature;    //  followed by 
+            ushort Revision;     // Revision level of header          (1)
+            ushort ReservedWord; // Reserved for future use
+            ulong  SubfieldLen;  // Length of subfields               (2)
+            ulong  TimesRead;    // Number of times message read
+            ulong  MSGIDcrc;     // CRC-32 of MSGID line              (3)
+            ulong  REPLYcrc;     // CRC-32 of REPLY line              (3)
+            ulong  ReplyTo;      // This msg is a reply to..
+            ulong  Reply1st;     // First reply to this msg
+            ulong  Replynext;    // Next msg in reply chain
+            ulong  DateWritten;  // When msg was written
+            ulong  DateReceived; // When msg was read by recipient
+            ulong  DateProcessed;// When msg was processed by tosser/
+                                 // scanner
+            ulong  MessageNumber;// Message number (1-based)
+            ulong  Attribute;    // Msg attribute, see "Msg Attributes"
+            ulong  Attribute2;   // Reserved for future use
+            ulong  Offset;       // Offset of text in ????????.JDT file
+            ulong  TxtLen;       // Length of message text
+            ulong  PasswordCRC;  // CRC-32 of password to access message
+            ulong  Cost;         // Cost of message
+        end;
+        SubField1                // Extra fields as defined below
+        .
+        .
+        SubFieldXX
+    end;
+
+    (1) This field is intended for future revisions of the specifications
+        to allow the use of a different fixed-length binary message
+        header. The current revision level is one (1).
+
+    (2) The SubfieldLen field is set to zero (0) if the header does not
+        have any subfield data. I.e. the length of the binary header is
+        not included in this field.
+
+    (3) When calculating the CRC-32 of the MSGID and REPLY lines, the
+        text ^aMSGID: and ^aREPLY: should be removed as well as all
+        leading and trailing white space characters.
+
+
+    The SubField structure is made up of an ID, a length specifier, and
+    a block of data. Zero or more subfields may follow the fixed-length
+    binary header. SubFields are not stored in any specific order and
+    are not terminated by any specific character unless otherwise
+    specified.
+
+    SubField:
+        ushort  LoID;            // Field ID, 0-65535
+        ushort  HiID;            // Reserved for future use
+        ulong   datlen;          // Length of buffer that follows
+        uchar   Buffer[datlen];  // DATLEN bytes of data
+    end;
+
+    ---------------------------------------------------------------------
+    Defined LoID codes
+    ---------------------------------------------------------------------
+
+    ID=0, Name=OADDRESS
+
+    A network address. This is used to specify the originating address.
+    More than one OADDRESS field may exist. DATLEN must not exceed 100
+    characters. For a FidoNet-style address, this field must follow the
+    ZONE:NET/NODE.POINT@DOMAIN format where .POINT is excluded if zero
+    and @DOMAIN is excluded if unknown.
+
+
+    ID=1, Name=DADDRESS
+
+    A network address. This is used to specify the destination address.
+    More than one DADDRESS field may exist (e.g. carbon copies). DATLEN
+    must not exceed 100 characters. For a FidoNet-style address, this
+    field must follow the ZONE:NET/NODE.POINT@DOMAIN format where .POINT
+    is excluded if zero and @DOMAIN is excluded if unknown.
+
+
+    ID=2, Name=SENDERNAME
+
+    The sender (author) of the message. DATLEN must not exceed 100
+    characters.
+
+
+    ID=3, Name=RECEIVERNAME
+
+    The recipient of the message. DATLEN must not exceed 100 characters.
+
+
+    ID=4, Name=MSGID
+
+    Used to store the message identification data. All data not relevant
+    to the actual ID string, including leading and trailing white space
+    characters should be removed. DATLEN must not exceed 100 characters.
+
+
+    ID=5, Name=REPLYID
+
+    Used to store the message reply data. All data not relevant to the
+    actual reply string, including leading and trailing white space
+    characters should be removed. DATLEN must not exceed 100 characters.
+
+
+    ID=6, Name=SUBJECT
+
+    The subject of the message. DATLEN must not exceed 100 characters.
+    Note that this field may not be used for FidoNet-style file attaches
+    or file requests.
+
+
+    ID=7, Name=PID
+
+    Used to store the FTN PID kludge line. Only the actual PID data is
+    stored and ^aPID: is stripped along with any leading and trailing
+    white space characters. DATLEN must not exceed 40 characters.
+
+
+    ID=8, Name=TRACE
+
+    This is also referred to as ^aVia information in FTNs. It contains
+    information about a system which the message has travelled through.
+    The format of the field is  where:
+
+       YYYY is the year (1992-9999)
+         MM is the month (01-12)
+         DD is the day (01-31)
+         HH is the hour (00-23)
+         MM is the minute (00-59)
+         SS is the second (00-59)
+
+    The timestamp is stored in ASCII (0-9) characters. The network
+    address is the address of the system. It is expressed in ASCII
+    notation in the native format of the forwarding system.
+
+
+    ID=9, Name=ENCLOSEDFILE
+
+    A file attached to the message. Only one filename may be specified
+    per subfield. No wildcard characters are allowed. If this subfield
+    is present in a message header, the ATTRIBUTE must include the
+    MSG_FILEATTACH bit.
+
+
+    ID=10, Name=ENCLOSEDFILEWALIAS
+
+    Identical to ENCLOSEDFILE with the exception that the filename is
+    followed by a  (00H) and an alias filename to be transmited to
+    the remote system in place of the local name of the file.
+
+
+    ID=11, Name=ENCLOSEDFREQ
+
+    A request for one or more files. Only one filemask may be specified
+    per subfield. If the filemask contains a complete path, it is to be
+    regarded as an update file request. If this subfield is present in a
+    message header, the ATTRIBUTE must include the MSG_FILEREQUEST bit.
+    To indicate that a password is to be transmitted along with the
+    request, a  (00H) character followed by the password is
+    appended. E.g. SECRET*.*MYPASSWORD.
+
+
+    ID=12, Name=ENCLOSEDFILEWCARD
+
+    One or more files attached to the message. Only one filename may be
+    specified per subfield. Wildcard characters are allowed. If this
+    subfield is present in a message header, the ATTRIBUTE must include
+    the MSG_FILEATTACH bit.
+
+
+    ID=13, Name=ENCLOSEDINDIRECTFILE
+
+    One or more files attached to the message. The filename points to an
+    ASCII file with one filename entry per line. If alias filenames are
+    to be used, they are specified after the actual filename and
+    separated by a  (00H) character, e.g. C:\MYFILE.LZHNEWS.
+    Wildcard characters are not allowed.
+
+
+    ID=1000, Name=EMBINDAT
+
+    Reserved for future use.
+
+
+    ID=2000, Name=FTSKLUDGE
+
+    An FTS-compliant "kludge" line not otherwise represented here. All
+    data not relevant to the actual kludge line, including leading and
+    trailing white space and ^A (01H) characters should be removed.
+    DATLEN must not exceed 255 characters. The FTS kludges INTL, TOPT,
+    and FMPT must never be stored as separate SubFields. Their data must
+    be extracted and used for the address SubFields.
+
+
+    ID=2001, Name=SEENBY2D
+
+    Used to store two-dimensional (net/node) SEEN-BY information often
+    used in FTN conference environments. Only the actual SEEN-BY data is
+    stored and ^aSEEN-BY: or SEEN-BY: is stripped along with any leading
+    and trailing white space characters.
+
+
+    ID=2002, Name=PATH2D
+
+    Used to store two-dimensional (net/node) PATH information often used
+    in FTN conference environments. Only the actual PATH data is stored
+    and ^aPATH: is stripped along with any leading and trailing white
+    space characters.
+
+
+    ID=2003, Name=FLAGS
+
+    Used to store the FTN FLAGS kludge information. Note that all FLAG
+    options that have binary representation in the JAM message header
+    must be removed from the FLAGS string prior to storing it. Only
+    the actual flags option string is stored and ^aFLAGS is stripped
+    along with any leading and trailing white space characters.
+
+
+    ID=2004, Name=TZUTCINFO
+
+    Time zone information. This subfield consists of four mandatory
+    bytes and one optional. The first character may be a plus (+) or a
+    minus (-) character to indicate a location east (plus) or west
+    (minus) of UTC 0000. The plus character is implied unless the first
+    character is a minus character. The following four bytes must be
+    digits in the range zero through nine and indicates the offset in
+    hours and minutes. E.g. 0100 indicates an offset of one hour east of
+    UTC.
+
+    ---------------------------------------------------------------------
+    Message attributes
+    ---------------------------------------------------------------------
+    MSG_LOCAL       (0x00000001L)   // Msg created locally
+    MSG_INTRANSIT   (0x00000002L)   // Msg is in-transit
+    MSG_PRIVATE     (0x00000004L)   // Private
+    MSG_READ        (0x00000008L)   // Read by addressee
+    MSG_SENT        (0x00000010L)   // Sent to remote
+    MSG_KILLSENT    (0x00000020L)   // Kill when sent
+    MSG_ARCHIVESENT (0x00000040L)   // Archive when sent
+    MSG_HOLD        (0x00000080L)   // Hold for pick-up
+    MSG_CRASH       (0x00000100L)   // Crash
+    MSG_IMMEDIATE   (0x00000200L)   // Send Msg now, ignore restrictions
+    MSG_DIRECT      (0x00000400L)   // Send directly to destination
+    MSG_GATE        (0x00000800L)   // Send via gateway
+    MSG_FILEREQUEST (0x00001000L)   // File request
+    MSG_FILEATTACH  (0x00002000L)   // File(s) attached to Msg
+    MSG_TRUNCFILE   (0x00004000L)   // Truncate file(s) when sent
+    MSG_KILLFILE    (0x00008000L)   // Delete file(s) when sent
+    MSG_RECEIPTREQ  (0x00010000L)   // Return receipt requested
+    MSG_CONFIRMREQ  (0x00020000L)   // Confirmation receipt requested
+    MSG_ORPHAN      (0x00040000L)   // Unknown destination
+    MSG_ENCRYPT     (0x00080000L)   // Msg text is encrypted          (1)
+    MSG_COMPRESS    (0x00100000L)   // Msg text is compressed         (1)
+    MSG_ESCAPED     (0x00200000L)   // Msg text is seven bit ASCII    (1)
+    MSG_FPU         (0x00400000L)   // Force pickup
+    MSG_TYPELOCAL   (0x00800000L)   // Msg is for local use only
+    MSG_TYPEECHO    (0x01000000L)   // Msg is for conference distribution
+    MSG_TYPENET     (0x02000000L)   // Msg is direct network mail
+    MSG_NODISP      (0x20000000L)   // Msg may not be displayed to user
+    MSG_LOCKED      (0x40000000L)   // Msg is locked, no editing possible
+    MSG_DELETED     (0x80000000L)   // Msg is deleted
+
+    (1) This revision of JAM does not include compression, encryption, or
+        escaping. The bits are reserved for future use.
+
+    =====================================================================
+    ????????.JDT                                             Message text
+    ---------------------------------------------------------------------
+    The .JDT file contains the text of messages. The text is stored as an
+    stream of seven or eight bit ASCII data. Allowed characters in the
+    text are 00H through ffH unless the header ATTRIBUTE field has the
+    MSG_ESCAPED bit enabled, in which case the legal range of data is 20H
+    through 7eH.
+
+    An escaped character is stored as \ where  is the two digit
+    hexadecimal ASCII value of the character. A single \ is stored as \\
+    or \5C. The case of the hexadecimal ASCII value is irrelevant, i.e.
+    5c is treated as 5C.
+
+    =====================================================================
+    ????????.JDX                                            Message index
+    ---------------------------------------------------------------------
+    The .JDX file is used to quickly locate messages for any given user
+    name or to locate a message with a specific number. Each record in
+    the file consists of two ulongs. The first ulong holds the CRC-32 of
+    the recipient's name (lowercase), the second ulong holds the
+    physical offset of the message header in the .JHR (header) file.
+
+    The record number (+BaseMsgNum) within the .JDX file determines a
+    message's number.
+
+    If both ulongs are -1 (ffffffffH), there is no corresponding message
+    header.
+
+    =====================================================================
+    ????????.JLR                                         Lastread storage
+    ---------------------------------------------------------------------
+    The .JLR file is used to maintain a user's position within a message
+    area. The layout of the "lastread" record follows. One record per
+    user is required.
+
+    LastRead:
+        ulong   UserCRC;         // CRC-32 of user name (lowercase)   (1)
+        ulong   UserID;          // Unique UserID
+        ulong   LastReadMsg;     // Last read message number
+        ulong   HighReadMsg;     // Highest read message number
+    end;
+
+    (1) The functions to convert a string to lowercase characters that
+        are provided in the API will only convert characters A-Z (into
+        a-z). It is required that this convention is followed by all
+        applications.
+
+    The UserID field is a unique number for each user. If the "lastread"
+    record is deleted, UserCRC and UserID are both set to -1
+    (ffffffffH). An application may not depend on any specific order in
+    the .JLR file. A user's "lastread" record may appear anywhere in the
+    file and must be searched for when retrieving it and when storing an
+    updated record.
+
+    =====================================================================
+    Updating message headers
+    ---------------------------------------------------------------------
+    If a header record grows after is has been retrieved from the .JHR
+    file, it must be appended to the end of the .JHR file since it would
+    overwrite the following header otherwise. The .JDX file must be
+    properly updated to indicate the new location of the header record.
+    The old header record must be changed to indicate that it has been
+    deleted by setting the MSG_DELETED bit in the Attribute field and the
+    TextLen field to zero (to prevent a maintenance program from removing
+    the message text that is now pointed to by another header).
+
+    =====================================================================
+    Message base sharing and locking
+    ---------------------------------------------------------------------
+    To allow several programs to access the message base at any given
+    time, region locking is used to protect the message base from being
+    corrupted during updates.
+
+    When an application needs to write to any of the message base files,
+    it must first attempt to lock the first byte of the .JHR (header)
+    file. If the lock call fails, the application must either fail or
+    attempt to lock the file again. The message base files may under no
+    circumstances be updated if the application cannot successfully lock
+    the .JHR file.
+
+    Note that data acquired (read) from the message base may not be used
+    when writing data to the message base, unless the application has
+    maintained a lock of the message base from the time the data was
+    acquired or the MODCOUNTER field is the same as when the data was
+    acquired.
+
+    The application must open the files in shareable (DENYNONE) read/
+    write or readonly mode. The only exception to this is an application
+    that requires exclusive access to the message base, such as a message
+    base maintenance utility, it should open the files in non-shareable
+    (DENYALL) read/write mode.
+
+    =====================================================================
+    Reply threads and linking
+    ---------------------------------------------------------------------
+    JAM introduces a new reply link pointer, not commonly used today.
+    This section is an attempt to describe how reply threads, reply
+    linking, and this new reply link pointer is implemented in JAM.
+
+    One of the major differences is that reply threads in JAM are not
+    based on similar or identical subjects of messages since this method
+    does not allow for proper reply threads.
+
+    The method used in JAM is based on the immediate relation between any
+    given message and direct replies to it. This is supported by many
+    message editors by using the MSGID and REPLY FTS kludge fields. These
+    are common, although expressed differently, in messages not based on
+    FidoNet technology, such as RFC-822. The obvious advantages include
+    allowing a program to easily find the original message to a reply,
+    and to find all replies to any given message.
+
+    The reply thread information consists of three fields: ReplyTo,
+    Reply1st, and ReplyNext. The reason for three fields, as opposed to
+    just two, is that with two fields, it is only possible to keep track
+    of the original message of a reply (which is sufficient) and one
+    reply to any given message (which is not sufficient). With three
+    fields, it is possible to maintain a thread of any number of replies
+    to any given message.
+
+    In the description of the different fields below, the following
+    messages and message numbers will be referred to:
+
+      1 -> 2 -> 4 -> 5
+      :    :
+      :    +--> 8
+      :
+      +--> 3 -> 7
+      :
+      +--> 6
+
+    Message number two, three, and six are replies to message number one.
+    Message number four and eight are replies to message number two.
+    Message number seven is a reply to message number three.
+    Message number five is a reply to message number four.
+
+    ---------------------------------------------------------------------
+    ReplyTo
+    ---------------------------------------------------------------------
+    This field holds the number of the message that this message is a
+    reply to. In the example above, the ReplyTo field would contain the
+    following values:
+
+    Message number one would contain zero; message number two, three, and
+    six, would contain one; message number four and eight would contain
+    two; message number seven would contain three, and message number
+    five would contain four.
+
+    ---------------------------------------------------------------------
+    Reply1st
+    ---------------------------------------------------------------------
+    This field holds the number of the first message that is a reply to
+    this message. In the example above, the Reply1st field would contain
+    the following values:
+
+    Message number one would contain two, message number three would
+    contain seven, and message number four would contain five. All other
+    messages would contain zero.
+
+    ---------------------------------------------------------------------
+    ReplyNext
+    ---------------------------------------------------------------------
+    This field is used to create the actual message thread or chain. In
+    the event that there is more than one reply to any given message, it
+    is necessary to maintain a thread of all the replies; this is due to
+    the fact that the original message can only hold information about
+    the first reply (the Reply1st field) to it.
+
+    The first reply (which the original message's Reply1st field holds),
+    has its ReplyNext field pointing to the second reply, the second
+    reply's ReplyNext field poinst to the third reply, and so on.
+
+    In the example above, the ReplyNext field would contain the following
+    values:
+
+    Message number two would contain three, message number three would
+    contain six, and message number four would contain eight. All other
+    messages would contain zero.
+
+    =====================================================================
+    Contacts
+    ---------------------------------------------------------------------
+    Joaquim Homrighausen                            Telefax: +352 316 702
+    389, route d'Arlon                                Modem: +352 316 702
+    L-8011 Strassen                               eMail: 2:270/17@fidonet
+    Luxembourg                                                joho@abs.lu
+
+    Andrew Milner                                   Telefax: +352 251 621
+    9a, Boulevard Joseph II                           Modem: +352 251 621
+    L-1840 Belair                                 eMail: 2:270/18@fidonet
+    Luxembourg                                             andrew@fido.lu
+
+    Mats Wallin                                    Telefax: +46 8 6453285
+    F”rskottsv„gen 11                                Modem: +46 8 6453882
+    S-126 44 H„gersten                           eMail: 2:201/329@fidonet
+    Sweden                                                     mw@fido.lu
+
+ +Back Go Back + + + + diff --git a/html/misc/outbound.html b/html/misc/outbound.html new file mode 100644 index 00000000..4a350c05 --- /dev/null +++ b/html/misc/outbound.html @@ -0,0 +1,114 @@ + + + + + + + + +Binkley style outbound with MBSE BBS. + + + +
+
Last update 02-Feb-2001
+

 

+ +

Binkly style outbound documentation for MBSE BBS.

+

+The MBSE BBS outbound directory structure is BinkleyTerm compatible, with +domains and point subdirectories (full 5d). There are separate "protected" and +"unknown" inbound directories for incoming sessions. Files received during +outbound sessions are always placed in the "protected" inbound directory. Only +the "protected" inbound directory is processed automatic. +

+ +

+Note that this is a very simple document and that it is not even finished. +

+

+.pol	Poll flag, is handled as crash immediate, the length is always 0 bytes.
+
+	Flow files are files with the full pathnames to the files to send
+	on disk. Names are translated by MBSE BBS to full DOS filenames and
+	paths depending on your setup. 
+	If you use it then it is importand that you think about the directory
+	structure to use. See also the documentation about the setup of the
+	ftp server
+	The filenames may be prepended with a special character:
+	#	= Truncate file after sent.
+	- or ^	= Kill file after sent.
+	@	= Leave file after sent, this is the default.
+
+.flo	Normal flow file (contains complete filenames to send).
+.clo	Crash flow file.
+.hlo	Hold flow file.
+.ilo	Immediate flow file, overrides CM flag.
+
+	The following are .pkt files, during the mail session they will be
+	renamed to nnnnnnnn.pkt with an unique name and added to the spool
+	file. Messages can allways be added to the outbound as long as the
+	node isn't locked.
+
+.out	Normal .pkt file.
+.cut	Crash .pkt file.
+.hut	Hold .pkt file.
+.iut	Immediate .pkt file.
+
+	It seems that these are subdirectories used by ifpack during packing
+	of mail. These are used for the news/e-mail gate.
+
+.opk
+.cpk
+.hpk
+.ipk
+
+
+.req	Request file. Contains filenames in ascii with <cr><lf>.
+
+.su0	Arcmail bundles, the last digit may be any digit or letter.
+.mo0
+.tu0
+.we0
+.th0
+.fr0
+.sa0
+
+.sts	Node status file created by mbcico. These are data files containing
+	three values: 
+	1. 'time', this is the last call attempt time (in time_t format).
+	2. 'retries', is the number of retries to try to connect that node. This
+   	    field is zeroed when the call succeeds or when that node calls in.
+	    It is also zeroed when a new poll is created. Currently, mbcico stops
+	    calling a node if the counter is higher then 30.
+	3. 'code', is the return code of the last attempt.
+	0      - Successfull call
+	1      - No dialout port available
+	2      - No CONNECT or TCP connect failed
+ 	3      - Could not reset the modem
+	4      - System is locked
+	5      - Retry time not reached?
+	6      - Fatal error in nodelist lookup
+	7      - Call prohibited by config options
+	8      - Phone number unavailable
+	9      - No free matching port
+	10     - Unused
+	11..29 - Session (handshake) errors.
+	This file is not compatible with the .sts files created by ifcico.
+ +
+.spl	Spool file, created by mbcico.
+
+.bsy	Busy file, for locking nodes. The 'pid' of the process who locked that
+	node is inserted into this file. All programs of the MBSE BBS package
+	(and ifcico package) check if the pid exists if a .bsy file is found.
+	If there is no pid found, the lock is a stale lock and is removed.
+
+
+ +Back +Go Back +
+ + + diff --git a/html/misc/semafore.html b/html/misc/semafore.html new file mode 100644 index 00000000..19dcefc0 --- /dev/null +++ b/html/misc/semafore.html @@ -0,0 +1,51 @@ + + + + + + + + +Semafore files with MBSE BBS. + + + +
+
Last update 22-jul-2001
+

 

+ +

Semafore files with MBSE BBS.

+ +The directory $MBSE_ROOT/sema is the hardcoded semafore directory where all +semafore's must be created, tested and removed. When the system is booting, +the init script will erase all semafore's just before the BBS is started. +This description is valid from MBSE BBS v0.33.17 and newer. + +
+zmh		Purpose: to mark the state of Zone Mail Hour. 
+		Created by "mbtask" at the start of Zone Mail Hour.
+		Removed by "mbtask" at the end of Zone Mail Hour.
+
+upsalarm	Purpose: Signal that the system is running on battery power.
+		Created and removed by UPS software.
+		Checked by mbtask to suspend processing.
+		Checked by mbfido to stop processing.
+
+upsdown		Purpose: Signal that the system will go down on low battery.
+		Created and removed by UPS software.
+		Checked by mbtask to go down.
+		Checked by several scripts and "mbstat wait".
+
+newnews		Purpose: Signal that there are new articles on the news server.
+		Checked by mbtask to start news processing.
+		Removed by mbtask as soon as it is detected.
+
+mbtask.last	Purpose: A timestamp created and touched by "mbtask" every
+		minute so you can check it is running.
+
+ +Back Go Back +
+ + + diff --git a/html/misc/usleep.html b/html/misc/usleep.html new file mode 100644 index 00000000..fc64d73c --- /dev/null +++ b/html/misc/usleep.html @@ -0,0 +1,61 @@ + + +System load and the usleep() call. + + + + +
+		usleep.doc
+
+
+At some time when developping MBSE BBS I decided that background utilities
+did't need full speed to do their jobs. BBS utilities under DOS needed
+to run as fast as possible because you needed to bring the bbs down to run
+these programs and users couldn't login during that time.
+
+Starting with mball, the allfiles creator, I inserted code that does usleep(1)
+after each 5 processed files. The 1 microsecond is not really the time the
+program pauses, it's probably a lot longer. I think this depends on the 
+hardware type, (Intel, Sparc, Alpha etc) how long Linux will really suspends
+executing the utility.
+
+The program speed downgrade at the development machine that mball needed was
+3 times the original exection time, while system loading stayed under 30%.
+At that time the development machine is an 486DX2-66 with a Seagate ST32151N
+SCSI harddisk.
+
+The extra usleep code is only active if you run these utils with the -quiet
+switch and when this is set in mbsetup. See menu 1->5.
+With this switch, the program is mostly run by cron. If you onmit
+this switch, this is probably when you start the program manually, it will
+then always run at full speed, no matter what the setting in mbsetup is.
+
+If you have a fast system or don't care that the performance of your system 
+drops because of background processing, you can turn this future off with
+mbsetup in the global section. (menu 1->5).
+
+Remember, if you have a PII-400 MMX or so with IDE disks, you may still have
+performance problems and need to set that switch to yes. There is only one
+way to find out if you need it.
+
+Well, actually, I tested this on a Dell Latitude PII-266, setting the switch to
+yes gave better performance then no. Why? The CPU has more time for the slow
+IDE disk. With the slow switch on programs runs even faster then with the switch
+off. 
+
+Michiel.
+
+
+ +Back Go Back + + + + diff --git a/html/nodelist.html b/html/nodelist.html new file mode 100644 index 00000000..07dff033 --- /dev/null +++ b/html/nodelist.html @@ -0,0 +1,131 @@ + + + + + + + + +Nodelist and Nidediff processing. + + + +
+
Last update 07-Jun-2001
+

 

+ +

Nodelist and Nodediff processing

+

+ +

Introduction

+

+A received a lot of questions about nodelist and nodediff processing, so +I will describe here the setup of the development system for the Fidonet +nodelist. First of all, it is very important that you +use three separate directories to do the nodelist processing. This is to +make sure that all stages are independent of each other, and if something +goes wrong, you still have a working system. The three directories are:
+

    +
  1. /var/spool/mbse/ftp/pub/fido/nodelist, this is the public +download area, the received diff's are stored here as well as the final +compressed nodelists for download. +
  2. /opt/mbse/tmp/nlwork, this is the working directory +to apply diffs to the previous nodelist. This directory should allways +contain the latest uncompressed nodelist. +
  3. /var/spool/mbse/nodelist, this is the systems nodelist +directory defined in mbsetup, menu 1.3.4 +
+In short the steps to process the nodediff's is as follows: +
    +
  1. Receive the nodediff and store it for download. +
  2. Apply the diff to the latest nodelist. +
  3. Hatch the new compressed nodelist. +
  4. Store the new nodelist for download. +
  5. Unpack the new nodelist in the nodelist compiler directory. +
  6. Set the compile semafore. +
  7. Compile the nodelists. +
+Next I will describe these steps in detail. +

 

+ +

The download area

+

+First define the download area for the bbs. In my case, this is area 20. From +here users can download the nodelists and nodediffs, files to the downlinks +are send from here. Below is the example of my system. +

+ +

 

+ +

The NODEDIFF tic area

+

+From your uplinks you usually receive NODEDIFF files. Create a tic area for +that purpose. I have keep# set to 5, this means the last 5 diff's are stored +in the download directory, older ones are removed. Now you can receive +nodediff files, store them for download, and send them to other nodes. +

+ +

 

+ +

Apply the diff

+

+We do this with the tic magic processor. In this example +I have NODELIST.007 in the /opt/mbse/tmp/nlwork directory. +Note that this filename is uppercase, they are usually stored and distributed +as uppercase names. As I receive the diff files as arc, the filemask on +my system is nodediff.a##. +This means that the file with the name nodediff.a14 in the area NODEDIFF +is a match. The command that is executed expands to +mbdiff /opt/mbse/tmp/nlwork/NODELIST /var/spool/mbse/ftp/pub/fido/nodelist/nodediff.a14 -quiet if the received nodediff is +nodediff.a14.
The mbdiff program applies +nodediff.a14 against NODELIST.007 in the +/opt/mbse/tmp/nlwork directory. If this is successfull, a +new NODELIST.014 is created there, a compressed +nodelist.z14 is created there and NODELIST.007 is +removed.
If this operation fails, only NODELIST.007 will stay +in that directory. +Because the ARC program for Linux isn't good for files, I +left the Arc files command empty in the archiver setup. As a fallback the +mbdiff program uses zip to create the compressed archive.
+If creating the new nodelist fails for some reason, a missed diff or so, +the whole processing stops here. The previous nodelist is still here and +you can manually correct the situation. So, if you missed a diff, see that +you get it and manually give the mbdiff commands as user +mbse until you are up to date. Or, place the latest +uncompressed nodelist in the directory /opt/mbse/tmp/nlwork. +

+ +

 

+ +

Processing the new nodelist

+

+Now that we have created the new compressed nodelist, it has to go somewhere. +The file nodelist.z14 is in the directory +/opt/mbse/tmp/nlwork. The example for the hatch manager +is shown below. The hatch manager runs automatic with the comand +mbfido tic. This setup will hatch the new nodelist in the +tic area NODELIST The two screens below show the tic and +hatch setup for this area. +

+ + +

+Now that we have hatched the new nodelist and stored in in the download area, +and maybe send some copies to downlinks, we have to feed it to the nodelist +compiler for our own system. We use a tic magic command to do +that. In this case we unpack the nodelist in /var/spool/mbse/nodelist +and set the compile semafore so that the mbindex + will compile the new nodelist. Don't be afraid that the unpacked +nodelists will acumulate in the nodelist directory, mbindex +will handle that, only the latest two nodelists are kept there. The +mbindex program is started by the taskmanager +mbtask. +

+ +

 

+ +Back Go Back +
+ + + diff --git a/html/postfix.html b/html/postfix.html new file mode 100644 index 00000000..44ad60cb --- /dev/null +++ b/html/postfix.html @@ -0,0 +1,160 @@ + + + + + + + + +MBSE BBS - Internet Gateway - Postfix setup. + + + +
+
Last update 21-Jun-2001
+

 

+ +

MBSE BBS - Internet Gateway - Postfix setup.

+

+Of course you need to make all these changes as root. +Add the mbmail program as service to the postfix system by +adding two lines to master.cf. +


+
+#
+# Postfix master process configuration file.  Each line describes how
+# a mailer component program should be run. The fields that make up
+# each line are described below. A "-" field value requests that a
+# default value be used for that field.
+#
+# Service: any name that is valid for the specified transport type
+# (the next field).  With INET transports, a service is specified as
+# host:port.  The host part (and colon) may be omitted. Either host
+# or port may be given in symbolic form or in numeric form. Examples
+# for the SMTP server:  localhost:smtp receives mail via the loopback
+# interface only; 10025 receives mail on port 10025.
+#
+# Transport type: "inet" for Internet sockets, "unix" for UNIX-domain
+# sockets, "fifo" for named pipes.
+#
+# Private: whether or not access is restricted to the mail system.
+# Default is private service.  Internet (inet) sockets can't be private.
+#
+# Unprivileged: whether the service runs with root privileges or as
+# the owner of the Postfix system (the owner name is controlled by the
+# mail_owner configuration variable in the main.cf file).
+#
+# Chroot: whether or not the service runs chrooted to the mail queue
+# directory (pathname is controlled by the queue_directory configuration
+# variable in the main.cf file). Presently, all Postfix daemons can run
+# chrooted, except for the pipe and local daemons. The files in the
+# examples/chroot-setup subdirectory describe how to set up a Postfix
+# chroot environment for your type of machine.
+#
+# Wakeup time: automatically wake up the named service after the
+# specified number of seconds.  Specify 0 for no wakeup. Presently,
+# only the local pickup and queue manager daemons need a wakeup timer.
+#
+# Max procs: the maximum number of processes that may execute this
+# service simultaneously. Default is to use a globally configurable
+# limit (the default_process_limit configuration parameter in main.cf).
+#
+# Command + args: the command to be executed. The command name is
+# relative to the Postfix program directory (pathname is controlled by
+# the program_directory configuration variable). Adding one or more
+# -v options turns on verbose logging for that service; adding a -D
+# option enables symbolic debugging (see the debugger_command variable
+# in the main.cf configuration file).
+#
+# In order to use the "uucp" message tranport below, set up entries
+# in the transport table.
+#
+# In order to use the "cyrus" message transport below, configure it
+# in main.cf as the mailbox_transport.
+#
+# SPECIFY ONLY PROGRAMS THAT ARE WRITTEN TO RUN AS POSTFIX DAEMONS.
+# ALL DAEMONS SPECIFIED HERE MUST SPEAK A POSTFIX-INTERNAL PROTOCOL.
+#
+# ==========================================================================
+# service type	private	unpriv	chroot	wakeup	maxproc	command + args
+# 		(yes)	(yes)	(yes)	(never)	(50)
+# ==========================================================================
+smtp	  inet	n	-	n	-	-	smtpd
+pickup	  fifo	n	n	n	60	1	pickup
+cleanup	  unix	-	-	n	-	0	cleanup
+qmgr	  fifo	n	-	n	300	1	qmgr
+rewrite	  unix	-	-	n	-	-	trivial-rewrite
+bounce	  unix	-	-	n	-	0	bounce
+defer	  unix	-	-	n	-	0	bounce
+smtp	  unix	-	-	n	-	-	smtp
+showq     unix	n	-	n	-	-	showq
+error     unix	-	-	n	-	-	error
+local	  unix	-	n	n	-	-	local
+cyrus	  unix	-	n	n	-	-	pipe
+    flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
+uucp	  unix	-	n	n	-	-	pipe
+    flags=F user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
+ifmail    unix  -       n       n       -       1       pipe
+    flags=F user=fido argv=/usr/local/bin/ifmail -r $nexthop ($recipient)
+mbmail    unix  -       n       n       -       1       pipe
+    flags=F user=mbse argv=/opt/mbse/bin/mbmail -r $nexthop ($recipient)
+bsmtp     unix  -       n       n       -       -       pipe
+    flags=F. user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
+
+
+In main.cf change or add the line:
+
+relay_domains = $mydestination, f2802.n280.z2.fidonet.org
+
+The fidonet address will be your fidonet address of course. If you have more +fidonet aka's, add them as well seperated with commas. +

+ +Next you need to add mbmail to the +transport file. +


+
+# /etc/postfix/transport
+#
+# execute "postmap /etc/postfix/transport" after changing this file
+#
+# Local destinations
+#
+seaport.mbse.nl		local:
+www.mbse.nl		local:
+news.mbse.nl		local:
+#
+# Fidonet mailers at this machine. Test on several strings to make sure
+# it will catches everything.
+#
+z1                      mbmail:f2802.n280.z2.fidonet
+.z1                     mbmail:f2802.n280.z2.fidonet
+z2                      mbmail:f2802.n280.z2.fidonet
+.z2                     mbmail:f2802.n280.z2.fidonet
+z3                      mbmail:f2802.n280.z2.fidonet
+.z3                     mbmail:f2802.n280.z2.fidonet
+z4                      mbmail:f2802.n280.z2.fidonet
+.z4                     mbmail:f2802.n280.z2.fidonet
+z5                      mbmail:f2802.n280.z2.fidonet
+.z5                     mbmail:f2802.n280.z2.fidonet
+z6			mbmail:f2802.n280.z2.fidonet
+.z6			mbmail:f2802.n280.z2.fidonet
+fidonet			mbmail:f2802.n280.z2.fidonet
+.fidonet		mbmail:f2802.n280.z2.fidonet
+fidonet.org		mbmail:f2802.n280.z2.fidonet
+.fidonet.org		mbmail:f2802.n280.z2.fidonet
+
+
+Don't forget to run postmap /etc/postfix/transport. Now all +files are changed, run postfix reload to activate the +changes. + +

+ +Back +Go back +Home Go to main +

+ + + diff --git a/html/programs/import.html b/html/programs/import.html new file mode 100755 index 00000000..3046fb19 --- /dev/null +++ b/html/programs/import.html @@ -0,0 +1,41 @@ + + + + + + + + +MBSE BBS Programs - Import Configuration. + + + +
+
Last update 30-Jan-2001
+

 

+ +

import - Import Configuration.

+

+ +

Synopsis.

+

+import [command] +

 

+ +

Description.

+

+import can be used to import the configuration databases from +plain ascii textfiles. This program is not supported. For the format of the +input files look in the source. This program will also not function properly +after 31-Dec-1999. If someone writes real good working conversion programs +to convert BBS, Tosser, Mailer setups to MBSE BBS setup, then make them +public available. On my BBS there is a utility to export RA2.02 databases to +the format that this import program can read. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/index.htm b/html/programs/index.htm new file mode 100644 index 00000000..2c2b3ece --- /dev/null +++ b/html/programs/index.htm @@ -0,0 +1,50 @@ + + + + + + + + +MBSE BBS Programs. + + + +
+
Last update 06-Jun-2001
+

 

+ +

MBSE BBS Programs.

+ + +
    +
  1. import, Import databases +
  2. mbaff, Announce newfiles and filefind +
  3. mball, Allfiles and newfiles list creator +
  4. mbchat, Sysop to user chat utility +
  5. mbcico, The Fidonet mailer ala ifcico +
  6. mbdiff, Nodelist difference processor +
  7. mbfbgen, FileBase Generator utility +
  8. mbfido, Fidonet mail and files procesor +
  9. mbfile, Files database maintenance program +
  10. mbindex, Nodelist index compiler +
  11. mblang, Language datafile compiler +
  12. mbmon, The monitor program +
  13. mbmsg, The messagebase utility program +
  14. mbout, The mailer outbound program +
  15. mbpasswd, The passwd wrapper +
  16. mbsebbs, The bbs program +
  17. mbseq, Sequence number creator +
  18. mbsetup, The setup program +
  19. mbstat, The bbs status change program +
  20. mbtoberep, The toberep.data lister +
  21. mbuser, The userbase maintenance program +
  22. mbuseradd, The adduser wrapper +
+ + +Main Back to Main index +
+ + + diff --git a/html/programs/mbaff.html b/html/programs/mbaff.html new file mode 100644 index 00000000..b5c74263 --- /dev/null +++ b/html/programs/mbaff.html @@ -0,0 +1,99 @@ + + + + + + + + +MBSE BBS Programs - mbaff - Announce new files and Filefind processor. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbaff - Announce new files and FileFind processor.

+

+ +

Synopsis.

+mbaff [command] <options> +

  + +

Description.

+

+mbaff +is the new files report generator and filefind server for mbsebbs. +In order to run mbaff +you must first start mbsed, +this is the deamon which controls all bbs activities. +

+When mbaff +is run with the commandline command announce +the first thing it does is to scan all the file databases for files +from which the announced flag is not yet set, and that area has a valid +newfiles groupname. These files are uploads for example. +If such a file is found the announced flag is set and +the file is added to the +toberep.data +file. This file may already contain +new files who were received as .tic files and processed by the +mbfido program. +After this is done the toberep.data +file is compared against the newfiles +reports to see if there is anything to report. If that's the case the +creation of reports begins in the echomail areas specified. After that the +toberep.data +file is erased and the mailout semafore set.
+The files to announce are divided into groups, the names of the groups are +set in the file download areas. If you plan this well, you can make seperate +announcements for several networks, announce files bij groups of file, ie. HAM +or .jpg pictures, Linux etc. +

+When +mbaff +is run with the commandline command +filefind +it will search each echomail area for unreceived messages addressed to +allfix or filefind. +It will read the message header and mark the message as received. The +search options are set on the subject line. All file areas for which the +filefind flag is set to true will be searched for the requested search +patterns. If there are files found a reply will be generated for the +user who wrote the request. If the reply area is different from the scan +area, the reply is placed in the reply area. If it's not set, the reply +goes into the same area. If the netmail option is set, the reply will +be sent by netmail. To prevent echomail overflow the replies in the same +area are limited to 15 found files, replies in the other echomail area +are limited to 50 files. Netmail replies will contain up to 100 files. +

 

+ +

Environment.

+

+In order to run mbaff you need to set one global environment variable +$MBSE_ROOT. +This variable must point to the root of the bbs directoy structure. The +main configuration file +config.data +must be present in the ~/etc subdirectory. +

 

+ +

Commands.

+

+mbaff announce - Announce new files.
+mbaff filefind - Process filefind requests. +

 

+ +

OPTIONS

+

+mbaff [command] -quiet - Quiet mode, no screen output. +Use this switch if you run mbaff from the crontab. +

+ +Back Back to index  +Index Back to main index +

+ + + diff --git a/html/programs/mball.html b/html/programs/mball.html new file mode 100644 index 00000000..714a0f6e --- /dev/null +++ b/html/programs/mball.html @@ -0,0 +1,77 @@ + + + + + + + + +MBSE BBS Programs - Allfile listing generator. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mball - Allfiles listing generator

+

+ +

Synopsis.

+

+mball [commands] <options> +

 

+ +

Description.

+

+mball is the allfiles and newfiles listing generator that +can be made available on your bbs for your users to get a complete listing +of wat is available for download. When used with the -zip +option it can also produce complessed versions of these two listings. The +resulting files are created in the current directory. After the creation of +these files you can hatch them into your bbs with the programs +mbfido tic when you properly setup a .tic file area for this purpose +and create records for the hatch manager. +

+It can also create 00index files in each download directory +for FTP users. Because this file starts with double zero it is most likely the +file at the top in each directory. At the same time HTTP pages are created in +the download directories of your filebase. These are named index.html, +index1.html and so on, there are as many as needed. The main index is created in the root +of your filebase. If you use the default setup then a user browsing at your bbs +can type http://yoursite.org/files/index.html to see the list +of fileareas. +

 

+ +

Environment.

+

+In order to run mball you need to set the global variable +$MBSE_ROOT. This variable must point to the root of the bbs +directory structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mball index - Create 00index and HTTP files in all download directories.
+mball list - Create allfiles.txt and newfiles.txt files. +

 

+ +

Options.

+

+mball [command] -quiet - Quiet mode, supress screen output.
+mball list -zip - Create zipped listings as well. +

  + +

Setup.

+

+In mbsetup menu 1.15 you need to set the public FTP base, +the days to include in newfiles listings and the maximum security level. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbchat.html b/html/programs/mbchat.html new file mode 100755 index 00000000..87bca2da --- /dev/null +++ b/html/programs/mbchat.html @@ -0,0 +1,61 @@ + + + + + + + + +MBSE BBS Programs - mbchat - the Sysop to user chat program. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbchat - The Sysop to User chat program.

+

+ +

Synopsys.

+

+mbchat <device> +

 

+ + +

Description.

+

+The program mbchat is used for Sysop to User chat. It +must be started by the sysop if the user has paged the sysop. The sysop +must be logged in as user mbse in order to have write +permissions to the same tty as the user has. For example, if the user is +at ttyS0 (COM1), the command to chat would be mbchat ttyS0. +

 

+ + +

Environment.

+

+In order to run mbchat you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ + +

Bugs.

+

+When you try to chat with a user who is up or downloading a file, the +transfer will fail or may even block. You need to check what the user is +doing before using this program. +

+This program will not be developed anymore and will be replaced by a program +that will chat via mbsed. This is safer and can be used even +from a remote site over the net. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbcico.html b/html/programs/mbcico.html new file mode 100644 index 00000000..e9a980e1 --- /dev/null +++ b/html/programs/mbcico.html @@ -0,0 +1,222 @@ + + + + + + + + +MBSE BBS Programs - mbcico - The Fidonet mailer. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbcico - The Fidonet mailer.

+ +

+This is work in progress.... +

+ +

Synopsis.

+

+-r<role> -a<inetaddr> <node> ...
+-r 0|1        1 - master, o - slave [0]
+-n<phone>     forced phone number
+-l<ttydevice> forced tty device
+-t<tcpmode>   telnet TCP/IP mode, must be one of ifc|itn|ibn, forces TCP/IP
+-a<inetaddr>  supply internet hostname if not in nodelist
+ <node>        should be in domain form, e.g. f11.n22.z3 +(this implies master mode)
+-h            show this help message
+
+ or: mbcico tsync|yoohoo|**EMSI_INQC816|-t ibn|-t ifc|-t itn (this implies slave mode) +

 

+ +

Description.

+

+mbcico stands for MBse "Internet - Fidonet Copy In /Copy Out", +this is a FidoNet(r) compatible transport agent. It is based on +ifcico written by Eugene G. Crosser, <crosser@average.org>, +2:5020/230@FidoNet. I changed the name of the program to make the difference +between ifcico and mbcico. Nowadays it is +quite different then ifcico. +

+Currently it supports FTS-0001, YooHoo/2U2 and EMSI handshake protocols, +Xmodem, Telink, Modem7, Hydra, SEAlink with and without overdrive and +crash recovery, Bark file and update requests, WaZoo protocols: DietIFNA, +plain Zmodem (aka ZedZip, EMSI flag "ZMO") and ZedZap, WaZoo file and +update requests (nodelist flag should be XA). WaZoo file and update requests +do also work with FTS-0001 sessions, this is supported by several well known DOS +mailers also. +Password protected requests and update requests are implemented (but not +yet full tested). +

+There is also a special protocol optimized to use over TCP/IP connections, +contributed by Stanislav Voronyi <stas@uanet.kharkov.ua>, it is +identiefied by EMSI proto code TCP (not registered) and nodelist flag IFC. +The default port is 60179. There is a telnet variant on this, the default +port is 23, and nodelist flag is ITN. The telnet variant is written by +T. Tanaka. +

+There is also a Binkp implementation, this is a +bi-directional TCP/IP protocol. +This protocol is prefferred over the IFC protocol because it is +more efficient. Nodelist flag is IBN, the default port is 24554, and the +nodelist request flag is XX. This Binkp implementation supports multiple +batches, however this is only tested against another mbcico. +I don't know if any other mailer supports this option, but it is documented +in the spec's. +

+Outbound directory structure is BinkleyTerm compatible, with domains and +point subdirectories (full 5d). There are separate "protected" and +"unprotected" inbound directories for the incoming sessions with the nodes +that are in your setup. Files received during outbound sessions are always +stored in the "protected" inbound. +

+"Magic" file request processors are executable files placed in the "magic" +directory. If a request is made for a file with matching name, the +executable from the "magic" directory is run, and its stdout output is mailed +to the requestor. Full requestor's address, in the form of "John Smith of +1:234/56/7" is passed to the executable in the command line. Non-executable +files in the magic directory contain the full names to magic filenames. The +magic NODELIST can thus point to the full path and filename of your latest +nodelist. These magic names are automatic maintained by the mbfido +program when the magic name is set in the .tic file that you receive. +

+To run mbcico in master mode, you need to make dialout +devices read/writeable for mbcico, and do the same for +the directory where your uucp locks are created (usually /var/locks). +

 

+ +

Answer Mode.

+

+To make mbcico work in answer mode, you need +mgetty written by Gert Doering. mbcico must be +started with one of the following parameters: +

+FTS-0001 call:       "/opt/mbse/bin/mbcico tsync"
+FTS-0006 call:       "/opt/mbse/bin/mbcico yoohoo"
+EMSI call:           "/opt/mbse/bin/mbcico **EMSI_....."
+

+In the latter case the received EMSI packet should be passed whitout trailing +CR). To make this work mgetty must be compiled with the +-DFIDO option. Other getty programs might work. +

+To answer TCP/IP calls the following lines should be added to /etc/inetd.conf: +

+binkd   stream  tcp     nowait  mbse    /opt/mbse/bin/mbcico    mbcico -t ibn
+tfido   stream  tcp     nowait  mbse    /opt/mbse/bin/mbcico    mbcico -t itn
+fido    stream  tcp     nowait  mbse    /opt/mbse/bin/mbcico    mbcico -t ifc
+

+In the file /etc/services the following lines must be present: +

+binkd           24554/tcp               # mbcico IBN mode
+tfido           60177/tcp               # mbcico ITN mode
+fido            60179/tcp               # mbcico IFC mode
+mbse            60180/tcp               # MBSE BBS deamon
+

+In this case I installed the ITN mode at port 60177 instead of 23 like most +sysops do. +

 

+ + +

Master Mode.

+

+To make mbcico scan for pending outbound mail and do +appropriate calls, start it with -r1 flag. It will check +for Zone Mail Hour, outside ZMH only crash mail is delivered. Mail to +non-CM systems is only send when mail has the Immedidate status. +Poll request are always honnored, even to non-CM systems if there is a +poll request in the outbound. Be carefull. +The taskmanager mbtask will start calling mbcico -r1 +if it has seen the scanout semafore. After all calls are completed mbcico +will remove the scanout semafore. +During ZMH all non-compressed mail is send. File requests in the outbound do not +force calling a system. If you make a filerequest, you must also make a +poll for that node to really start the request. You can also force a call +by entering mbcico f2802.n280.z2 on the commandline. +Only one call is made then and there is no dial delay. If mbcico -r1 is +called a random dialdelay is used with each call except for internet calls. +

 

+ +

Environment.

+

+In order to run the mbcico you need to set one global environment variable +$MBSE_ROOT +This variable must point to the root of the bbs directoy structure. +

 

+ +

Return Codes.

+

+

+0        - No errors
+1..32    - Linux errors, SIGHUP, SIGKILL, etc.
+101      - No dialout ports available.
+102      - Dial failed (no CONNECT or TCP connection failed).
+103      - Could not reset the modem (no OK).
+104      - System is locked.
+105      - not used?
+106      - Nodelist lookup failed.
+107      - Call prohibited by config options.
+108      - Phone number unavailable.
+109      - No matching ports defined.
+110      - Tried to call a CM system outside ZMH.
+111..129 - Session failures (not defined).
+130      - Could not establish session, system is marked undialable.
+
+These codes are also stored in status files for nodes, with the extension +of ".sts". These are small datafiles containing three decimal numbers. +
    +
  1. Time retry code, this is the last call attempt time. This is an unsigned + long representing the number of seconds since the epoch. +
  2. Retries, this is the number of consequtive call attempts made that returned + "call failed" or other errors. This field is zeroed when the call succeeds and + when a new "poll" is created. If the value is 30, the node won't be called + anymore. +
  3. Code, this is the return code of the last attempt. +
+

 

+ +

Configuration.

+

+The behaviour of mbcico can be configured with mbsetup, +section 1.16 If something doesn't do what you want, set the debug on for +that problem. This will produce huge logfiles, but also a lot of information. +Important flags are Device IO, EMSI debug, File forward, Locking, Outboundscan +and Session. +

 

+ +

Bugs.

+

+Incoming calls from McMail mailers, McMail is quite hasty +to establish an EMSI session, and times out in less than a second. So +if your system is heavy loaded, or not too fast, McMail cannot connect +with your system. This is a known problem with McMail 1.0 and older, +later versions are ok. +

 

+ +

Authors.

+

+

+Eugene G. Crosser <crosser@average.org>   Orginal ifcico.
+Stanislav Voronyi <stas@uanet.kharkov.ua> TCP/IP code.
+T. Tanaka                                 Telnet mode.
+Martin Junius                             Rewrite of opentcp().
+Omen Technology Inc                       Zmodem protocol.
+Arjen G. Lentz, Joaquim H. Homrighausen   Hydra transfer protocol.
+Cristof Meerwald                          Implementation of Hydra in ifcico.
+P. Saratxaga                              Tty driver code, yoohoo extensions.
+Dima Maloff                               Binkp protocol.
+Michiel Broek                             Rewrite for MBSE BBS.
+
+

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbdiff.html b/html/programs/mbdiff.html new file mode 100644 index 00000000..b83c8134 --- /dev/null +++ b/html/programs/mbdiff.html @@ -0,0 +1,70 @@ + + + + + + + + +MBSE BBS Programs - mbdiff - Nodelist difference file processor. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbdiff - Nodelist difference file processor.

+

+ +

Synopsis.

+

+mbdiff [nodelist] [nodediff] <options> +

 

+ +

Description.

+

+mbdiff applies a (compressed) nodediff file against the +nodelist of the week before to create a new nodelist. The result is a new +plain nodelist and a nodelist compressed with zip. +

 

+ +

Environmet.

+

+In order to run mbdiff you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mbdiff [nodelist] [nodediff] The nodelist must be the full +path and filename without the dot and daynumber extension. The nodediff is +the full path and filename to the (compressed) nodediff file fitting on the +latest nodelist. It is adviced to make a seperate working directory where +you keep the nodelists. Don't do this in your normal nodelist directory. +When the operation is successfull, the new nodelist is in the working directory +and the old list is removed. A compressed version of the nodelist is also +placed in the working directory. From here you can hatch the new compressed +nodelist with the mbfido program. +

 

+ +

Options.

+

+-quiet - supress screen output, this switch is needed when +mbdiff runs on the background. +

 

+ +

Bugs.

+

+If you find any bugs, mispelled documentation etc, please contact the author: +Michiel Broek at 2:280/2802@Fidonet or mbroek@users.sourceforge.net +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbfbgen.html b/html/programs/mbfbgen.html new file mode 100755 index 00000000..ae37479d --- /dev/null +++ b/html/programs/mbfbgen.html @@ -0,0 +1,61 @@ + + + + + + + + +MBSE BBS Programs - mbfbgen - FileBase Generato. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbfbgen - FileBase Generator

+

+ +

Synopsis.

+

+mbfbgen +

 

+ +

Description.

+

+mbfbgen is used to import filebase areas from CD-ROM. This +util works like fbgen which is known to RA users. It reads +the file files.bbs to get the filenames and descriptions +to build the filedatabase. +

+To import a filebase you must setup the area with mbsetup. +If you are really importing from a CD that will stay mounted on your system +you must set CDrom to yes. If the files.bbs file is not in the +directory were the files are, but somewere else on the CD, you must fill in +the field Files.bbs in the edit file area screen. +If the files.bbs file is in the same directory together with the files, you may +leave that field blank. +It is handy to use a closed range of file areas. +Once you are ready with the setup start mbfbgen, enter the +start and end area numbers, the uploader name, and the import will start. +This can last quite long as from each file the 32 bits CRC is calculated +that will be stored in the filedatabase. When mbfbgen is +finished, run mbfile index to recreate the filerequest index +file. +

 

+ +

Environmet.

+

+In order to run fbgen you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbfido.html b/html/programs/mbfido.html new file mode 100644 index 00000000..50a133a9 --- /dev/null +++ b/html/programs/mbfido.html @@ -0,0 +1,260 @@ + + + + + + + + +MBSE BBS Programs - mbfido - The Fidonet mail and files processor. + + + +
+
Last update 10-Jul-2001
+

 

+ +

mbfido, the fidonet mail and files processor.

+

+ +

Synopsis.

+

+mbfido [command(s)] <options> +

 

+ +

Description.

+

+mbfido +is the program to process fidonet mail and files. In order to run mbfido +you must first start mbtask, +this is the deamon which controls all bbs activities. To prevent that +mbfido will run more than once at the same time a lock +is placed in the protected inbound with the pid of the running +mbfido program. The gateway to and from internet is also +handled by mbfido. +

 

+ +

Specifications.

+

+The recognized mail packets are type 2+ following the FSC-0039 standard with +a fallback to the old stone age packets. +Can handle messages of maximum 429467295 bytes, or less if you have less +memory available, the practical limit is about 1 Meg. Note that most mailprocessors +are only guaranteed to work to maximum 16 KBytes. +Recent experiments in the LINUX echo show that this is still true, +although most tossers seem to process mail up to 32 KBytes. +

 

+ +

Tossing Mail.

+

+First make sure you have the necessary message areas in your setup. At least +you need the badmail and dupemail areas and a netmail area for each network +you participate in. If you don't create badmail and dupemail areas then +bad (unknown area etc) and dupes are lost and you cannot check the reason why. +If you don't create the netmail areas for each network, then netmail to your +system will dissapear. It is not possible to "retoss" the badmail yet after +you have created any missing echomail areas. +

+To prevent .pkt name collision the toss of incoming mail is done in parts. +The first run is to process all uncompressed mailpackets and add mail to the +outbound. Then each compressed ARCmail archive will be uncompressed and +processed and mail will be imported and forwarded as necessary. During all +these passes all filenames are sorted by date and time, the oldest files are +processed first. +

+The recognized mail packets are type 2+ following the FSC-0039 standard with +a fallback to the old stone age packets. The packets are checked for being +addressed to one of your own aka's and for a correct password. The +password check may be switched off in the nodes setup. After all the packet +header checks the messages will be extracted from the packet file. +

+When messages are extracted from the packets, the date format is checked for +Year2000 bugs from other tossers. Several checks are done by ideas of Tobias +Ernst of 2:2476/418. It is also possible to run the pktdate +utility before each packet will be processed. Whatever date format us used in +the original message, mbfido will always rewrite the date +field in the right FTS-0001 format. +

+If the message is a netmail the message is checked for DOMAIN, INTL, FMPT and +TOPT kludges so that full 4d or 5d addressing will be possible. Then a check +is done if this netmail is addressed to one of our aka's. If it's addressed to +"sysop" or "postmaster" the name is replaced with the sysop's name. If the +message is addressed to one of the names defined in the service setup, that +mail will be handled by the service manager, ie. given to areamgr, filemgr or +send further as email to your local system. +
+Then the message is checked if it is addressed to an existing bbs user, and if +so it will be imported into the netmail area of the main zone of the bbs. +If it's not addressed to a bbs user, the message will be readdressed to the +sysop. If the message is not for one of our aka's the message will be put in the +mailqueue for further routing. +

+If the message is a echomail message it will be checked for being a duplicate by +storing the CRC32 value of the AREA: line, message subject, origin line, +message date and msgid kludge and testing if that CRC32 value exists in the +echomail duplicate database. If there is no msgid in the message, the whole +message body will be include to complete the CRC32 dupe check. +Also the existance of the echomail area is checked and the node must be linked to that area. +If the message is not in a passthru area and is not a duplicate it +is finally imported in the message base. +After that is the message will be forwarded to downlinks +by adding the message to the mailqueue. +

 

+ +

Adding mail to the outbound.

+

+Adding mail to the outbound is done in two passes. The first pass is to put all +outgoing mail into the ~/tmp directory, these files are named z.n.n.p.ext +The extension can be qqq for packed mail, nnn for normal unpacked mail, hhh for +hold unpacked mail and ccc for crash unpacked mail. Adding mail to this tmp +directory can allways be done, even if one of the nodes you are adding mail +for is having a mail session with your system. This is a safe operation.
+In the second pass, these temp files are really added to the outbound, but +only if the destination node is not locked, ie. there is no current mailsession +with that node. If there is a mail session going, these temp files will stay in +the temp directory and are added to the outbound in a later run of +mbfido. If adding the mail to the outbound succeeds +the temporary file is removed. +

 

+ +

Alias file.

+

+If the file /opt/mbse/etc/aliases excists, mbfido will try to fetch ftn-style +aliases from there. +If "from" address of a message from FidoNet matches right side +of some entry in alias file, then the Reply-To: header is created +in the RFC message with the name part taken from the left side of the +sysalis entry and domain part taken from myfqdn (below). E.g., if a +fidonet message comes from "John Smith of 1:234/567.89@fidonet" and +there is an entry in the sysalias file: +

+"jsmith:      John.Smith@p89.f567.n234.z1.fidonet.org"
+
+and Domain name value is "mbse.nl", then the resulting message will +contain a line: "Reply-To: jsmith@mbse.nl". +

 

+ +

Commands.

+

+mbfido notify <nodes> +This command will send notify messages to all nodes in your setup which +have the notify option set to on. If you enter nodes as option you may use +wilcards, ie 2:*/* to send messages to all nodes in zone 2. If you specify +exactly one node, messages will be generated even if that node has the +notify function off. From cron you should not specify any nodes, this will +just send to all your links the information about their setup. Each node +will receive a status report for files and mail, and area list for all +file areas and mail areas to each aka a node has, and a flow report for +mail for each aka. +

+mbfido roll +This command will only do something if a new week or month has begun. +If this is true the statistic records in several databases are updated. +You should run this command each midnight from cron to be sure that this when it is +time to do so. This command is always executed before one of the scan, toss or tic commands so +if you don't do this in cron, it will still happen. +

+mbfido scan +Scan for new messages entered at the bbs or by other utilities. If the file +~/tmp/echomail.jam or ~/tmp/netmail.jam exists, +mbfido will only scan the messages in areas which are +pointed at in this file. This is a lot faster then a full mailscan. +If it is not present, all messagebases are scanned +to see if there is a new message. If you specify +-full on the commandline a full messagebase scan is forced. +It is wise to do this sometimes, on my bbs I run this once a day. +

+mbfido tag +The command will create tag- and areas files in the doc directory for each group of +mail and files. +

+mbfido test +This is for testing of the mail routing. In the source "tracker.c" I have +included a list of nodes that will be tested. This is for development only, +but it might be handy for you to test your netmail routing. +

+mbfido tic +Process incoming files accompanied with .tic control files. Several actions can +take place on the incoming file before they are imported in the BBS areas. +Options are rearchiving, replacing banners (with your add), check for DOS +viruses, running scripts for certain filename patterns, send these files to +other nodes etc. All options can be defined for each area. If as a result from +one of the actions there are new files hatched, for example after processing +a nodelist difference file which created a new nodelist, the .tic processing +will start again, until there is really nothing more to do. +

+mbfido toss +Toss incoming fidonet netmail and or echomail. By default mail in the protected +inbound directory will be processed, uncompressed .pkt files and compressed +arcmail bundles are recognized, filename case doesn't matter. +

+mbfido news Scan all defined newsgroups for new newsarticles. +New articles are fetched from the newsserver and stored in your messagebase and +send to your up- and downlinks. This is for use with an NNTP gateway. +

+mbfido uucp +This will read a standard a newsbatch from stdin and gate the articles +to Fidonet and the local message base. This is for use with an UUCP gateway, this +mode should be called by uuxqt. The newsbatch may be compressed or uncompressed or +a single news article. +

+mbnews +This is an alternative to mbfido uucp -quiet. +

 

+ +

Options.

+

+mbfido [command] -nocrc +Disable CRC checking of incoming TIC files. Only use this if you know what +you are doing. +

+mbfido scan -full +Force scanning of all message bases for new entered mail. You need this if +mail in entered with other editors then from mbse. Also, running it once a +day is adviced to catch any missed messages. +

+mbfido news -learn +Scan the newsserver for news articles, and update the news dupes database only. +Use this switch if you start using mbfido to gate news articles for the first time. +Articles will not be gated with this switch, mbfido will just learn which articles +already excist. Normally you only need to use this switch once. +

+mbfido [command] -nodupe +Disable checking for duplicate's. Normally you should not use this switch. +This switch doesn't work with the news command, only for echomail and tic files. +

+mbfido [command] -quiet +Quiet mode, all output to the current tty is supressed. Use this flag if +you toss mail from a script (started by cron) after mail is received. +

+mbfido toss -a Toss mail and allow to autocreate +new message areas. See the message area setup +how to set this up. +mbfido toss -unsecure +Toss mail without checking if the echomail is for your own system en without +checking if the sending node is connected to your system. Nodes who are +excluded from a certain echo, can stil not enter messages in that echo. +

+mbfido [command] -unprotect +Toss from the unprotected inbound directory. The default is to toss from the +protected inbound directory. +

 

+ +

Environment.

+

+In order to run the bbs you need to set one global environment variable +$MBSE_ROOT +This variable must point to the root of the bbs directoy structure. +

 

+ +

Bugs.

+

+There are still bugs, this program is under development. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbfile.html b/html/programs/mbfile.html new file mode 100644 index 00000000..1afc6dfb --- /dev/null +++ b/html/programs/mbfile.html @@ -0,0 +1,93 @@ + + + + + + + + +MBSE BBS Programs - mbfile - File database maintenance program. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbfile - File database maintenance program.

+

+ +

Synopsys.

+mbfile [commands] <options> +

 

+ +

Description.

+

+mbfile +is the filedatabase maintenance program for mbsebbs. In order to run mbfile you +must have started mbsed, +this is the deamon which controls all bbs activities. +

+The main purpose of mbfile +to do automatic maintenance on the downloadable files on the bbs, such as +removing or moving old files, checking the database and packing the database. +The best way to do the maintenance is to run mbfile +from the crontab. example: +

+30 05 * * * export MBSE_ROOT=/opt/mbse; /opt/mbse/bin/mbfile kill pack check index -quiet
+
+

 

+ +

Environment.

+

+In order to run the bbs you need to set one global environment variable +$MBSE_ROOT +This variable must point to the root of the bbs directoy structure. The +main configuration file config.data +must exist in the subdirectory ~/etc. +

 

+ +

Commands.

+

+mbfile check +Check the database integrity. All files in the filedatabase must exist on +disk and all files on disk must exist in the filedatabase. There are some +exceptions, files.bbs, files.bak, 00index, index*.html, header, readme and +files that start with a dot. +Of all files the date and time is checked, the size and the crc +value of the file. If there is something wrong, the error is corrected or the +file is removed. If the area is a CD-rom area, the check that files on disk +must exist in the filedatabase is skipped. +

+mbfile index +Create fast filerequest index for the mbcico filerequest +processor. +

+mbfile pack +This command will actualy remove the records of files that are marked for +deletion. If the file is still on disk, it will be removed also. So when +you delete files with mbsetup, they are still in your database and on disk +until you run mbfile pack. +

+mbfile kill +Delete or move files in areas that have the download age +set or the filedate age set. A setting of 0 is ignored. +Areas on CD-rom are always skipped. +If the Move to Area option is set the files are moved to the given area. The +upload date and download date are reset to the current date and time. +So if you set in the destination area aging of 14 days, files will stay +there for 14 days after the move. This is good for automatic "last chance" areas. +

 

+ +

Options.

+

+mbfile [command] -quiet +Quiet mode, no screen output. Use this switch if you run mbfile from the crontab. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbindex.html b/html/programs/mbindex.html new file mode 100644 index 00000000..862e70cd --- /dev/null +++ b/html/programs/mbindex.html @@ -0,0 +1,68 @@ + + + + + + + + +MBSE BBS Programs - mbindex - Nodelist Index Compiler. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbindex - Nodelist Index Compiler.

+

+ +

Synopsis.

+

+mbindex <options> +

 

+ + +

Description.

+

+mbindex is the nodelist index compiler. It will create +an index file containing the sorted fidonet addresses as index file to the +raw nodelists in the defined nodelist directory. Several other programs +use this index file for fast retreival of data from the nodelists. Compiling +new nodelist indexes can always be done, while compiling the result +is stored in temporary index files and only after successfull compilation the +original indexes are renamed and the temporary files get the normal names. +The renamed (old) indexes stay on disk including the previous version of the +old raw nodelist. They stay there in case some program had the nodelist or +index still open. So in the nodelist directory there are current nodelists, +previous +nodelists, current indexes and previous indexes, and during compiling the +temporary indexes. There is no need to manually remove (and not wise to do so) +files from the nodelist directory. +

+The nodelists in the nodelist directory are the normal uncompressed nodelists +in MS-DOS format (with CR/LF). The filename extensions must be two or 3 digits. +So if you have a private pointlist named bestbbs.pts you +will have to rename that to bestbbs.999 to make it work. +

 

+ +

Environment.

+

+In order to run mbindex you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Options.

+

+mbindex -quiet Quiet mode, no screen output. Use the switch +if you run mbindex from a shellscript or from the crontab. +

 

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mblang.html b/html/programs/mblang.html new file mode 100644 index 00000000..e79edd6c --- /dev/null +++ b/html/programs/mblang.html @@ -0,0 +1,38 @@ + + + + + + + + +MBSE BBS Programs - mblang - Language Data Compiler. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mblang - Language Data Compiler

+

+ +

Synopsis.

+

+mblang [language data file] [language source text] +

 

+ +

Description.

+

+mblang compiles the source textfile to language datafile +which is used by the mbsebbs program. You only need to +use this program if you install a new language file. When you build the +complete mbse bbs package, this command is run automatic for you. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbmail.html b/html/programs/mbmail.html new file mode 100755 index 00000000..70fe3f2f --- /dev/null +++ b/html/programs/mbmail.html @@ -0,0 +1,47 @@ + + + + + + + + +MBSE BBS Programs - mbmail - Mail User Agent for the email gate. + + + +
+
Last update 10-Apr-2001
+

 

+ +

mbmail - Mail User Agent for the email gate.

+

+ +

Synopsys.

+mbmail -r<addr> -g<grade> -c<charset> -b <recip> +

 

+ +

Description.

+

+mbmail +is the Mail User Agent that should be called by your Internet mailer to deliver +mail to Fidonet systems. This program must always run as user mbse so +your mailer must be capable of doing so. The Postfix mailer I use can do that. +

+ +

Commandline options.

+

+mbfile -r<addr> -g<grade> -c<charset> -b <recip> +The -r<addr> is the address to route the packet to. This should normal be set by +the Internet mailer to one of your aka's. The -g<grade> is the packet flavor. This +can be one of the characters n, c or h which means normal, crash or hold. The -c<charset> will +force a certain characterset. Normally this will be automatic set. The -b switch disables splitting +of long messages. The <recip> are one or more recipients for the message. The message itself is +read from stdin. +

+Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbmon.html b/html/programs/mbmon.html new file mode 100644 index 00000000..3c73ab64 --- /dev/null +++ b/html/programs/mbmon.html @@ -0,0 +1,45 @@ + + + + + + + + +MBSE BBS Programs - mbmon - MBSE BBS Monitor. + + + +
+
Last update 07-jun-2001
+

 

+ +

mbmon - MBSE BBS Monitor

+

+ +

Sysnopsis.

+

+mbmon +

 

+ +

Description.

+

+mbmon is the monitor program so that you can see what is +happening on your bbs. It can show all processes and actions of all programs, +show system statitistics, disk useage, and the last callers list. +mbmon must run on the same system where the bbs is. +

 

+ +

Environment.

+

+In order to run mbmon you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbmsg.html b/html/programs/mbmsg.html new file mode 100644 index 00000000..4bc50324 --- /dev/null +++ b/html/programs/mbmsg.html @@ -0,0 +1,93 @@ + + + + + + + + +MBSE BBS Programs - mbmsg - Message Base Utility. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbmsg - Message Base Utility

+

+ +

Sysnopsis.

+

+mbmsg [commands] <options> +

 

+ +

Description.

+

+mbmsg +is the message base utility program for mbsebbs. In order to run mbmsg you +must have started mbsed, +this is the deamon which controls all bbs activities. +

+The main purpose of mbmsg +is to link messages after tossing mail, and to maintain the size of the message +bases and the age of the messages. The best way to do the maintenance is to +run mbmsg +from the crontab. example: +

+30 05 * * * export MBSE_ROOT=/bbs; /bbs/bin/mbmsg kill pack link -quiet
+
+Another purpose is to automatic post messages in message areas. Echomail and +netmail is possible. +

 

+ +

Environment.

+

+In order to run mbmsg you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mbmsg link Link all messages by subject ignoring +Re: in the subject lines. You should run this after tossing or scanning mail. +

+mbmsg kill Kill messages in areas that have the +age set or the maximum messages set. +A setting of 0 is ignored. The messages are not removed from the message base, +they are only marked as deleted. +

+mbmsg pack This command actualy removes the +messages who have the deleted flag set. +The lastread pointers are updated and the messages renumbered. After this +command there is no way you can recover your messages, except from backups. +

+mbmsg post <to> <#> <subj> <file> <flavor> + This command posts a message in numbered area. If a field +consists of more then one word it must be surounded with quotes. +The to field can be "Michiel Broek" for a full name or +"Michiel_Broek@f16.n2801.z2.fidonet" for netmail addressing. Look out: +you need underscore between the firstname and lastname, no spaces. +Flavor can be one or more of the characters "c", "i", "h" or "p" to set the Crash, +Immediate, Hold or Private flags. +If no flavor is needed, use the - (minus sign) as a placeholder. +

 

+ +

Options.

+

+mbmsg [command] -area <#> +Process only one area <#> number. +

+mbmsg [command] -quiet Quiet mode, +no screen output. Use this switch if you run mbmsg +from the crontab. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbout.html b/html/programs/mbout.html new file mode 100644 index 00000000..ec860b00 --- /dev/null +++ b/html/programs/mbout.html @@ -0,0 +1,105 @@ + + + + + + + + +MBSE BBS Programs - mbout - The Outbound Manager. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbout - The Outbound Manager

+

+ +

Synopsis.

+

+mbout [command] <params> <options> +

 

+ +

Description.

+

+mbout is the outbound manager for MBSE BBS. It can ask +information from the nodelists, create and remove polls, request and send files and +display the outbound status. Most of the tasks such as create and remove +polls should be done from the crontab. +

 

+ +

Environment.

+

+In order to run mbout you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mbout att <node> <flavor> <file> will attach +the specified file to the specified node. The node should be in the format +f2802.n280.z2, flavor should be crash, immediate, normal or hold. Only the first +letter of the flavor parameter is needed. +If the node is not in the nodelist, the status is Down or Hold, then this command fails. +To non-CM nodes you mus use the Immediate flavor if you want to send the file direct. +The flavors Hold and Normal are still allowed. The file must be in the directory range +from where file attaches are allowed. +

+mbout poll [node..node] creates poll requests in the outbound +for one or more nodes. The node should be in the format f2802.n280.z2. The semafore +scanout is created so that the mailer will start calling. +The mailer will handle the poll request as if it should deliver immediate mail, +so the node will be called as long as the poll request exists, even to nodes which are not CM. +The error counter for the node to poll will be reset to zero, so a node that was +previous marked undialable will be called again. +If a call to a node is successfull, the poll file will be removed by mbcico. +If a node is not in the nodelist or has the status Down or Hold, no poll will be created for that node. +

+mbout stop [node..node] removes poll requests that are +leftover when polling nodes didn't succeed. There is no check if the node is +in the nodelist or has the status Down or Hold, the poll is always removed. +

+mbout req <node> <file> [file..file] creates +filerequests to a node. One or more filenames may be given including wildcards. +It is not possible to do update or password protected uploads yet. If there +is already a requestlist for that node, the new requests will be added. This +command does not call a node, you need to create a poll request to make the +actual call. This is also practical if you want some files from your uplink, +just make the requests and the actual request is send when your normal +scheduled poll to your uplink is processed. +

+mbout stat shows the status of the mailer outbound. +This status is also written to the logfile. +

+mbout node <node> will show the nodelist information for +a certain node. +

 

+ +

Options.

+

+mbout [commands] -quiet will suppress screen output. This is +usefull if you run mbout from the crontab or from background +scripts. +

 

+ +

Examples.

+

+This is an example of crontab entries that writes the outbound status to the +logfile and creates and stops polling of 2 nodes.
+

+00 00 * * * export MBSE_ROOT=/opt/mbse; $MBSE_ROOT/bin/mbout stat -quiet
+00 01 * * * export MBSE_ROOT=/opt/mbse; $MBSE_ROOT/bin/mbout poll f98.n100.z92 f0.n100.z92 -quiet
+00 02 * * * export MBSE_ROOT=/opt/mbse; $MBSE_ROOT/bin/mbout stop f98.n100.z92 f0.n100.z92 -quiet
+
+

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbpasswd.html b/html/programs/mbpasswd.html new file mode 100644 index 00000000..487838df --- /dev/null +++ b/html/programs/mbpasswd.html @@ -0,0 +1,66 @@ + + + + + + + + +MBSE BBS Programs - mbuseradd - The useradd wrapper. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbpasswd - The password wrapper.

+

+ +

Synopsis.

+

+mbpasswd [-opt] [username] [password] +

 

+ +

Description.

+

+mbpasswd is the wrapper for the passwd program +is present on all Linux systems. To use passwd to change the password of +another user is only allowed by root. The mbpasswd program overcomes this limitation. +The wrapper mbpasswd is run from the bbs by user mbse when an ordinary +user is logged in the bbs. The program is called when a new user logs in the bbs or +when an excisting user changes his password. His password under Unix is then always the same as his +password in the bbs program. This is necessary for the user to be able to get +his email using the pop3 protocol.

+You never need to run mbpasswd by hand, in fact it is protected so that only +members of group bbs are allowed to use it. +

 

+ +

Environment.

+

+mbpasswd must be installed setuid root and setgid root, ls -la looks like this:
+

+-rws--s--x   1 root     root         6644 Jun 26 21:23 /opt/mbse/bin/mbpasswd*
+
+

 

+ +

Commands.

+

+mbpasswd [-opt] [username] [password] for example:
+

+mbpasswd -f michiel secret
+
+Valid options are -f (forced), this will also change locked passwords, +this has only effect if your system uses shadow passwords. If you use +-n as option, locked passwords cannot be changed. For a new user the +-f option is used by mbsebbs, when a user changes his own password the +-n option is used. +

+ + +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbsebbs.html b/html/programs/mbsebbs.html new file mode 100644 index 00000000..632d1243 --- /dev/null +++ b/html/programs/mbsebbs.html @@ -0,0 +1,149 @@ + + + + + + + + +MBSE BBS Programs - mbsebbs - The main BBS program. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbsebbs - The main BBS program

+

+ +

Synopsis.

+

+mbsebbs +

 

+ +

Description.

+

+mbsebbs is the main bbs program for the users. +To be able to use the bbs, the bbs mustbe set open with mbstat open +or users may not login. This is normally done at system boot. +Also Zone Mail Hour is honored if the user logs in +on a tty that has the honor ZMH flag set to true. If it +is ZMH and the ZMH flag is true, the user will be kicked out of the bbs. You +should only set this flag on the modem lines where you need to be available +for ZMH if your "Fidonet" network requires that. +

+The first visible action is to show the logo.ans file. Because it is not +known who is trying to login, you only need to place this file in the +default language directory. +

+The next check is to see if the user is allowed to login on the tty he +currently is on. +If this tty is not available or is not in your setup, the user is kicked +out. If he is allowed to login, a message is shown at which port he is on, +unless you have turned this feature off in the setup. +

+If a user logs in the first check is if he/she has a Unix account or not. +Unix users bypass the login prompt. Other users will get the normal prompt +the same way DOS based bbs programs do. At that time it is checked if the +user has IEMSI capabilities, if that is true, IEMSI login will be tried. +If the user is not known, the newuser procedure begins. +

+If the user login is successfull, his favourite language will be loaded. +Then it is checked if the user is the Sysop, if so, the Sysop flag is set. +If the user has a blank password, he is asked to create a new password. +Next it is checked if the user has an Unix account, if not he is forced to +create a Unix account. This situation can exist after switching to MBSE BBS +and you have converted your old userbase to the userbase for MBSE BBS. +If the users Date of Birth is invalid, he is forced to enter the right +Date of Birth. +The next check is to see if the user has passed the expiry date, this is a +usefull feature for systems with donating users. +Finally the access limits are set for the user and time remaining for today and +download limits are set. +

+After successfull login the user can be presented with a bunch of advertising +screens. I will only name the screens without filename extension, as these +screens are searched for in the following order;
+

    +
  1. filename.ans in the users favourite language directory. +
  2. filename.ans in the default language directory. +
  3. filename.asc in the users favourite language directory. +
  4. filename.asc in the default language directory. +
  5. If nothing is found, nothing is displayed. +
+welcome. This screen can contain information about the session +the user has, his download limits, time left etc. +

+welcome1 is shown if the user has show bulletins set to true. +

+birthday is shown if the user logs in at his birthday and if he +has show bullentins set to true. +

+dd-mm is shown if dd is the date of today and +mm is the current month and if the user has show bulletins +set to true. +

+sec20 is shown if the user has the security level in the +filename, level 20 in this example. Als the display bulletins must be set to +true. +

+news is shown if the user has the display bulletins set to +true. +

+onceonly is shown only if the user has never seen this screen, +the test is to compare the users last login date against the date of this file. +

+After all these screens the users Offline Reader areas are checked to see if +you as sysop didn't change the message areas. If you made changes, the users +setup is adjusted and he will be notified. This means he sees a list +with deleted areas and new areas. +

+Next if the user has newmail scan set to true all message bases are checked to +see if the user has new mail. This includes a check to see if he has Unix mail. +If there is Unix mail, those mails are retrieved from the POP3 server and stored +in his private mailbox. +If there is new mail for the user, the user sees a list of areas with the messages +in it and he is offered to read and reply these messages. +

+Then if the user has show newfiles set to true and he is not a new bbs user +he will see a list of new files you have on your bbs. During this display +he can tag files for later download. +

+The final setup is to set the users "do not disturb" flag and then the menu +system is started. The menu system will run forever, until the user chooses +to logoff, the connection is lost or his daily timelimit is reached. For the +possibilities and setup of the menus see +MBSE BBS Menu System +

 

+ +

Environment.

+

+In order to run mbsebbs you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

+If the environment variable CONNECT is present, a log entry +will be made with the connect speed. +

+If the environment variable CALLER_ID is present, a log entry +will be made with the caller id. +

+If the environment variable LOGNAME is present and it is not +bbs then it is assumed that it is a Unixmode login of the +user who's Unixname is in the LOGNAME environment variable. +This variable is set by the /bin/login program, so users that telnet to your +bbs or login via mgetty and login with their Unixname will +set this. If the LOGNAME is bbs then the +user is prompted to enter his Fidonet style name. By the way, you can change +that default bbs username with mbsetup. +

 

+ + +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbseq.html b/html/programs/mbseq.html new file mode 100644 index 00000000..1ab89e47 --- /dev/null +++ b/html/programs/mbseq.html @@ -0,0 +1,49 @@ + + + + + + + + +MBSE BBS Programs - mbseq - Sequence number creator. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbseq - Sequence number creator

+

+ +

Synopsis.

+

+mbseq +

 

+ +

Description.

+

+mbseq writes a eight character hexadecimal unique sequence +number to the stdout. This number is received from mbsed +which keeps track of the generated sequence numbers. This written number can +be used in shell scripts to create unique filenames for Fidonet .pkt files, +for example: +

+ +cp temp.pkt `mbseq`.pkt + +

 

+ +

Bugs.

+

+Nah, it's only 50 lines code, what could go wrong? +

+ + +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbsetup.html b/html/programs/mbsetup.html new file mode 100644 index 00000000..42733478 --- /dev/null +++ b/html/programs/mbsetup.html @@ -0,0 +1,50 @@ + + + + + + + + +MBSE BBS Programs - mbsetup - The Setup Program. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbsetup - The Setup Program

+

+ +

Synopsis.

+

+mbsetup +

 

+ +

Description.

+

+mbsetup is the setup program for MBSE BBS. It should be run +only by user mbse. If you run it by accident as root file +permissions will be wrong and your bbs may not function. For a detailed +description of all setup options see MBSE BBS +Setup Guide +

 

+ +

Environment.

+

+In order to run mbsetup you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. If it is not present, ie you run +mbsetup for the first time, a default +config.data will be created. This will also happen with +several other databases. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbstat.html b/html/programs/mbstat.html new file mode 100644 index 00000000..f589c93e --- /dev/null +++ b/html/programs/mbstat.html @@ -0,0 +1,79 @@ + + + + + + + + +MBSE BBS Programs - mbstat - MBSE BBS Status Changer. + + + +
+
Last update 07-Jul-2001
+

 

+ +

mbstat - MBSE BBS Status Changer

+

+ +

Synopsis.

+

+mbstat [commands] <options> +

 

+ +

Description.

+

+mbstat changes the bbs status between open and close, can wait +for all users to logoff and wait for critical utilities to stop their actions. +

 

+ +

Environment.

+

+In order to run mbstat you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mbstat semafore scanout will set the internal +semafore scanout in the mbtask daemon. The following semafore's +are valid: scanout, mailout, mailin, mbindex, reqindex, msglink. +

+mbstat close will close the bbs for users. +Users that are just logging in to the bbs will be thrown out after a short message. +Users already logged in will be thrown out when they pass by a menu prompt. +So users who are doing file transfers can finish their transfers before being disconnected. +

+mbstat open opens the bbs for users. +This should be run from one of the system startup scripts right after you started +mbsed. If you installed everything as it should this +command is already executed at system startup. +

+mbstat wait will +wait for the bbs to become free. This includes a check for utilities that +do critical actions so they can finish their job without corrupting the bbs +databases. The default is to wait 60 minutes. If the semafore +upsdown exists it will wait only 30 seconds. +

+You should run mbstat close wait in your system shutdown script so +that the system shutdown will wait for a clean shutdown of the bbs before +the rest of your system goes down. If you installed everything as it should +be then these commands are already installed in your system shutdown scripts. +

+ +

Options.

+

+mbstat [command] -quiet will supress screen output. +This is good for using mbstat in scripts. +

+ + +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbtask.html b/html/programs/mbtask.html new file mode 100644 index 00000000..bc0cfebc --- /dev/null +++ b/html/programs/mbtask.html @@ -0,0 +1,319 @@ + + + + + + + + +MBSE BBS Programs - mbtask - MBSE BBS Taskmanager. + + + +
+
Last update 07-Jul-2001
+

 

+ +

mbtask - MBSE BBS Taskmanager

+

+ +

Sysopsis.

+

+mbtask +

 

+ +

Description.

+

+mbtask is the taskmanager for the whole MBSE BBS system. +This deamon keeps track of all client actions, +does the logging for the clients, does database locking, authorizes clients, +set/resets users "do not disturb flags", sends and receives chat messages, +keeps track of Zone Mail Hour and the BBS open/close status. Communication +between mbsed and the client programs is done via Unix +Datagram sockets. The protocol used to communicate between mbtask +and the clients is explained later. +This daemon also watches the semafore directory for some special files. +It also starts programs when they are needed. +The very first time mbtask is started it creates a default config.data and task.data, +the main configuration and task configuration files +mbtask should be started at system boot so the bbs system will start working. +The init script that is installed on your system will do that. +This program is introduced with MBSE BBS v0.33.16 +and replaces the run_inout and mailer scripts that were called by cron every minute. +

+After startup and initalization mbtask runs internally once per second forever. +If there is nothing to do then this time will slowly increase upto 5 seconds. This time will be reset +to one second as soon as there is work to be done. The actual work is to check a number of external and +internal semafore's and act on these. +But before any program is started a number of things are checked: +

    +
  1. Check the system's load average. If it is too busy the processing of background + tasks is suspended until your system load drops. + The default setup is set at 1.50 but you can change that with mbsetup. Experience + will learn what the best value will be and I need some feedback on that.
    +
  2. The UPS semafore upsalarm will be checked. This means that the system is running on + battery power and no new jobs are started. +
  3. The UPS semafore upsdown will be checked. This is the fatal one, if + this one excists mbtask will try to stop all current running jobs. + If there are no jobs left running then mbtask will stop itself. + The upsdown semafore means that the system + will shutdown and power off, that's why it's fatal and there is no way back.
    +
  4. The status of the bbs will be checked, is it open or closed. If it is closed, no + jobs will be started. +
  5. The Zone Mail Hour is checked. If ZMH begins the semafore's zmh is created and + a outbound scan is forced. + If ZMH ends the semafore zmh is removed a new outbound scan is forced. +
  6. Each twenty seconds a ping is send to the IP addresses defined with mbsetup to + check if the internet can be reached. If both ping addresses fail, it is assumed that + the internet can't be reached. Note: this is for future use! +
+Each new minute the timestamp of semafore mbtask.last is updated so that you can check that +mbtask is running. Also each minute is checked if the system configuration files are +changed, is so they are reloaded. There is no need to stop and start mbtask if you made +changes to the system configuration. +Then all kind of internal semafore's will be checked. The commands that are executed have default +values, but they can be changed wit mbsetup. The commands can be scripts as well. +The checks and actions are: +

+ + + + + + + + + + + + + + + +
SemaforeSpeedTasktypeDepends onJob to run
mailoutFastmbfidoMax. 1 mbfido taskmbfido scan web -quiet
mailinFastmbfidoMax. 1 mbfido taskmbfido tic toss web -quiet
newnewsFastmbfidoMax. 1 mbfido taskmbfido news web -quiet
mbindexFastmbindexNo other tasksmbindex -quiet and if excist: goldnode
msglinkFastmbfidoNo other tasksmbmsg link -quiet
reqindexFastmbfileNo other tasksmbfile index -quiet
scanoutSlowcallOnly 1 call taskmbcico -r1
+

+The Fast and Slow values mean: Fast is each second, Slow is check each 20 seconds. +As you can see, the system will not do too much at the same time. Jobs like compiling +new nodelists or create file request indexes have a very low priority. Because this +daemon checks the semafore's each second it responds much better that the old scripts +running on the cron daemon. The system will be expanded so that more outgoing calls +will be done at the same time, ie. ISDN and analogue calls, and if they are present +internet calls, will be made at the same time. +

+The mbtask program keeps also track of a unique number generator, this is +just a simple counter that is increased each time it is asked for a new number. +It will take years for the numbers to repeat. Even if the status file is lost +the chance that numbers are repeated on your system are almost zero. The first +time the counter is initialized it is set to the current unix time in seconds +since 1 januari 1970. This counter is used by several programs to create unique +.pkt filenames, msgid numbers etc. +

 

+ +

Environment.

+

+In order to run mbtask you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. +

 

+ + +

Security.

+

+mbtaskmbse before the child process is created and the rest +of the initialisation is done. +The child process can never get root privileges because it is spawned by user mbse. +

 

+ + +

Communications.

+

+Communication between the server and the clients is established by +Unix datagram sockets. There can be only 1 server running. +The server will accept connections from clients on your local machine only. +The limit for the amount of clients that can connect to the server is set to 100. +

+The server creates a Unix datagram socket at startup and waits for connections. +The name of this this socket is /opt/mbse/tmp/mbtask. +When a client connects it creates a Unix datagram socket in /opt/mbse/tmp, the name is +the name of the program, added with the pid of the program. So if mbcico is started +with pid 2312 the socket will be /opt/mbse/tmp/mbcico2312. +

+All commands are 4 capital letters followed by a colon, a number indicating +how much data fields will follow. If that number is higher than zero, the +data fields are seperated with commas. The command is terminated +with a ; character. Examples are:
+

+GCLO:0;                 Zero datafields command.
+DOPE:1,dbname;          One datafield command.
+
+All commands will receive a reply as soon as possible. If a +resource is temporary not available, a reply will follow too, telling +this condition. Replies can also contain optional data. Examples:
+
+100:0;                  Response 100, no data.
+200:1,Syntax error;     One datafield.
+
+The server has a 10 minute timeout for receiving data when a connection +is established. The clients need to "ping" the server at regular intervals +to prevent a disconnect. All official MBSE BBS programs do that. The pid +send with most commands is the pid of the calling program. Since this number +is unique, it is used to keep track of the connected clients. +

+The commands are divided in 26 catagories, most unused at this time. +

+

+Catagories:
+
+Cat.    Description
+----    -------------------------------------------
+Axxx    Accounting, system monitor info etc.
+Cxxx    Chatting
+Gxxx    Global commands.
+Sxxx    Status commands.
+
+
+
+         Group A, Accounting.
+
+Command: AINI:5,pid,tty,uid,prg,city;   Initialize connection, and who am I.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ADOI:2,pid,doing;              What am I doing right now.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ACLO:1,pid;                    Close my connection.
+Reply:   107:0;                         Connection closed.
+         200:1,Syntax Error;            Error, connection is still open.
+
+Command: ALOG:5,fil,prg,pid,grade,txt;  Write a line of text in logfile with grade.
+Reply:   100:0;                         Ok.
+         201:1,errno;                   Error, number in errno.
+
+Command: AUSR:3,pid,uid,city;           Set username and city
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ADIS:2,pid,flag;               Set Do Not Disturb flag.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ATIM:1,time;                   Set new Client/Server timer in seconds.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ADEF:0;                        Set Client/Server timer to default (10 minutes).
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ATTY:2,pid,tty;                Set new tty name.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+
+         Group C, Chatting (just some ideas).
+
+Command: CIPM:1,pid;                    Is Personal Message present.
+Reply:   100:2,fromname,message;        Yes, from .. with message text.
+         100:0;                         No.
+
+Command: CSPM:3,fromuser,touser,txt;    Send personal message to user.
+Reply:   100:1,n;                       n: 0=Ok, 1=Do not disturb, 2=Buffer full, 3=Error.
+         100:0;                         Impossible.
+
+         The next commandis are some ideas, they are not implemented.
+
+        -CBPM:2,fromuser,txt;           Broadcast message to all users.
+        -CJCH:2,pid,channel;            Join Channel
+        -CCCH:2,pid,channel;            Close Channel
+        -CAML:2,channel,text;           Add textline to channel
+        -CIML:1,channel;                Is new textline present
+        -CSSP:1,user,reason;            Send Sysop Page
+        -CESP:1,user;                   Retract Sysop Page
+        -CRSP:1,user;                   Reject user Page
+        -CFCH:2,channel,user;           Force user in chatmode (for Sysop chat).
+        -CKCH:2,channel,user;           Kill user chatmode (for Sysops and moderators).
+
+
+        Group G, Global commands.
+
+Command: GNOP:0;                        No OPerations.
+Reply:   100:0;                         Ok.
+
+Command: GPNG:1,data;                   Ping, echo data.
+Reply:   100:1,data;                    Ping reply.
+
+Command: GVER:0;                        Give server version.
+Reply:   100:1,Version ....;            Version reply.
+
+Command: GSTA:0;                        Get complete mbsed status record. (13 fields)
+Reply:   100:19,start,laststart,daily,startups,clients,tot_clients,tot_peak,syntax_errs,
+                com_errs,today_clients,today_peak,today_syntax,today_comerr,bbsopen,
+                is_zmh,processing,system_load,sequence;
+
+Command: GMON:1,n;                      Get registration info line, 1=First, 0=Next line.
+Reply:   100:7,pid,tty,user,program,city,isdoing,starttime;
+         100:0;                         No more lines.
+
+Command: GDST:0;                        Get filesystem status (see note below).
+         100:n,data1, ..., data10;      Maximum 10 filesystems datalines.
+
+Command: GSYS:0;                        Get bbs statistics.
+         100:7,calls,pots_calls,isdn_calls,network_calls,local_calls,startdate,lastcaller;
+
+Command: GLCC:0;                        Get Lastcallers count
+         100,1,n;                       Return counter value.
+
+Command: GLCR:1,recno;                  Get Lastcaller record
+         100:9,user,location,level,tty,time,minsmcalls,speed,cations;
+         201:1,16;                      Not available.
+
+
+         Group S, Status commands.
+
+Command: SBBS:0;                        Get BBS Status (open, zmh, shutdown).
+Reply:   100:2,0,The system is open for use;
+         100:2,1,The system is closed right now!;
+         100:2,2,The system is closed for Zone Mail Hour!;
+
+Command: SOPE:0;                        Open the BBS.
+Reply:   100:0;                         Ok.
+
+Command: SCLO:1,mesage;                 Close the BBS with reason.
+Reply:   100:0;                         Ok.
+
+Command: SFRE:0;                        Is the BBS Free.
+Reply:   100:1,Running utilities: n  Active users: n;
+         100:0;                         It's free.
+
+Command: SSEQ:0;                        Get next unique sequence number.
+Reply:   100:1,number;                  Next unique sequence number.
+
+Command: SEST:1,semafore;               Get status of internal semafore.
+Reply:   100:1,n;                       1 = set, 0 = not set.
+         200:1,16;                      Semafore not known.
+
+Command: SECR:1,semafore;               Set semafore
+Reply:   100:0;                         Ok.
+         200:1,16;                      Error.
+
+Command: SERM:1,semafore;               Remove semafore
+Reply:   100:0;                         Ok (also if there was no semafore).
+         200:1,16;                      Semafore not known.
+
+Note: in reply of GDST the reply is 100:n,size free mountpoint fstype,..... +where n = 1 for 1 filesystem, and 10 for a total of 10 filesystems. There +will never be a reply for more then 10 filesystems. The reported filesystems +are retrieved from /etc/mtab which is the actual mountstatus. This is used +by the mbmon program to get a "live" view of your filesystems. +

 

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbtoberep.html b/html/programs/mbtoberep.html new file mode 100644 index 00000000..86413043 --- /dev/null +++ b/html/programs/mbtoberep.html @@ -0,0 +1,47 @@ + + + + + + + + +MBSE BBS Programs - mbtoberep - List newfiles to report. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbtoberep - List newfiles to report

+

+ +

Synopsis.

+

+mbtoberep +

 

+ +

Description.

+

+mbtoberep is a small utility to list the file +~/etc/toberep.data which contains the newfiles found on your system before +mbaff announce is run. This program is intended for system +development but I decided to leave it in the distribution for now. If you +pipe the output thru more or less you are able to inspect the records. +

 

+ +

Environment.

+

+In order to run mbtoberep you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbuser.html b/html/programs/mbuser.html new file mode 100644 index 00000000..b09b1665 --- /dev/null +++ b/html/programs/mbuser.html @@ -0,0 +1,71 @@ + + + + + + + + +MBSE BBS Programs - mbuser - User Database Maintenance. + + + +
+
Last update 02-Feb-2001
+

 

+ +

mbuser - User Database Maintenance

+

+ +

Sysnopsis.

+

+mbuser [commands] <options> +

 

+ +

Description.

+

+mbuser is the user database maintenance program. It can delete +users upto a certain level who have not called for a number of days. It can +also pack the user database. This is not really a pack of the database, the +deleted records are zeroed but the database is never shrinked. Every user +once in this database will keep his record forever. This is to be sure that +all LastRead Pointers will be correct. Records that are zeroed can be +reused for new users. mbuser must run setuid root and +setgid root because it executes /usr/sbin/userdel to delete the Unix account +of the user that is removed from the bbs. +

 

+ +

Environment.

+

+In order to run mbuser you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. mbuser must be +installed setuid root and setgid root, ls -la looks like this:
+

+-rws--s--x   1 root     root        23560 Jun 19 19:50 /opt/mbse/bin/mbuser*
+
+

 

+ +

Commands.

+

+mbuser kill [n] [l] will mark users to delete who have not +called in n days upto and including level l. +

+mbuser pack will delete (zero) the users marked for deletion. +You should also run this command if you marked users to delete with +mbsetup. +

 

+ +

Options.

+

+mbuser [command] -quiet will suppress screen output, this is +for running mbuser in the background or from the crontab. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbuseradd.html b/html/programs/mbuseradd.html new file mode 100644 index 00000000..92950b61 --- /dev/null +++ b/html/programs/mbuseradd.html @@ -0,0 +1,72 @@ + + + + + + + + +MBSE BBS Programs - mbuseradd - The useradd wrapper. + + + +
+
Last update 02-Feb-2001
+

 

+ +

mbuseradd - The useradd wrapper.

+

+ +

Sysnopsis.

+

+mbuseradd [gid] [username] [comment] [userdir] +

 

+ +

Description.

+

+mbuseradd is the wrapper for the useradd +program that should be present on most Linux systems. useradd +may only be executed by root and there are some other minor +things that need to be done as root to create a new Unix +account that can be used with MBSE BBS. The solution for these problems is +mbuseradd, this little program runs setuid root and setgid +root. If it fails to do that it aborts. mbuseradd is called +by mbsebbs from the newuser function. You never need to +run mbuseradd by hand. If it is successfull the user will +have an entry in /etc/passwd, the comment is his Fidonet name, and his shell +is $MBSE_ROOT/bin/mbsebbs. +

+If all this is successfull until now, the homedirectory for this user is +created and the right ownership and permissions are set. In his homedirectory +the empty file .hushlogin is placed to prevent check for +new mail when he logs into your system. This is the Unix mailcheck that is +skipped and has nothing todo with the check for new mail in the bbs. All +other directories that are needed for the bbs are created by mbsebbs. +

 

+ +

Environment.

+

+In order to run mbuseradd you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. mbuseradd must be +installed setuid root and setgid root, ls -la looks like this:
+

+-rws--s--x   1 root     root         6644 Jun 26 21:23 /opt/mbse/bin/mbuseradd*
+
+

 

+ +

Commands.

+

+mbuseradd [gid] [name] [comment] [usersdir] for example:
+

+mbuseradd bbs mbroek "Michiel Broek" /opt/mbse/home
+
+

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/routing.html b/html/routing.html new file mode 100644 index 00000000..75a1d088 --- /dev/null +++ b/html/routing.html @@ -0,0 +1,211 @@ + + + + + + + + +Netmail routing behaviour. + + + +
+
Last update 07-Jun-2001
+

 

+ +

MBSE BBS Netmail routing behaviour

+ +

Introduction

+

+The mbfido program that is responsible for unpacking, +importing, exporting and routing of netmail has a build in default routing +plan. In general this is quite simple, if we know the destination node or +his uplink, (that node or uplink is in our setup), then we will route via +that node in our setup. If the node or his uplink is not in our setup, then +the nodelist is used and normal fidonet routing is used. This means, if you +are a node, everything goes to your hub, if you are a hub, then mail for +your downlinks will go direct to the downlinks because they are in your setup, +everything else goes to the host. +If you are a host, then your own downlinks will get the mail direct, +the downlinks of the hubs in your net well be routed via the hubs below you. +If it is for a node in your region but outside your net, mail will be routed via +the other hosts in your region. Mail to outside your region will go to the +region coordinators system. +

 

+ +

Tracking and bouncing

+

+At this moment there is no bouncing of undeliverable mail. I will built this +in, but it will only work inside your own net. I will never include code for +bouncing mail outside your net, because nodelists are always not uptodate. +

 

+ +

Special routing

+

+What if you need special routing. The solution is simple, add the routing +nodes to your setup and fill in the "route via" field. If you don't have a +session password with that node, leave the password fields blank. This node +will never know that he is in your setup as long as you have the notify +settings for that node switched off. To figure +out such solutions yourself, I have included the flow diagrams for the tracking +module. +

 

+ +

Main tracking routine:

+
+
+	+=============================+
+	|     Trackmail to dest.      |
+	+--------------+--------------+
+		       |
+	++-------------+-------------++
+	||   rc = GetRoute to dest   || (See next diagram).
+	++-------------+-------------++
+		       |
+	+--------------+--------------+  yes
+	|       rc = R_NOROUTE        +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | no			| res: R_NOROUTE |
+		       |			+================+
+	+--------------+--------------+  yes
+	|       rc = R_UNLISTED       +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       |			| res: R_UNLISTED|
+		       |			+----------------+
+	+--------------+--------------+  yes
+	|        rc = R_LOCAL         +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | no			| result: R_LOCAL|
+		       |			+================+
+	+--------------+--------------+  no
+	|   routing node in setup ?   +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | yes			|   result:  rc  |
+		       |			+================+
+	+--------------+--------------+  no
+	|   "Route via" filled in ?   +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | yes			|  res: R_ROUTE  |
+		       |			+================+
+	+--------------+--------------+
+	|   Change route to address   |
+	|       result = R_ROUTE      |
+	+=============================+
+
+
+

Sub function GetRoute:

+
+
+	+=============================+
+	|          GetRoute           |
+	+--------------+--------------+
+		       |   
+	+--------------+--------------+
+	|      Add domain name	      |
+	+--------------+--------------+
+		       |
+	+--------------+--------------+ yes
+	|  Is dest our own address ?  +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			|   rc = R_LOCAL |
+		       |			+================+
+	+--------------+--------------+ yes
+	| Is dest our point address ? +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			|  rc = R_DIRECT |
+		       |			+================+
+	+--------------+--------------+ yes (route to boss)
+	|    Are we a point system    +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			| dest is my Boss|
+		       |                        |  res: R_DIRECT |
+		       |			+----------------+
+	+--------------+--------------+ yes
+	| Dest. addr. in nodes setup? +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			|  rc = R_DIRECT |
+		       |			+================+
+	+--------------+--------------+ yes
+	| Boss of point dest in setup +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			|  rc = R_DIRECT |
+		       |			|   dest = Boss  |
+		       |			+================+
+	+--------------+--------------+ 
+	| Is node listed and do we    | yes
+        | know his uplink in setup ?  +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			| dest is uplink |
+		       |			|  rc = R_DIRECT |
+		       |			+================+
+	+--------------+--------------+ yes
+	|   Are we host in network ?  +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			| Set host addr. |
+		       |			+--------+-------+
+		       |				 +----------+
+	+--------------+--------------+ yes			    |
+	|    Are we hub in domain ?   +------------------+	    |
+	+--------------+--------------+		+--------+-------+  |
+		       | no			|  Set hub addr. |  v
+		       |			+--------+-------+  |
+		       |				 |	    |
+		       +---------------<-----------------+-----<----+
+		       |
+	+--------------+--------------+
+	|    Set our region number    |
+	+--------------+--------------+
+		       |
+		       |
+	+--------------+--------------+ no
+	|       Host address set ?    +-----------------------------+
+	+--------------+--------------+				    |
+		       | yes					    |
+		       |					    |
+	+--------------+--------------+ 
+        |  Dest region <> our region  | yes			    |
+	|  or Dest zone <> our zone   +------------------+	    |
+	+--------------+--------------+		+--------+-------+  |
+		       | no			|   Dest to RC   |  |
+		       |			|  rc = R_ROUTE  |  |
+		       |			+================+  |
+	+--------------+--------------+ yes			    |
+	|     Dest net <> our net     +------------------+	    |
+	+--------------+--------------+		+--------+-------+  |
+		       | no			| to host destnet|  |
+		       |			|  rc = R_ROUTE  |  |
+		       |			+================+  |
+	+--------------+--------------+ yes			    |
+	|       Has node a hub        +------------------+	    |
+	+--------------+--------------+		+--------+-------+  |
+		       | yes			| to node's hub  |  |
+		+------+--------+		|  rc = R_ROUTE  |  |
+		| dest is direct|		+================+  |
+		|  rc = R_ROUTE |				    |
+		+===============+				    |
+								    |
+		       +------------------------<-------------------+
+	+--------------+--------------+ no
+	|       Hub address set ?     +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | yes			|  via our hub   |
+		       |			|  rc = R_ROUTE  |
+		       |			+================+
+	+--------------+--------------+ yes
+	|  Dest node of our hub addr  +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | no			|  rc = R_DIRECT |
+		       |			+================+
+		+------+-------+
+		| dest is host |
+		| rc = R_ROUTE |
+		+==============+
+
+
+ +Back Go Back +
+ + + diff --git a/html/setup/archiver.html b/html/setup/archiver.html new file mode 100644 index 00000000..9a93ac25 --- /dev/null +++ b/html/setup/archiver.html @@ -0,0 +1,44 @@ + + + + + + + + +MBSE BBS Setup - Archiver programs. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - archiver programs

+

+To process mail, files and test new uploads you need archivers to process those +files. For each (un)archiver you must setup the full path and filename and +commandline switches. Archivers and unarchivers may be different programs such +as zip and unzip.

+There is a little +difference in processing mail and files, mail will always work on the same +directory, while for ticfile processing the archives can contain subdirectories. +So it is obvious that for rearchiving a file you need the recursive +switches to keep the directory structure within an archive as it was.

+There is also a special command to replace a banner in an archive. This is when +you receive files with the banner of your uplink in it and you want to replace +it with the add of your own bbs and you don't want to mess with the files in +the archive.

+The last option is to extract the file FILE_ID.DIZ from the +archive, this can be used for file description when the file is imported in +your bbs. To make life a little more easy, during the first bbs setup the most +common archivers already configured. You only need to make sure that they are +really present on your system. +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/bbs.html b/html/setup/bbs.html new file mode 100644 index 00000000..cc6d8c76 --- /dev/null +++ b/html/setup/bbs.html @@ -0,0 +1,42 @@ + + + + + + + + +MBSE BBS Setup - Edit BBS Setup. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - Edit BBS Setup.

+

+ +

Edit BBS Setup.

+

+The BBS setup is split in the following sections: +

+ +

    +
  1. Security limits +
  2. Language setup +
  3. BBS menus +
  4. File areas +
  5. Transfer protocols +
  6. BBS List data +
  7. Oneliners +
  8. TimeBank data +
  9. Safe Cracker data +
+ +Back Back to index  +Home Back to main index +
+ + + diff --git a/html/setup/bbslist.html b/html/setup/bbslist.html new file mode 100644 index 00000000..36478cc7 --- /dev/null +++ b/html/setup/bbslist.html @@ -0,0 +1,28 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - BBS List Data. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - BBS List Data.

+

+This is not available yet. +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/domains.html b/html/setup/domains.html new file mode 100644 index 00000000..b83bb56a --- /dev/null +++ b/html/setup/domains.html @@ -0,0 +1,48 @@ + + + + + + + + +MBSE BBS Setup - Edit Domains. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Edit Domains.

+

+ +

Introduction.

+

+The domains table is used to translate Fidonet domains to internet domains +and back for the Fidonet <-> Internet gateway. When you add entries to +this table make sure that the entry .fidonet and +.ftn is always the last entry. This is the default entry. +New added domains can be moved in place with the Move +command. +

 

+ +

Edit Domains.

+

+

+Fidonet   The Fidonet domain to match.
+Internet  The internet domain to match.
+Active    If this domain is active.
+Deleted   If this domain must be deleted.
+
+

+Next is an example table. +

+ + +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/emareas.html b/html/setup/emareas.html new file mode 100644 index 00000000..0ecaad5b --- /dev/null +++ b/html/setup/emareas.html @@ -0,0 +1,164 @@ + + + + + + + + +MBSE BBS Setup - Mail Setup - Mail Areas. + + + +
+
Last update 08-Jun-2001
+

 

+ +

MBSE BBS Setup - Mail Setup -> Mail Areas.

+

+ +

Introduction.

+

+Mail areas have fixed area numbers, just like file areas. But if you want you +can move areas. +Some offline readers don't like changing the area numbers. All areas can +be of the following types: local, netmail, echomail and news. If you gate +news and echomail in the same area, then select echomail +if this area is a Fidonet area, select news if this area is a Usenet news area. +

+There is a global setup tool, if you are in the main message area setup screen then +you can choose the Global command. This will allow you to do bulk changes on areas +selected by the mail groups. Options are delete connection, add new connection, +replace connection, change connection status, change days old for purge, change +maximum messages for purge, change user security, change aka to use, change origin line, +change netmail reply board and delete message area. +

 

+ +

Message Area Setup.

+

+

+Area Name   The description of the area.
+Area Tag    The echomail area tag.
+Newsgroup   The newsgroup name if you are gating this area.
+Moderator   Leave this blank for now!
+JAM base    The path and name of the JAM message base without extension.
+Origin      The origin line to add to echomail messages.
+Fido Aka    The Fidonet aka for this area.
+QWK name    The name of the area for OffLine Readers.
+Group       The name of the echomail group.
+Distrib.    Leave this blank for now!
+Area Type   Local, Netmail, Echomail or News.
+Msg Kinds   Private/Public, Private, Public, Read Only, FTN moderated, Usenet Moderated
+FTN chars   FTN characterset, not in use yet, defaults to IBMPC 2
+RFC chars   RFC characterset, not in use yet, defaults tp LATIN-1 2
+Days Old    The maximum age of the messages before purging.
+Max. Msgs   The maximum messages in this area.
+Netreply    Netmail reply area if this is echomail.
+Active      If this area is active.
+User Del.   Users may delete their own messages.
+Read Sec.   The security level to read messages.
+Write Sec.  The security level to write messages.
+Sysop Sec.  The security level to do sysop actions.
+Aliases     Allow the use of an Alias.
+Random org  Create random origin lines (Oneliner database).
+Quotes      Add a random quote under new messages (Oneliner database).
+Mandatory   If this area is mandatory for downlinks.
+UnSecure    Don't check link address during toss (Dangerous!).
+OLR Default Switch area default on for OLR users.
+OLR Forced  Area is always on for OLR users.
+Connections This will take you to the screen to edit up and downlinks.
+
+

+ + +

 

+ +

Edit connection

+

+

+Aka         The network address.
+Send to     Export mail to this node.
+Recv from   Import mail form this node.
+Pause       The node is temporary disconnected.
+Excluded    The node is disconnected by the sysop.
+Delete      Delete this connection.
+
+

+A note about the excluded switch. This can be used to disconnect a node +from the area by moderator request. AreaMgr requests from that node +for this area are not processed anymore, he cannot disconnect this area +and reconnect. If you want to prevent a node to connect the area while +he is not connected, you should manually connect the node and then set +the Excluded flag to yes. However, the status of this flag is reported to the +node in the notify messages, so this action is not invisible. +

 

+ + +

Global Commands.

+

+From menu 9.2 you can enter the global commands menu. In this menu you can: +

    +
  1. Delete connection +
  2. Add new connection +
  3. Replace connection +
  4. Change connection status +
  5. Change days old +
  6. Change max. messages +
  7. Change security +
  8. Change aka to use +
  9. Change origin line +
  10. Change netmail reply +
  11. Delete message area +
+After you have selected the action you want and added the items to do, you will see +a screen were you can select message area groups. You can then tag one or more +groups and press enter when you are done. Then you have one chance to perform the +actions or to bail out. All areas matching in that group are affected by your +changes. If you are not happy with the result, don't save the database and no +harm is done. The file mbsetup.log shows all affected areas. +

 

+ + +

Automatic area creation.

+

+If you want to use the automatic area creation you have to define a fictitious +area tagged 'DEFAULT' with the options you want for new areas like this: +

+ 1.  Area Name Area autocreada:
+ 2.  FTN area  DEFAULT
+ 3.  Newsgroup
+ 4.  Moderator
+ 5.  JAM base  /var/spool/mbse/mail/
+ 6.  Origin    Parolas BBX. Por fin.
+ 7.  Fido Aka  0:0/0@                                      22. Sysop Sec.   100
+ 8.  QWK name                      15. Days Old    40      23. Aliases      No
+ 9.  Group     AUTOCREADAS         16. Max. Msgs   1000    24. Quotes       No
+ 10. Distrib.                      17. Netreply    0       25. Mandatory    No
+ 11. Area Type Echomail            18. Active      Yes     26. UnSecure     No
+ 12. Msg Kinds Public              19. User Del.   Yes     27. OLR Default  No
+ 13. FTN chars IBMPC 2             20. Read Sec.   5       28. OLR Forced   No
+ 14. RFC chars LATIN-1 2           21. Write Sec.  5       29. Connections
+
+The FTN area's Tag must be 'DEFAULT' exactly. Connections will be left blank. Fill +the remaining options with your defaults for the new areas. +If Fido AKA has not been filled in, the best fitting AKA according to the origin of +the message will be used from the configuration.
+

+Areas will be created as is laid out in this template, the tag of a new area +will be added to the name and base path, the new tag will be placed in the tag +and qwk name (truncating it if needed). +Only the node from which the new area is received will be added in connections. +

+You will need to change the setup, menu 18, item 2, to change the command +'mbfido tic toss'. Add the -a parameter if you want the automatic +creation of areas to work when importing received mail. +So the commandline would be like /opt/mbse/bin/mbfido tic toss web -a -quiet. +

+ +Back Back to Mail Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/emgroup.html b/html/setup/emgroup.html new file mode 100644 index 00000000..52dc66b7 --- /dev/null +++ b/html/setup/emgroup.html @@ -0,0 +1,50 @@ + + + + + + + + +MBSE BBS Setup - Mail Setup - Message Groups. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - Mail Setup - Message Groups.

+

+ +

Introduction.

+

+Message Groups are to logically divide your echomail areas in groups for +different mail networks. It makes sense to select the groups by uplink, and +areas file that is available for each network. By doing that downlinks can +automatic connect areas that are not available at your bbs but are available +from your uplink. NOTE: uplink requesting is not yet implemented! +

 

+ +

Message Group Setup.

+

+

+Name     The name of the group.
+Comment  The description of the group.
+Active   If this group is active.
+Use Aka  The Fidonet aka to use.
+Uplink   The Fidonet aka of your uplink.
+Areas    The name of the areas file (~/etc/file.ext).
+Deleted  If this group must be deleted.
+
+

+ +

+ +Back Back to Mail Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/fdb.html b/html/setup/fdb.html new file mode 100644 index 00000000..b705bb24 --- /dev/null +++ b/html/setup/fdb.html @@ -0,0 +1,58 @@ + + + + + + + + +MBSE BBS Setup - Files Database. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Files Database.

+

+ +

Introduction.

+

+This option allows you to manually edit the files in the files database. +The option to edit the file description is not present at this moment, but +will be when I have the time. The basic file entries can't be changed. +

 

+ +

Edit File.

+

+

+FileName  The 8.3 filename of the file.
+Long fn   The long filename of the file, not in use yet.
+FileSize  The size of the file in bytes.
+FileDate  The real date of the file.
+Last DL.  The date of the last download of the file.
+Upl.Date  The upload date.
+Uploader  The name of the uploader.
+Times DL  The number of times downloaded from the BBS.
+Times FTP Not in use yet.
+Times Req The number of times requested by mailer.
+Password  The password to access this file.
+Cost      Not in use yet.
+Free      If this file is free for download.
+Deleted   If this file should be deleted.
+Missing   If this file is missing on disk.
+No Kill   Don't delete this file with mbfile
+Announced If this file is ever announced as new.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/fegroup.html b/html/setup/fegroup.html new file mode 100644 index 00000000..3800b70d --- /dev/null +++ b/html/setup/fegroup.html @@ -0,0 +1,64 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup - File Groups. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup - File Groups.

+

+ +

Introduction.

+

+File echo groups are to logically divide your file echo's for different +file distribution networks. It makes sense to select the groups by uplink and +area file that is available for that file distribution network. By doing that +downlinks can connect areas that are not yet connected at your bbs but are +available from your uplink. NOTE: uplink requests is not yet implemented. +

 

+ +

Cost Sharing.

+

+With the setup of groups you can also specify the Cost Sharing for the +files distribution. The unit cost is the cost for each transmitted file +if the unit size field is zero, or the unit price per transmitted unit size. +The final cost is multiplied with the "Add Prom." factor to add taxes or so. +Also if your uplink sends advanced .tic files, the cost found in that .tic +file will be added to the cost as well. Further you can set the final price +to divide between your downlinks or let them all pay the full price. + +

File Group Setup.

+

+

+Name      File Echo Group name.
+Comment   The description of that group.
+Active    If this group is active.
+Use Aka   The Fidonet aka to use for this group
+Uplink    The Fidonet aka of the uplink.
+Areas     The name of the areas file (in ~/etc).
+Unit Cost The cost per unit.
+Unit Size The size in Kbytes per unit.
+Add Prom. The prommilage to add to the cost.
+Divide    Divide cost over downlinks.
+Deleted   If this group must be deleted.
+
+

+ +

+ +Back Back to File Echo's Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/fidonet.html b/html/setup/fidonet.html new file mode 100644 index 00000000..8de0cd55 --- /dev/null +++ b/html/setup/fidonet.html @@ -0,0 +1,42 @@ + + + + + + + + +MBSE BBS Setup - Fidonet Networks. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - fidonet Networks

+

+Each fidonet network can have maximum 6 zones. The main zone (where you are) +must be the first zone, the others will follow. You can add 6 additional +nodelists to merge with the main nodelist. These additional nodelists are +normally more recent that the main nodelist, so entries in the additional +nodelists will replace entries from the main nodelist when you compile the +nodelists. In the shown example you can see that I have a regional nodelist +and a pointlist added for my region. For each additional list you must +specify the RC address because that information is normally present in these +nodelists. Watch out! Nodelist names are case sensitive. If you receive a +nodelist and automatic put them in place with the mbfido +program, and the resulting file is uppercase, you must use uppercase names +here also. You don't need to give the extension of the nodelist name, the +mbindex will figure that out. +

+ + +


+Back Back to index +
+Home Back to main index +
+ + + diff --git a/html/setup/fileecho.html b/html/setup/fileecho.html new file mode 100644 index 00000000..d74a678e --- /dev/null +++ b/html/setup/fileecho.html @@ -0,0 +1,94 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup - TIC Areas. + + + +
+
Last update 08-Jun-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup - TIC Areas.

+

+ +

Introduction.

+

+In this setup you can define the File Echo's or TIC areas. Files received or +send from this areas are bound together with a *.tic file with information +about the file and where to store that file. Each file echo must belong to a +group, in this grouprecord is the information about costsharing and some +other details. When a file is received at your system you can do several +things with that file before it is stored in your download areas such as; +scanning the file for virusses, extracting the FILE_ID.DIZ file to use as +description, allow update of magic alias, convert to another compression +format, replace the file archive comment with an add of your own bbs and limit +the number of files (nodelists). +

 

+ +

TIC Area Setup.

+

+

+Comment    A description for this area.
+Area tag   The tag for this area.
+BBS area   The BBS download area number, 0 means passthru.
+Message    Not in use yet.
+Group      The group where this area belongs to.
+Keep #     The number of files to keep, the name must match.
+Fido aka   The Fidonet aka to use for this area.
+Convert    The archiver to convert to, leave blank for none.
+Banner     The bannerfile (in ~/etc) to replace in the archive.
+Replace    Honor the "Replace" command in the .tic file.
+Dupecheck  Check for duplicates in this area.
+Secure     Check if the sending system is connected.
+No touch   Don't touch the filedate, keep it original.
+Virus sc.  Try to scan for virusses.
+Announce   Files may be announced in this area.
+Upd magic  Allow update magic request name.
+File_id    Try to use the FILE_ID.DIZ file for description.
+Conv.all   Convert archive even if it is already right.
+Send org.  Send original received file instead of the file from the BBS.
+Mandatory  Downlinks can't disconnect from this area.
+Notified   Not in use yet.
+Upl discon Not in use yet.
+Deleted    If this area must be deleted.
+Active     If this area is active.
+Systems    To the screen with connected systems.
+
+

+ +

+ + +

Global Commands.

+

+From menu 10.2 you can enter the global commands menu. In this menu you can: +

    +
  1. Delete connection +
  2. Add new connection +
  3. Replace connection +
  4. Change connection status +
  5. Change aka to use +
  6. Delete TIC area +
+After you have selected the action you want and added the items to do, you will see +a screen were you can select TIC file area groups. You can then tag one or more +groups and press enter when you are done. Then you have one chance to perform the +actions or to bail out. All areas matching in that group are affected by your +changes. If you are not happy with the result, don't save the database and no +harm is done. The file mbsetup.log shows all affected areas. +

 

+ + +Back Back to File Echo's Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/filefind.html b/html/setup/filefind.html new file mode 100644 index 00000000..fc67e2a6 --- /dev/null +++ b/html/setup/filefind.html @@ -0,0 +1,58 @@ + + + + + + + + +MBSE BBS Setup - Filefind Areas. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Filefind Areas.

+

+ +

Introduction.

+

+The filefind idea on Fidonet came from the program Allfix written by Harald +Harms. The idea is +that a user writes a mail in a filefind area addressed to "Allfix" with in the +subject line the items to search for. On all BBS'es with a filefind utility +those programs try to find the requested files and then produce a reply of +which files they have found. That reply can be in the same area, in a special +reply echo or can be sent by netmail. Usually the user gets a lot of replies +from which he can see if someone has the file(s) available he was searching +for. +

 

+ +

Filefind Setup.

+

+

+Comment     The comment for this area.
+Origin      The origin line to use for the reply.
+Aka to use  The Fidonet aka to use in this area.
+Scan area   The JAM area in which to scan for requests.
+Reply area  The JAM area to put the replies in, leave blank if in the same area.
+Language    Not in use yet, but DO select one!
+Template    Not in use yet.
+Active      If this area is active.
+Deleted     If this area must be deleted.
+Net. reply  If the reply will be sent by netmail.
+Hi ACSII    If high ASCII is allowed in the replies.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/files.html b/html/setup/files.html new file mode 100644 index 00000000..e30518b9 --- /dev/null +++ b/html/setup/files.html @@ -0,0 +1,79 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - File Areas. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - File Areas.

+

+ +

File Areas introduction.

+

+This is the setup for the file areas in which users can up and download files. +This database has fixed area numbers, the database can't be packed. This is +done because areas can point to other areas and users are "used" to use +areas by number. Also the .tic areas reference the file areas by record +numbers. Extending the database is allways possible. One important note, +before you can set this up, you need to define the +newfiles groups. +

 

+ +

File Areas Setup.

+

+

+Area Name  The area name.
+Path       The full path to the file area.
+Down Sec.  The download security level.
+Upl. Sec.  The upload security level.
+List Sec.  The security level to list the files in this area.
+Files.bbs  The full path and filename if this area is on CDROM.
+           You may leave this blank if it is in the Path together
+           with the files.
+Available  If this area is available.
+Check New  Check this area for new files if a user logs in.
+Dupecheck  Check this area for duplicates if a user uploads a file.
+Free area  If all files in this area are free.
+Direct DL  Allow direct download from this area.
+Pwd upl.   Allow users to password protect their uploads.
+Filefind   Search in this area for filefind requests.
+Add alpha  Add .tic files alphabetic sorted or at the bottom of the list.
+CDrom      Is this a CDROM area. The affects the behaviour of some
+           other utilities because the Path is read-only.
+File req.  Allow File Request from this area.
+BBS group  Not in use yet.
+New group  New files announce group. See Newfiles groups for more info.
+Min. age   Minimum user age to access this area.
+Password   The password for this area. If blank, no password is needed.
+DL days    How long must a file not been downloaded to (re)move it.
+FD days    How old must a file be to be (re)moved.
+Move area  The area to move the file to, if zero it is deleted.
+Cost       The cost in units to download from this area.
+Archiver   The archiver to use to repack the files with.
+Upload     Alternate upload area. If a user uploads a file in this
+           area, it will be placed in the alternate area. If the
+           value is zero, the file will be placed in the current
+           file area. On CD-rom areas you must not leave this zero
+           unless you set the upload security level so high that
+           nobody can upload in this area.
+
+

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/global.html b/html/setup/global.html new file mode 100644 index 00000000..165635da --- /dev/null +++ b/html/setup/global.html @@ -0,0 +1,464 @@ + + + + + + + + +MBSE BBS Setup - Global Setup. + + + +
+
Last update 22-Jun-2001
+

 

+ +

MBSE BBS Setup - Global Setup

+

+ +In this setup you can edit all global settings for MBSE BBS. All sections will +be discussed below. +

+ +

1.1. Edit Registration Info.

+

+

+System name       The name of your BBS
+Domain name       Your internet domain name (or a fake name if you have 
+                  no direct connection).
+Sysop uid         The Unix name of your Sysop account
+Sysop Fido        The Fidonet name of your Sysop account
+Location          The Location of your BBS
+QWK/Bluewave      The packet name for Offline mail downloads.
+Omed id.          Not in use
+Comment           A comment line for your BBS
+Origin line       The default origin line for echomail
+Startup uid       The default username "bbs"
+
+

+ +

1.2. Edit Global Filenames.

+

+

+System logfile    The name of the main logfile
+Error logfile     The name of the errors logfile
+Default menu      The name of the default main menu
+Default language  The name of the default language
+Chat logfile      The name of the logfile for chatting
+Welcome logo      The name of the BBS logo ANSI file
+
+

+ +

1.3. Edit Global Paths

+

+

+BBS Menus         The path to the default menus
+Txtfiles          The path to the default ANSI and ASCII textfiles
+Home dirs         The path to the users home directories
+Nodelists         The path to the nodelist directory
+Inbound           The unprotected fidonet inbound
+Prot inb.         The (password) protected fidonet inbound
+Outbound          The outbound for the main aka
+Bad TIC's         Where bad TIC files are saved
+TIC queue         Where TIC files for downlinks are kept
+Magic's           Where the magic filerequests are kept
+DOS path          The DOS drive and path
+Unix path         The Translated DOS path in real
+LeaveCase         Leave outbound .flo filenames as is, No forces to uppercase
+
+The DOS path and Unix path are translated for in and outbound mail sessions, +so the outside world will be happy. The DOS path is a fake, you can put +anything you like in there, but "C:\OUT" is a good choice. Note that +the TIC queue must be somewere in the Unix path, otherwise it is +impossible to create a DOS path from the path to the TIC files in that +directory. To set this up correctly is also important if you use other mailers +as well, for example binkd, or even a DOS binkly-style mailer running from +a network. All those mailer must "see" the same file attaches in the .flo +files. If you leave the DOS path empty, no translation will be performed +and the Unix paths will be stored in the .flo files. +

+ +

1.4. Edit BBS Configuration

+

+

+Private system    Set to true when only pre-registered users are allowed
+Exclude Sysop     True is Sysop will be invisible
+Show connect      Show connection info at logon
+Ask protocols     Ask protocol before each up/download
+Sysop level       The Sysop security level
+Password Length   The minimum password length, should be 6.
+Password Char.    The password hiding character
+Idle timeout      The idle timeout in minutes
+Login Enters      Maximum times for only enter 
+Login Attempts    Maximum login attempts
+Homedir Quota     Maximum size in MBytes for each user
+Location length   The minimum length of the location (3 in Holland!)
+Show new msgarea  Show new available message areas at logon (for OLR users)
+OLR Max. msgs.    Maximum messages to download, 0 is no limit.
+OLR Newfile days  The maximum age for newfiles in the OLR packet
+OLR Max Filereq   Maximum filerequests allowed for OLR users
+BBS Log Level     What will be logged or not the BBS program
+Utils Log Level   What will be logged or not for utilities
+Utils slowly      Should utilities release timeslices
+CrashMail level   Minimum level to allow sending netmail crash
+FileAttach level  Minimum level to allow attach files to netmail
+Min diskspace MB  At which low diskspace level utilities should stop working.
+
+The minimum diskspace setting is to prevent that files get corrupted if your filesystem +is full. All drives are checked except CD-roms and floppies and the /boot directory if that +one is on a separate filesystem. Ext2, msdos and vfat partitions +are checked. The lowest free diskspace found counts. Default is 10 MB. +Note, Reiserfs is not supported at this moment because I don't have access to a +system with reisefs volumes. This means that if you use Reiserfs that you are not +protected against a full filesystem. +

+ +

1.5. New users defaults.

+

+

+Access level      The access level and flags after registration
+Cap. Username     Capitalize the username
+Ask ANSI          Ask for ANSI screen (default is yes)
+Ask Sex           Ask for Male/Female
+Ask Voicephone    Ask for voice phonenumber
+Ask Dataphone     Ask for data phonenumber
+Telephone scan    Scan for duplicate numbers
+Ask Handle        Ask for handle (nickname)
+Ask Birth date    Ask for birthdate (needed for checks)
+Ask Location      Ask for users location
+Ask Hot-Keys      Ask for hot-keyed menus (default is yes)
+One word names    Allow one word names
+Ask address       Not implemented
+Give email        Give new users email access (default is yes)
+
+

+ +

1.6. Text Colors.

+

+Several prompts use different colors. They can be changed with the following +menu. +

+ + +

+ +

1.7. Next User Door.

+

+This is a "message to nextuser" door I found in RapidBBS. It allows a user +to write a message to the next BBS user. +

+Text file         The textfile to display
+Quote             The prompt to show
+
+

+ +

1.8. Safe cracker door.

+

+This is a door I found in RapidBBS, it is a simple number guessing game. +

+Digit 1           The first digit to guess
+Digit 2           The second digit to guess
+Digit 3           The third digit to guess
+Max trys          The maximum number of trys per day
+Max numb          The highest number to guess
+Num gen           Automatic number generation
+Prize             The prize to win
+Welcome           The welcome file to display
+Opened            The file to display to the winner
+
+

+ +

1.9. Time Bank Door.

+

+This is the timebank door I found in RapidBBS. It allows a user to deposit +time or download kilobytes on his bank account so when he needs it for +big downloads he can use his savings for extra large downloads. Anyway, +I haven't figured this one out completly for myself, so the meaning of all +these settings are not well explained right now. +

+Time balance      Maximum time balance
+Max time withdraw Maximum time to withdraw
+Max time deposit  Maximum time to deposit
+Kb. balance       Maximum Kilobytes balance
+Max Kb. withdraw  Maximum Kilobytes to withdraw
+Max Kb. deposit   Maximum Kilobytes to deposit
+Users time ratio  Time ratio
+Users Kb. ratio   Kilobytes ratio
+
+

+ +

1.10. Sysop paging

+

+For sysop chat we use a program that will connect to the users tty. This is +not a nice solution because it will not work over a network, but at least +it works. +

+Ext. chat         External chat program, not in use!
+Chat device       The device where the sysop is called (beeped)
+Call script       For future use
+Page length       The length of a page in seconds
+Page times        Maximum number of times a user may page the sysop
+Sysop area        Message from user to Sysop area number
+Ask reason        Ask reason for chat, this will be logged
+Use Extern        Use external chat 
+Log Chat          Log the chat conversation
+Prompt Chk.       Check at menu prompts for Sysop breaking in
+Freeze Time       Freeze users time during chat
+Sunday..Saturday  The times the Sysop is normal available
+

+ +

1.11. Flag Descriptions.

+

+In this menu you can give the 32 users flags a meaningfull description. +

+ +

1.12. Fileecho Processing.

+

+A note, when you change the number of Systems or Groups, the databases affected +will be updated automatic. +

+Keep days         How long TIC files should be kept on hold
+Hatch pwd         The internal hatch password. Make this weird.
+Drv space         The minimal free space on your disk in kilobytes
+Systems           The maximum number of connected nodes
+Groups            The maximum number of fileecho groups
+Max. dupes        The maximum number of entries in dupe database
+Keep date         Keep original filedate
+Keep netm         Keep sent netmails
+Res future        Reset dates in the future
+Loc resp          Respond to local created filefind messages
+Repl ext          Replace filename extension with .* before filesearch
+Plus all          Allow filemgr +all command
+Notify            Allow filemgr notify=on/off command
+Passwd            Allow filemgr passwd command
+Message           Allow filemgr message=on/off command
+Tic on/off        Allow filemgr tic=on/off command
+Pause             Allow filemgr pause/resume commands
+

+ +

1.13. Edit Fidonet mail and echomail processing.

+

+Note that the first 2 mailboards must also exist in the normal mail areas if +you want to see what is in them. Here they are defined for quick access of the +tosser. For the Max. systems and groups see 1.12. If you use MBSE BBS together +with a DOS based BBS (using DOSEMU or mars netware emulator), you can set the +behaviour of the outbound to 4d. addressing instead of 5d. This option may +dissapear in the future.
+Another option is present, this is the pktdate option. This +is the full path and filename to an external program that can inspect and +correct the mail .pkt files. Originally I put this in to run pktname of Tobias +Ernst of 2:2476/418 to fix y2k problems in the incoming mail. At this time +most y2k fixes are build in, but in case you need it it's there. To make it +clear; the y2ktools written by Tobias are static compiled for Linux and they +should run on all Linux i386 versions. Until now, I still use pktdate because +it is necessary.
+ +

+Badboard          The path and filename of the bad messages
+Dupeboard         The path and filename of the duplicate messages
+Pktdate           Full path and filename of a .pkt preprocessor
+Max pkts.         Maximum Kb. of mail packets before a new one is created.
+Max arcs.         Maximum size in Kilobytes of an arcmail file
+Keep days         How many day should we keep ARCmail on hold
+Echo dupes        Maximum number of entries in the echomail dupe database
+Reject old        Reject echomail messages older then n days
+Max msgs          Default maximum number of messages in each area
+Days old          Default number of days old to keep messages
+Max systems       Maximum number of nodes to connect to echomail
+Max groups        Maximum number of echomail groups
+4d address        Use 4d. addressing (not needed you only use MBSE BBS)
+Split at          Gently split messages after n KBytes (12..60)
+Force at          Force split of messages after n KBytes (16..63)
+

+A note about the splitting of messages. Some tossers can't handle +messages greater than 16 KBytes, these tossers are rare these days. Most +tossers can handle messages of 32 KBytes. To set these values on the safe +side set "Split at" to 27 and "Force at" to 31. This means that a long +newfile report will be split after 27 KBytes when a new group of files +should start in the report. If it can't find that point because a large +number of files is in the group that is just being processed, the message +split will be forced right after the file that passes the 31 KBytes limit. +I use values of 1 KBytes below maximum for overhead such as SEEN-BY and +PATH lines. Values larger then 32 KBytes is not a good idea, recent tests +in May 1999 have shown that your messages will not reach all systems +if they are larger then 32 KBytes. Splitting is used for newsfiles reports +and gated news articles to Fidonet. +

+ +

1.14. Edit Internet mail and news processing.

+

+Email and news is setup here. There are three possible configurations which you +can set with 1.14.11: +

    +
  • No ISP. If you don't have any connection to the internet + use this setting. Email will come from the default Fidonet UUCP gate and will be send out + via the UUCP gate. Users have email addresses like + user@f2802.m280.z2.fidonet.org Note, the username is their + Unix name when sending email. +
  • Dial ISP. If you dial the internet regulary or are connected + with a cable modem without a valid DNS (Nameserver) entry you should use + this mode. Email will be sent via your local SMTP port, then through your + own sendmail (or whatever you use) to your ISP. + As soon as you are connected to the internet + the mail will be sent to your ISP's mailer. In your sendmail you should + define the mailer of your ISP as Smarthost. Incoming email will still come + from the UUCP gate. Users have email addresses like + user@f2802.m280.z2.fidonet.org Note, the username is their + Unix name. +
  • Perm ISP. If you are permanent connected to the internet + either with a static or dynamic IP address use this option. Use this option + also if you have an UUCP domain and hav a dialup UUCP connection. You need to + register a DNS name and MX record for your system, if you don't you won't be able to + receive email from the internet and must use the previous Dial mode. + If you have a dynamic IP address you can still get a DNS name from for + example dynip.com + Incoming email will come directly from the internet, but if someone sends + email via the UUCP gate it is also accepted. Users have email addresses like + user@yourbbs.domain.org. Note, the username is their + Unix name. +
+Another word of wisdom from my side, configuration of the internet, ppp, sendmail etc. is not discussed +here, see the HOWTO's and other documentation that exists at +www.linuxdoc.org, it's all there. + +
+POP3 node         The POP3 node to use, should be localhost
+SMTP node         The SMTP node to use, should be localhost
+NNTP node         The NNTP node to use, should be localhost
+NNTP m.r.         If the NNTP server needs the Mode Reader command
+NNTP user         The username for the NNTP server if needed
+NNTP pass         The password for the NNTP server if needed
+News dupes        The number of entries for the news dupes database.
+Email aka         The Fidonet aka to use for the fidonet.org UUCP gate
+UUCP aka          The default Fidonet UUCP gate, 2:292/875@fidonet
+Emailmode         The email mode, discussed above
+News mode         Newsfeed mode, INN, rnews or UUCP.
+Split at          Gently split newfiles reports after n KBytes (12..60)
+Force at          Force split of newfiles reports after n KBytes (16..63)
+Control ok        Allow news control messages to be gated
+No regate         Don't regate already gated messages
+
+In rnews mode the NNTP entries are replaced by:
+
+Path rnews        The full path and filename to the rnews binary.
+
+In UUCP mode the NNTP entries are replaced by:
+
+UUCP path         The full path to the uucppublic directory.
+UUCP node         The UUCP nodename of your ISP.
+

+ + +

+

1.15. Allfiles and Newfiles lists.

+

+These are the settings that affect the generation of newfiles and allfiles reports. +

+Ftp base          The root of the public download area (.../ftp)
+New days          The number of days old files are "newfiles"
+Security          The highest security level to include files in the reports
+Groups            The number of newfile groups the newfiles database can hold
+

+ +

1.16. Fidonet Aka's.

+

+Here you can enter 40 fidonet addresses. These are 5d addresses. +

+ +

1.17. Mailer Setup.

+

+Note that you can't disable FTS-0001 sessions as that is a mandatory session +protocol in Fidonet. There are 40 phonenumber translations present, this is for +countries with lots of telephone operators with all kind of prefixes for +carrier select functions. +

+Mailer logl.      The logging level for mailer sessions
+Default phone     The default phonenumber for EMSI sessions
+TCP/IP flags      The TCP/IP capability flags for TCP/IP sessions
+Default speed     The default speed for EMSI sessions
+Timeout reset     The timout for normal modem commands
+Timeout connect   The timeout for waiting for connect
+Dial delay        The maximum delay between calls, minimum is 10 seconds.
+No Filerquests    Disable filerequests
+No callout        Disable callout
+No hold mail      Send "hold" mail if we make the call
+No pickup all     Exchange mail for one aka only
+No EMSI session   Disable EMSI
+No YooHoo/2U2     Disable FTS-0006 sessions
+No Zmodem         Disable zmodem protocol
+No Zedzap         Disable zedzap protocol
+No Hydra          Disable Hydra protocol
+No TCP/IP         Disable TCP/IP protocol, set to Yes if you don't have internet.
+Phonetrans 1..40  Maximum 40 phone number translations
+Max. files        Maximum files to request, 0 is unlimited 
+Max. MBytes       Maximum MBytes to request, 0 is unlimited
+
+ +

1.18. FTPD Settings.

+

+A new program is mbftpd. This is a replacement for the normal +ftp server for Linux with special futures for MBSE BBS. This is not working +yet so don't use it. Setting it up is adviced. +

+Base path         The ftp base directory (ie. /SYS/usr/ftp).
+Upload pth        Incoming files (ie. /SYS/usr/ftp/incoming).
+Banner msg        The banner file to display before login.
+Path filter       The legal character in upload filenames.
+Path msg          Message to display if illegal characters in upload.
+Email addr        Your email address.
+Shutdown          Shutdown message if FTP server is closed.
+Readme login      Readme to display after login.
+Readme cwd*       Readme to display after chdir.
+Msg login         Welcome message after login.
+Msg cwd*          Message to display in directory.
+Userslimit        Maximum FTP users allowed.
+Loginfails        Maximum login failures.
+Compress          If compress command is allowed.
+Tar               If tar command is allowed.
+Mkdir ok          If users may create directories.
+Log commands      Log user commands.
+Anonymous         If anonymous login is allowed.
+User mbse         If user mbse is allowed. Dangerous!
+
+ +

1.19. Edit HTML pages setup.

+

+Here you setup the HTML pages that can be created with the +mbfile web command. These are HTML pages of your download +areas and indexes of all areas. If there are pictures in these areas +thumbnails are created if you have the convert +command available. The document root is the same as defined in your +web server. The link to ftp must be created from that directory to +your ftp base directory. To do that become root, cd to the document root +and type ln -s /var/spool/mbse/ftp files In this case the link +is called files. Note that all download areas are accesible, +there is no user authentication yet available. +

+Docs root         The path to the httpd documents root.
+Link to ftp       The link to the ftp directory.
+URL name          The URL of your webserver.
+Charset           The default character set, ISO-8859-1.
+Table color       The tables background color.
+Header color      The tables header background color.
+Author name       The author name you want in the HTTP headers.
+Convert command   The graphics convert command. (ImageMagick needed).
+Files/page        The number of files to display per web page.
+Icon Home         The name of the Home icon file.
+Text Home         The text to display for Home.
+Icon Back         The name of the Back icon file.
+Text Back         The text to display for Back.
+Icon Prev.        The name of the Previous page icon file.
+Text Prev.        The text to display for Previous page.
+Icon Next         The name of the Next page icon file.
+Text Next         The text to display for Next page.
+
+

+ +Back Back to index +
+Home Back to main index +

+ + + diff --git a/html/setup/hatch.html b/html/setup/hatch.html new file mode 100644 index 00000000..13a17023 --- /dev/null +++ b/html/setup/hatch.html @@ -0,0 +1,61 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup - Hatch Manager. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup - Hatch Manager.

+

+ +

Introduction.

+

+Hatch files is nothing more than entering a new file into a file echo. That +file is searched for on your system in a specific directory with a certain +filemask. This can be for example a new created nodelist or an allfiles listing. +Everytime mbfido tic is run it will scan for files defined +in this setup. If such a file is found, a special .tic file is written and +stored in the mailers inbound directory. When the mbfido +starts processing .tic files, that new hatched file will be processed as if +it was received form another system. To let this work, you obviously need +an existing TIC area. +

 

+ +

Hatch Manager Setup.

+

+

+Mask    The path and filename mask to search for. 
+        "?" matches any character, "#" matches digits and "@" matches
+        alpha characters. Don't use "*", this doesn't work!
+Area    The area to hatch this file in.
+Replace The filename to replace, ie. "nodelist.z*"
+Magic   The filerequest magic name, ie. "nodelist"
+Desc    The description of the file, %12 in the description
+        means copy the 12th character of the name in place.
+Dupe    Check for duplicates.
+Active  If this area is active.
+Deleted If this area must be deleted.
+Days    The days in the week to scan for this file.
+Month   The dates in the month to scan for this file.
+
+

+ + +

+ +Back Back to File Echo's Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/index.htm b/html/setup/index.htm new file mode 100644 index 00000000..0ae82b24 --- /dev/null +++ b/html/setup/index.htm @@ -0,0 +1,80 @@ + + + + + + + + +MBSE BBS setup. + + + +
+
Last update 27-May-2001
+

 

+ +

MBSE BBS Setup Guide

+

+ +

Invoking mbsetup

+

+As user mbse type mbsetup to start the setup +program. This version is not yet finished. There are a few items you can't +setup yet. +When you start mbsetup you will see the following screen: +

+ +

 

+ +

mbsetup main options

+

+

    +
  1. Edit Global configuration +
  2. Edit Fido networks +
  3. Edit Archiver programs +
  4. Edit Virus scanners +
  5. Edit Modem types +
  6. Edit TTY lines info +
  7. Edit Fidonet nodes +
  8. Edit BBS setup +
      +
    1. Edit Security limits +
    2. Edit Language setup +
    3. Edit BBS menus +
    4. Edit File areas +
    5. Edit Transfer protocols +
    6. Edit BBS List data +
    7. Edit Oneliners +
    8. Edit TimeBank data +
    9. Edit Safe Cracker data +
    +
  9. Edit Mail setup +
      +
    1. Echo mail groups +
    2. Echo mail areas +
    +
  10. Edit File echo's setup +
      +
    1. Edit Fileecho groups +
    2. Edit Fileecho areas +
    3. Edit Hatch manager +
    4. Edit Magic files +
    +
  11. Edit Newfiles groups +
  12. Edit Newfiles reports +
  13. Edit Filefind setup +
  14. Edit Files database +
  15. Edit BBS users +
  16. Edit Services +
  17. Edit Domains +
  18. Edit Task Manager +
  19. Show software information +
  20. Create site documents +
+ +BackBack to index +
+ + + diff --git a/html/setup/language.html b/html/setup/language.html new file mode 100644 index 00000000..1b006ef6 --- /dev/null +++ b/html/setup/language.html @@ -0,0 +1,57 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Language Setup. + + + +
+
Last update 25-Jul-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Language Setup.

+

+ +

Language introduction.

+

+You need to define at least one language, this is the default language. +The paths to the BBS menus and Txtfiles for the default language +must be exactly the same as defined in the global setup, menus 1.3.1 and 1.3.2
+I did this so you can make your +own local languages next to the default languages. If something is not +present in your local language, the BBS will fall back to the default +language. This is true for the menus and textfiles for the BBS. It is +therefore wise to name all menus and textfiles the same for all languages used. +When you setup the languages for the first time, entries for English, Dutch, +Spanish and Italian are created. +

 

+ +

Language setup.

+

+

+Select      The letter to select this language.
+Name        The name of this language.
+Menupath    The path to the menu files.
+Textpath    The path to the ANSI and ASCII textfiles.
+Macropath   Not in use yet.
+Available   If this language is available.
+Datafile    The name of the language datafile in ~/etc
+Security    The minimum security level to select this language.
+Deleted     If this language must be deleted.
+
+

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/magic.html b/html/setup/magic.html new file mode 100644 index 00000000..f9987581 --- /dev/null +++ b/html/setup/magic.html @@ -0,0 +1,74 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup - Magic Files Setup. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup - Magics Files Setup.

+

+ +

Introduction.

+

+Magics are special actions that you can perform if files received in a .tic +area. The actions are: copy file to a directory, unpack file in a directory, +set number of files to keep, move file to another .tic area, update magic +request alias, adopt file into another area, store in another path, +delete file (don't process it further) and execute a command. The edit screen +is different for all kinds of actions you select. More than one magic record +may exist for each area. With all these actions you can for example can setup +processing of nodediff's and unpacking nodelists in the nodelist directory. +

 

+ +

Magics Setup.

+

+

+Magic     The action to perform, select with the spacebar.
+Filemask  The filemask to scan for. "?" Matches all characters,
+          "#" matches any digit and "@" any alpha character.
+Active    If this magic is active.
+Deleted   If this magic must be deleted.
+Area      The area in which this magic is found.
+To path   The destination path. (Copy, Other path and Unpack).
+To area   The destination area. (Adopt and Move).
+Command   The command to execute. (Execute).
+Keep #    The number of files to keep. (Keep).
+Compile   Trigger "compile nodelists". (Copy, Unpack and Execute).
+
+

 

+ +

Macro's

+

+In the commandline for the magic execute command you may use macro's to replace +parts of the commandline. The following macro's are defined: +

+%F   Replaced by the full path and filename of the file.
+%P   Replaced by the full path to the file.
+%N   Replaced by the filename without dot and extension.
+%E   Replaced by the extension of the filename.
+%L   The last 2 characters of the filename extension.
+%D   The day number of the year, 3 digits.
+%C   The last 2 digits of the day number of the year.
+%A   The .tic area name.
+
+ +

+ +

+ +Back Back to File Echo's Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/mail.html b/html/setup/mail.html new file mode 100644 index 00000000..f7f9048a --- /dev/null +++ b/html/setup/mail.html @@ -0,0 +1,35 @@ + + + + + + + + +MBSE BBS Setup - Mail Setup. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - Mail Setup.

+

+ +

Edit Mail Setup.

+

+The Mail Setup is split in the following sections: +

+ +

    +
  1. Echo mail groups +
  2. Echo mail areas +
+ +Back Back to index  +Home Back to main index +
+ + + diff --git a/html/setup/modems.html b/html/setup/modems.html new file mode 100644 index 00000000..5d5e9081 --- /dev/null +++ b/html/setup/modems.html @@ -0,0 +1,88 @@ + + + + + + + + +MBSE BBS Setup - Modem types. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - Modem types

+

+In the setup screen you can define all kinds of modems you use. This includes +ISDN modems. +This is not the setup of individual lines, that is in the next section, so +if you own a bbs with 5 analogue lines with only two brands and types of +modems connected, you need only to define those two types of modems here. Some +defaults are installed during initial bbs setup. +

 

+ +

Setup a modem.

+

+

+Type             The description of this modem.
+Init 1           The first modem init string.
+Init 2           The second init string (if needed).
+Init 3           The third init string (if needed).
+Reset            Not in use
+Hangup           Only needed if drop DTR doesn't work.
+Dial             The dial command.
+Info             Command to get caller-id (not tested).
+Ok               The modem "OK" response.
+Offset           The answer/connect time offset.
+Speed            The maximum modem linespeed, ie 28800.
+Available        If this modem is available.
+Deleted          If this modem must be deleted.
+Stripdash        Strip dashes from the dial command.
+Connect strings  Here you can define 20 connect strings.
+Error strings    Here you can define 10 non-connect strings.
+
+

 

+ +

Special characters

+

+

+\\               Send one backslash.
+\r               Send the CR character.
+\n               Send the LF character.
+\t               Send the TAB character.
+\b               Send the BS character.
+\s               Send a space character.
+\d               Wait one second.
+\p               Wait 0,25 second.
+\D               Send untranslated phone number.
+\T               Send translated phone number.
+
+

 

+ +

The Hangup field

+

+This is only needed if your modem doesn't hangup by dropping the DTR line for +one second. Most modems do that if &D2 or &D3 is in the init string. +

 

+ +

The Offset field.

+

+The Offset field is to calculate the cost for outgoing calls. +Analogue modems need time to establish the connection, 6 seconds is quite +common. So when you see the CONNECT BLABLA message, the phone connection +is there already 6 seconds and you are already paying for 6 seconds. This +offset is thus added to the total calculated connect time for cost +calculations. For ISDN modems this can be 1 or 0. +

 

+ +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/newfiles.html b/html/setup/newfiles.html new file mode 100644 index 00000000..6823b5d6 --- /dev/null +++ b/html/setup/newfiles.html @@ -0,0 +1,54 @@ + + + + + + + + +MBSE BBS Setup - Newfiles Reports. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Newfiles Reports.

+

+ +

Introduction.

+

+For each network you can define one or more newfiles reports to announce the +newfiles that arrived on your BBS. The files to include in the reports are +specified by the newfiles groups you can include or exclude for announcement. +

 

+ +

Reports Setup.

+

+

+Comment     The comment for this report.
+Msg area    The JAM message base to write the report in.
+Origin line The origin line to use.
+From name   The name to use in the "From:" field.
+To name     The name to use in the "To  :" field.
+Subject     The text to use in the "Subj:" field.
+Language    Not in use yet, but DO select! 
+Template    Not in use yet.
+Aka to use  The Fidonet aka to use in this area.
+Active      If this report is active.
+Deleted     If this report must be deleted.
+High ASCII  Allow high ASCII in this area.
+New groups  The screen to define the groups to include.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/newgroups.html b/html/setup/newgroups.html new file mode 100644 index 00000000..894dd9a0 --- /dev/null +++ b/html/setup/newgroups.html @@ -0,0 +1,49 @@ + + + + + + + + +MBSE BBS Setup - Newfiles Groups. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Newfiles Groups.

+

+ +

Introduction

+

+The newfiles group are there to create separate newfiles announcements for +several networks and areas. Even if you don't want to make different +announcements you still need to define at least 2 groups. One is a group +where you don't announce files in and one where you do. These groups are +linked to the BBS file areas and must be defined before you define the BBS +file areas. As you can see in the example picture I seperated the groups +in subjects. +

 

+ +

Newfiles Groups Setup.

+

+

+Name    The tag name of the group.
+Comment The comment for this group.
+Active  If this group is active.
+Deleted If this group must be deleted.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/nodes.html b/html/setup/nodes.html new file mode 100644 index 00000000..cf8084c7 --- /dev/null +++ b/html/setup/nodes.html @@ -0,0 +1,146 @@ + + + + + + + + +MBSE BBS Setup - Fidonet nodes. + + + +
+
Last update 22-Jun-2001
+

 

+ +

MBSE BBS Setup - Fidonet nodes.

+

+ +

Introduction

+

+Unlike many other bbs packages, for each node you need only one record. If you +have a relation with a node for one network with costsharing, and other +networks without costsharing you need two records for that node. For each node +you can setup the aka's, mail, files and session handshake. +

 

+ +

Main setup

+

+

+Sysop name       The name of the system operator.
+Fido aka's       Maximum 20 Fido addresses.
+Dial command     You can put an override here for the normal 
+                 dial command. If you leave this empty the 
+                 command from the modem setup is used.
+Phone number 1   An alternative phone number/ip address to dial.
+Phone number 2   An alternative phone number/ip address to dial.
+                 Use these above commands if the node has
+                 another phone number as mentioned in the
+                 nodelist. If you call this node via TCP/IP
+                 and the IP address can't be resolved by
+                 the nodelist, you may enter an IP address
+                 or hostname here.
+Route via        A route via Fido address. All mail for this
+                 node will be send via this Aka, even mail 
+                 and files for other networks. This can be
+                 usefull if this node has internet access
+                 so you can send everything to this node
+                 over the internet.
+Netmail direct   Set "direct" flag in netmail to this node.
+Netmail crash    Send netmail always "crash" to this node.
+Netmail hold     Put mail on "hold" for this node.
+Send notify      Send automatic generated notify messages.
+Language         The language to use (not yet working).
+Deleted          If this node must be deleted.
+No EMSI          Disable EMSI handshake.
+No YooHoo/2U2    Disable FTSC-0006 handshake.
+No Filerequest   Disable filerquest from this node.
+Don't call       Do not call this node.
+No Hold mail     Only pickup mail if we call, send nothing.
+Pickup primary   Only exchange mail for one Aka.
+No Zmodem        Disable Zmodem protocol.
+No Zedzap        Disable Zedzap protocol.
+No Hydra         Disable Hydra protocol.
+No TCP/IP        Disbale TCP/IP protocol, forces dial only.
+
+

+ +

 

+ +

Mail setup

+

+

+Session pwd      The mailer session password.
+Check PKT pwd    Check password in received .pkt files. If not,
+                 errors or missing passwords are only logged.
+                 If set, errors or missing password are refused
+                 and the .pkt files are renamed to .bad
+UplMgr program   The name of the Areamgr program of this node.
+                 (This doesn't work yet).
+UplMgr passwd    The password for the Areamgr of this node.
+Mail forward     Not in use yet.
+ARCmail comp.    Use ARCmail 0.60 file naming convention for out of zone mail.
+ARCmail a..z     Allow a..z last character for ARCmail filenames.
+
+

+ +

 

+ +

Mail groups

+

+Here you can tag which mail groups are available for this node. Note that all +groups are visible here, even for networks this node has no aka's in. Be +carefull not to allow a node to connect areas from networks he has no aka in. +

+ +

 

+ +

File setup

+

+

+Files password   The password for .tic files.
+Mgr password     The password for the Areamgr and Filemgr.
+UplMgr program   The name of the Filemgr progrom of this node.
+UplMgr passwd    The password of the Filemgr if this node.
+UplMgr Add +     Add a "+" in the command to connect areas.
+Incl. message    Send a netmail message for each file to send.
+Send TIC file    Send .tic file to this node.
+Advanced TIC     Send advanced or standard .tic files.
+File forward     Forward TIC files for this node (not yet).
+Billing          Is Costsharing active for this node.
+Bill direct      Send the bill direct or on command.
+Credit           The credit this node has in units.
+Debet            The debet we have with this node (informational).
+Add              Add (or substract) factor to the bill.
+Warn level       The debet level when to write a warning mesage.
+Stop level       The debet level when to stop sending files.
+
+

+ +

 

+ +

File groups

+

+The same story as for mail groups is true for the file groups. +

+ +

 

+ +

Statistics

+

+In this statistics screen you can see the mail and files flow with this +node. Values are stored for the current week, the previous week, the +current month and previous month and the overall total since you defined +this node. There are actual 12 months of statistics stored in the nodes +record, only 2 are visible. +

+ +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/oneliner.html b/html/setup/oneliner.html new file mode 100644 index 00000000..3973e6ef --- /dev/null +++ b/html/setup/oneliner.html @@ -0,0 +1,37 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Oneliners. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Oneliners.

+

+ +

Oneliners.

+

+Oneliners are small quotes that can be random selected and displayed to +your users. From the same database oneliners can be selected and inserted +at the bottom of messages. With the oneliners setup you can edit, add, +delete and import oneliners. Import is done from plain ASCII textfiles, +one quote on each line. The lines should be maximum 70 characters long. +

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/protocol.html b/html/setup/protocol.html new file mode 100644 index 00000000..1ffb48e8 --- /dev/null +++ b/html/setup/protocol.html @@ -0,0 +1,55 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Transfer Protocols. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Transfer Protocols.

+

+ +

Introduction.

+

+It might look strange that you have to define transfer protocols for the bbs +while for the mailer you don't need to do that. This is historic, ifcico +already had internal protocols and the precessor of the bbs package had external +protocols. Because my priority was make the bbs working it still is that way. +When time comes I will build some of the protocols internal, adding external +protocols will allways be possible. +

 

+ +

Transfer Protocols Setup.

+

+

+Select Key  The key the user has to press to select this protocol.
+Name        The name of this protocol.
+Upload      The full path and filename and parameters to upload files.
+Download    The full path and filename and parameters to download files.
+Available   If this protocol is available.
+Batching    If this is a batching protocol.
+Bi direct   If this is a bi-directional protocol (Not supported yet).
+Advice      A small advice to the user shown before the transfer starts.
+Efficiency  The efficiency in percent. Has no real meaning.
+Deleted     If this protocol must be deleted.
+Sec. level  The security level a user must have to select this protocol.
+
+

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/safe.html b/html/setup/safe.html new file mode 100755 index 00000000..95096a82 --- /dev/null +++ b/html/setup/safe.html @@ -0,0 +1,29 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Safe Cracker Data. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Safe Cracker Data

+

+This is meant to edit users personal safe cracker records and to reset +the winner. This is not available yet. +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/security.html b/html/setup/security.html new file mode 100644 index 00000000..b172514b --- /dev/null +++ b/html/setup/security.html @@ -0,0 +1,56 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Security Limits. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Security Limits.

+

+ +

Security limits, introduction.

+

+Every BBS needs several security limits to make a difference between several +user groups. These are the twits, regular users and (co-)sysops. If you have +a donation system you will probably have more different levels. Every level a +user can have must have a record in this file. To operate MBSE BBS you need at +least 3 levels, twit with level 0, new users with the level as setup in 1.5.1, +and the sysop level as setup in 1.4.5 As said, for special usergroups you can +add more levels as you need. If a user logs in and has a level in the userbase +you didn't define here, he won't be able to login. Even the twit level needs +some access to be able to throw him out in a nice but friendly way, give him +5 minutes, 1 file to download and no more then 1 Kb so he will understand he +is not wanted. Some defaults are installed during first bbs setup. +

 

+ +

Limits setup

+

+

+Access level    The access level value.
+Maximum time    The maximum time each day.
+Download Kb.    Maximum Kilobytes download each day.
+Download Files  Maximum files to download each day.
+Description     The description for this level.
+Available       If this level is available.
+Deleted         If this level must be deleted.
+
+

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/services.html b/html/setup/services.html new file mode 100644 index 00000000..0259cf35 --- /dev/null +++ b/html/setup/services.html @@ -0,0 +1,69 @@ + + + + + + + + +MBSE BBS Setup - Edit Services. + + + +
+
Last update 06-Jun-2001
+

 

+ +

MBSE BBS Setup - Edit Services.

+

+ +

Introduction.

+

+Services are special mail accounts. Netmail addressed to one of these names +will be handled according to the action that is selected. Current implemented +actions are AreaMgr, FileMgr and Email. So if you name a service +Areamgr and set the action to AreaMgr then an incoming +netmail will be directed to the Areamgr function. If you define a service +listserv and set the action to Email then +and incoming netmail will be converted to email and send to listserv +at your host.
+If you should want to run some votemanager on your system you can +do that by creating a service votemgr with the type set to email. +You also need to setup a valid unix user votemgr so that there will be an excisting +mailbox. Then with some external scripts you can process all received messages. +

 

+ +

Edit Services.

+

+

+Name      The name of the Service.
+Type      Toggle the service type with the spacebar.
+Active    If this service is active.
+Deleted   If this service must be deleted.
+
+

+Here are some example services: +

+

+UUCP		Email
+allfix          FileMgr
+areamgr         AreaMgr                                                  
+fmail           AreaMgr                                                  
+gecho           AreaMgr                                                  
+listserv        Email                                                    
+majordomo       Email                                                    
+mbsebbs         Email                                                    
+mbsebbs-owner   Email                                                    
+mbtic           FileMgr                                                  
+owner-mbsebbs   Email
+raid            FileMgr
+
+Note: the UUCP services is needed if you are gating email! +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/sitedoc.html b/html/setup/sitedoc.html new file mode 100644 index 00000000..95435f3f --- /dev/null +++ b/html/setup/sitedoc.html @@ -0,0 +1,37 @@ + + + + + + + + +MBSE BBS Setup - Create Sitedocs. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Create Sitedocs.

+

+ +

Create Sitedocs

+

+This option creates 3 documents in the doc directory under the home directory +of MBSE BBS, site.doc, xref.doc and stat.doc. Only the file site.doc is more +or less complete, the other 2 are heavily under construction. These three +files are a complete reference of your BBS setup. Especially the site.doc is +a large document, think at least four times before you send it to a printer. +The document xref.doc will contain lists with data from your setup that +depends on eachother. The file stat.doc will be a listing of all statistic +counters that are present in several data files. +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/softinfo.html b/html/setup/softinfo.html new file mode 100644 index 00000000..933e4137 --- /dev/null +++ b/html/setup/softinfo.html @@ -0,0 +1,31 @@ + + + + + + + + +MBSE BBS Setup - Show Software Information. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Show Software Information.

+

+ +

Introduction

+

+This screen shows the information about the MBSE BBS software, copyright and +release policy. +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/taskmgr.html b/html/setup/taskmgr.html new file mode 100644 index 00000000..2f3ec58e --- /dev/null +++ b/html/setup/taskmgr.html @@ -0,0 +1,67 @@ + + + + + + + + +MBSE BBS Setup - Task Manager. + + + +
+
Last update 07-Jul-2001
+

 

+ +

MBSE BBS Setup - Task Manager.

+

+ +

Introduction

+

+The task manager is the daemon which controls the MBSE BBS. It watches semafore's and spawns +programs in the background. The behaviour is setup in this screen. +

+ +

Edit Task Manager

+

+

+Mailout   Action for semafore mailout.
+Mailin    Action for semafore mailin.
+Newnews   Action for semafore newnews.
+Index 1   Nodelist compiler 1 for semafore mbindex.
+Index 2   Nodelist compiler 2 for semafore mbindex.
+Index 3   Nodelist compiler 3 for semafore mbindex.
+Msglink   Action for semafore msglink.
+Reqindex  Action for semafore reqindex.
+ISP conn  Not in use yet!
+ISP disc  Not in use yet!
+Ping #1   IP address of node to ping to check the internet.
+Ping #2   IP address of second node to ping to check the internet.
+ISP blks  Set to true if you have internet dialup and if it blocks normal dial.
+Max Load  Max system load until processing is suspended.
+ZMH start Start of Zone Mail Hour in UTC time.
+ZMH end   End of Zone Mail Hour in UTC time.
+Debug     Enable debug logging.
+Max POTS  Maximum simultaneous outgoing calls (for now ISDN + POTS + TCP/IP).
+Max ISDN  Not in use yet!
+Max TCP   Not in use yet!
+
+

+Default are the original MBSE commands filled in, but you could also call +shell scripts. As you can see, the task manager is not yet finished. +

+The two IP addresses to ping need to be IP addresses, not hostnames. This is the +most reliable way to check the connection. You should enter the IP addresses of +the nameservers of your own ISP here. One of these will always be up, so if one +of these can be reached, the internet connection is assumed to be alive. +

+ +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/tic.html b/html/setup/tic.html new file mode 100644 index 00000000..d23d0bb7 --- /dev/null +++ b/html/setup/tic.html @@ -0,0 +1,37 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup.

+

+ +

File Echo's Setup.

+

+The File Echo's Setup is split in the following sections: +

+ +

    +
  1. File echo groups +
  2. File echo areas +
  3. Hatch manager +
  4. Magic files +
+ +Back Back to index  +Home Back to main index +
+ + + diff --git a/html/setup/timebank.html b/html/setup/timebank.html new file mode 100755 index 00000000..1e29c545 --- /dev/null +++ b/html/setup/timebank.html @@ -0,0 +1,29 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - TimeBank. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - TimeBank.

+

+This is meant to edit the users personal timebank records. This is not +available yet. +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/ttyinfo.html b/html/setup/ttyinfo.html new file mode 100644 index 00000000..4bd62e2b --- /dev/null +++ b/html/setup/ttyinfo.html @@ -0,0 +1,73 @@ + + + + + + + + +MBSE BBS Setup - TTY Lines. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - TTY Lines.

+

+ +

Introduction.

+

+For each line your bbs has you must setup a tty line. This also includes +console lines (for local login), network lines for internet and lan connections +and X-terminal connections, ISDN lines, and Analogue modem lines. If a call +comes in over a tty you didn't define, that call is refused. So if you are +directly connected to the internet, and have only 5 network tty's defined, +then maximum 5 users are allowed to telnet to your bbs via the internet. +

+One thing about the portspeed, this is only needed for devices connected to +serial ports such as modems and external ISDN adapters. For network tty's and +internal ISDN cards this should be set to zero. If you set it to some other value, +things still word but you will get error messages in the logs. +

+A note about the EMSI flags, this must match your modem capabilities, if +not dialout will not work correct. It is used to see which line to use to call +a certain node. If you add the X75 flag on an analogue line, your system will try to +call ISDN nodes using an analogue modem. So these are not your nodelist flags as they +may represent combined ISDN and analogue flags but the flags that belong to a modem. +

 

+ +

Setup a line.

+

+

+Comment      A description for this line.
+TTY device   The tty device name without /dev/
+Phone nr.    The phone number on this line.
+Line Speed   The maximum line speed for this line.
+Fido Flags   The EMSI flags for this line, include your modem flags here!
+Line Type    Can be POTS, ISDN, Network and Local.
+Available    Is this line available for use.
+Auth. log    Not in use yet.
+Honor ZMH    Deny users during ZMH on this line.
+Deleted      If this line must be deleted.
+Callout      Allow calling other systems from this line.
+Portspeed    The "locked" modemspeed, 0 to 4000000 baud, only for serial ports.
+Modemtype    The modem connected to this line.
+EMSI name    The EMSI name presented for this (modem) line.
+
+

 

+ +

Some examples.

+

+

+

+

+

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/users.html b/html/setup/users.html new file mode 100644 index 00000000..82cd3a18 --- /dev/null +++ b/html/setup/users.html @@ -0,0 +1,80 @@ + + + + + + + + +MBSE BBS Setup - BBS Users. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Users.

+

+ +

Introduction.

+

+This screen lets you edit some settings of the BBS users. Note that the users +database will never be packed and users will always keep their record number. +If a user is deleted the record will be blanked. New users will get a blank +record if it exists, otherwise the database will be expanded. The reason for +this is the LastRead pointers of the message areas, BBS systems who do it +in another method mostly can't keep track of LastRead pointers and records, +and they mix all users LastRead pointers. Fields that +can be changed by the users themselves are marked with a *. +

 

+ +

Edit User

+

+

+Full Name    The full (Fidonet) name of the user.
+Handle     * The nickname of the user.
+Location   * The location of the user.
+Address n  * The address of the user (3 lines).
+Voicephone * The voice phonenumber of the user.
+dataphone  * The data phonenumber of the user.
+Security     The security level of the user.
+Birthdate  * The birthdate of the user DD-MM-YYYY.
+Expirydate   The expiry date of the user DD-MM-YYYY.
+Expiry Sec   The security level the user gets after expiry.
+Unix uid     The unix username of the user.
+Comment      The comment about this user.
+Password   * Change password for this user.
+Sex        * Users sex, male or female.
+Credit       The users credit.
+Protocol   * The selected file transfer protocol.
+Archiver   * The selected archiver.
+Hidden       If the user is hidden from listings etc.
+Hotkeys    * Hotkeys on/off.
+Color      * Color on/off.
+Deleted      User must be deleted.
+No Kill      User can never be deleted.
+Fs Chat    * Use fullscreen chat on/off.
+Locked       Locked out of the BBS.
+Silent     * Do not disturb on/off.
+CLS        * Sent clearscreen codes on/off.
+More       * More prompt on/off.
+Fs Edit    * Use fullscreen editor on/off.
+MailScan   * Scan for new mail at logon on/off.
+Guest        Is this a "guest" account on/off.
+ShowNews   * Show "news" screens on/off.
+NewFiles   * New files scan at logon on/off.
+Ext Info     Send ^aKLUDGES with BlueWave downloads.
+Email        If this user has an email address.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/virscan.html b/html/setup/virscan.html new file mode 100644 index 00000000..6a585198 --- /dev/null +++ b/html/setup/virscan.html @@ -0,0 +1,52 @@ + + + + + + + + +MBSE BBS Setup - Virus scanners. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - virus scanners

+

+Once upon a time there was no DOS and no computer virusses. But since DOS was +invented as a small OS which was easily extensible, virus writers saw their +chance to easy spread their hacks. Although running a Linux system is +relative safe, most of the files that you have available on your bbs +are DOS based programs. And before you put them available for download, they +should be checked for virusses. Macro virusses are a relative new danger, +this can also hurt Unix/Linux users.

+There are several scanners for Linux available. Default only two of them +are setup. You may consult +http://www.openantivirus.org for more scanner mentioned in a mini-FAQ +maintained by Rainer Link. +

+NAI Virus Scan (uvscan) for Unix (Linux) made by +Network Associates, USA. +Not free for personal use. Uses the same DAT files as for Windows and DOS. +

+AntiVir/Linux made by +H+BEDV Datentechnik GmbH. +Can also be installed in sendmail or Postfix to scan incoming +and outgoing email. This may be a good idea if you run a email gateway. +This version can be registered for personal use. +

+As soon as you have made a scanner available in the setup and you receive files +in tic areas where the scan flag is set, then these files will be checked. +As soon as one of the scanners detects a virus the received file will not be imported. +Uploads from users will be checked with the installed virus scanners as well. +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/ups.html b/html/ups.html new file mode 100644 index 00000000..e225b5c6 --- /dev/null +++ b/html/ups.html @@ -0,0 +1,45 @@ + + + + + + + + +Using UPS semafore's. + + + +
+
Last update 08-Jun-2001
+

 

+

MBSE BBS - Using UPS semafore's.

+

+ + +If you have a UPS and you are able to let your UPS software create semafore's when powerfail conditions +occur then read on. The MBSE BBS taskmanager and a lot of utilities will act on two special semafore's, +they are: + +

    +
  1. upsalarm, this semafore should be set when there is no mains power, but there is enough + power left to operate your system. All background tasks will be suspended as long as this condition + is true. If the power comes back, the UPS software should remove this semafore. +
  2. upsdown, this semafore should be set when the UPS sofware signals your system to go down. + This is a fatal condition and there is no way back. Even if the power comes back your system should + shutdown and the UPS will disconnect the power to your system. After a while it will turn the power on + again and your system boots. MBSE BBS will if this semafore is seen kick users out of the bbs, and the + system shutdown script will try to close MBSE BBS as quick as possible. Normal the close timeout is + one hour to let users normal finnish what they were doing, now it is only 30 seconds and if they were + not logged out, they will be disconnected anyway. +
+I know not all UPS software can do this but most UPS software is open source so you can change it to create +these semafore's. It is not a problem that UPS semafore's still excist if the systems boots, the MBSE BBS +startup scripts will remove them before the bbs is started. +

 

+ + +Back Go Back + + + diff --git a/install-sh b/install-sh new file mode 100755 index 00000000..e9de2384 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/lang/Language.xref b/lang/Language.xref new file mode 100644 index 00000000..f2dfa9d4 --- /dev/null +++ b/lang/Language.xref @@ -0,0 +1,472 @@ +0 user.c newuser.c |Please enter your First and Last name: +1 user.c |Please enter your Last name: +2 user.c |Disconnecting user ... +3 user.c |Scanning User File ... +4 user.c YN|Did you spell your name correctly? [Y/n] +5 user.c |Name Entered: +6 user.c |This is a PRIVATE System. Type "off" to leave +7 filesub.c |Mark file number or press to stop +8 user.c filesub.c |Password: +9 user.c |Maximum login attempts have been exceeded ... +10 user.c |Either your NAME or PASSWORD is incorrect +11 bank.c | MBSE BBS System Bank +12 bank.c |Bank Account: +13 bank.c |Time in account +14 bank.c |Bytes in account +15 bank.c |Time deposited today +16 bank.c |Bytes deposited today +17 bank.c |Time withdrawn today +18 bank.c |Bytes withdrawn today +19 bank.c DWQ|(D)eposit, (W)ithdraw, (Q)uit: +20 bank.c |Bank > +21 bank.c TBQ|(T)ime, (B)ytes, (Q)uit : +22 bank.c |You must have at least 5 minutes remaining to deposit +23 bank.c |How much time. Minutes available to you is +24 bank.c |You have tried to deposit more than the maximum limit today. +25 bank.c |Maximum allowed minutes to deposit per day: +26 bank.c |You have exeeded your account balance. +27 bank.c |Maximum allowable minutes in bank account is: +28 bank.c |You are allowed to deposit: +29 bank.c |You have tried to withdraw more than the maximum limit today. +30 bank.c |Maximum allowed to withdraw per day: +31 bank.c |You have tried to withdraw more time than is in your bank account. +32 bank.c |Current bank balance: +33 bank.c |Maximum allowed kilobytes to deposit per day: +34 bank.c |You have exeeded your account balance. +35 bank.c |Maximum allowable kilobytes in bank account is: +36 bank.c |How many kilobytes. KBytes available to you is +37 newuser.c |MBSE Bulletin Board System - NEW USER REGISTRATION +38 newuser.c |Use this name: +39 newuser.c |Please enter new password : +40 newuser.c user.c |Please enter password again : +41 newuser.c user.c |Your passwords do not match! Try again. +42 newuser.c change.c user.c |Your password must contain at least +43 newuser.c change.c user.c |characters! Try again. +44 newuser.c YN|Do you want ANSI and graphics mode [Y/n]: +45 newuser.c change.c |Please enter you Voice Number +46 mail.c |Message exported to your private directory as: +47 newuser.c change.c |Please enter a proper phone number +48 newuser.c change.c |Please enter you Data Number +49 newuser.c change.c |Please enter your location: +50 newuser.c |Please enter a longer location +51 newuser.c MF|What is your sex? (M)ale or (F)emale: +52 newuser.c |Male +53 newuser.c |Female +54 newuser.c |Please answer M or F +55 newuser.c |Unknown +56 newuser.c change.c |Please enter your Date of Birth DD-MM-YYYY: +57 newuser.c |Sorry you entered this year by mistake. +58 newuser.c |Please enter the correct date format +59 chat.c |*** Sysop is starting chat *** +60 chat.c |*** Sysop has terminated chat *** +61 mail.c misc.c YN=|More (Y/n/=) +62 newuser.c YN|Would you like Hot-Keyed menus? [Y/n]: +63 newuser.c |Please answer Y or N +64 change.c |Please enter your Screen Length? [24]: +65 newuser.c |None +66 offline.c |Tag Offline Reader message areas +67 newuser.c |Your user account has been created: +68 newuser.c |Login Name : +69 newuser.c |Password : +70 newuser.c |not displayed +71 newuser.c |New user registration completed. +72 misc.c |Could not find +73 change.c |Old Location: +74 change.c |Please enter a longer location (min +75 change.c |Ansi Mode turned ON +76 change.c |Ansi Mode turned OFF +77 mail.c |Message doesn't exist +78 change.c |News bulletins turned ON +79 change.c |News bulletins turned OFF +80 change.c |Screen length is 24 +81 change.c |Screen length is now set to: +82 mail.c |Private message, not owner +83 change.c |Please enter the correct date format +84 misc.c |Todays Callers to +85 misc.c |# User Name Device TimeOn Calls Location +86 safe.c |Safe Cracker Door +87 safe.c |Please press a key to continue: +88 safe.c |In the safe lies ... +89 safe.c |Please enter three numbers consisting from 1 to +90 safe.c |Please enter three combinations. +91 safe.c |1st digit: +92 safe.c |Please try again! You must input a number greater than Zero and less than +93 safe.c |2nd digit: +94 safe.c |3rd digit: +95 safe.c | Left: +96 safe.c |Right: +97 safe.c YN|Attempt to open safe with this combination [Y/n]: +98 safe.c |You have won the following... +99 safe.c |Sorry - You didn't open the safe! +100 safe.c |The safe code was: +101 safe.c YN|Do you want to try again ? [Y/n]: +102 safe.c YN|Do you want to open the safe ? [Y/n]: +103 safe.c |THE SAFE IS CURRENTLY LOCKED +104 safe.c |has cracked the safe. +105 safe.c |The safe will remain locked until the sysop rewards the user. +106 safe.c |Maximum trys per day Exceeded! +107 nextuser.c |Message to Nextuser Door +108 nextuser.c |The FROM, TO and SUBJECT fields are optional. +109 nextuser.c | From: +110 nextuser.c | To: +111 nextuser.c |Subject: +112 nextuser.c | Type up to 10 lines 74 Characters per line +113 nextuser.c |Functions available: +114 nextuser.c LREAS|(L)ist, (R)eplace text, (E)dit line, (A)bort, (S)ave +115 nextuser.c |Select: +116 nextuser.c file.c |Aborting... +117 nextuser.c |Returning to +118 nextuser.c |Edit which line: +119 nextuser.c |Line does not exist. +120 change.c |Old Password: +121 change.c |New password: +122 change.c |Confirm new password: +123 change.c |Passwords do not match! +124 change.c |Password Change Successful +125 change.c |Old password incorrect! +126 funcs.c |User List +127 funcs.c |Enter Username search string or (Enter) for all users: +128 funcs.c |Name Location Last On Calls +129 funcs.c |Could not find search string ... +130 timecheck.c |Time limit exceeded ... disconnecting! +131 filesub.c YN=M|More (Y/n/=) M=Mark +132 filesub.c |Scanning +133 filesub.c |with +134 funcs.c |TIME STATISTICS for +135 funcs.c mbsebbs.c |on +136 funcs.c |Current Time : +137 funcs.c |Current Date : +138 funcs.c |Connect time : +139 funcs.c |Time used today : +140 funcs.c |Time remaining today : +141 funcs.c |Daily time limit : +142 mail.c |You have +143 mail.c YN|messages, read your mail now? [Y/n]: +144 mail.c |You have no new mail in your mail box ... +145 change.c |Hotkeys are now ON +146 change.c |Hotkeys are now OFF +147 funcs.c |On +148 funcs.c |Off +149 newuser.c |User name already exists +150 mail.c |Checking your mail box ... +151 page.c | MBSE BBS Chat +152 page.c |The SysOp is currently speaking to somebody else on +153 page.c |Try paging him again in a few minutes ... +154 page.c ||You have paged the Sysop the maximum times allowed. +155 page.c |Sysop currently is not available ... please leave a comment +156 mail.c |Posting message in area: +157 mail.c |From : +158 mail.c |To : +159 mail.c |Verifying user ... +160 mail.c |User not found. Try again, or (Enter) to quit +161 mail.c |Subject : +162 mail.c YN|Abort Message [y/N] ?: +163 mail.c YN|Private [y/N]: +164 lineedit.c |Begin your message now, Blank line to end +165 lineedit.c |Maximum of 60 lines, 73 characters per line +166 lineedit.c |Maximum message length exceeded +167 lineedit.c |Functions available: (Current Message: +168 lineedit.c |Lines) +169 lineedit.c |L - List message S - Save message C - Continue message +170 lineedit.c |Q - Quit message D - Delete line I - Insert line +171 lineedit.c |T - Text edit E - Edit line R - Replace line +172 lineedit.c LSCQDITERZ|Z - Center line +173 lineedit.c |Select +174 lineedit.c |Continue +175 lineedit.c file.c |Delete +176 lineedit.c |Delete starting at line +177 lineedit.c |Aborted. +178 lineedit.c |Please enter a number in the range of +179 lineedit.c |Delete ending at line +180 lineedit.c |Edit +181 lineedit.c |Enter line # to edit +182 lineedit.c |Insert +183 lineedit.c |Enter line # to insert text before +184 lineedit.c |List +185 lineedit.c |Enter line # to replace +186 lineedit.c nextuser.c |Line reads: +187 lineedit.c |Unchanged. +188 lineedit.c |Line now reads: +189 lineedit.c mail.c |Quit +190 lineedit.c YN|Are you sure [y/N]: +191 lineedit.c |Message aborted. +192 lineedit.c |No +193 lineedit.c |Text Edit +194 lineedit.c |Enter line # to edit +195 lineedit.c nextuser.c |Text to replace : +196 lineedit.c nextuser.c |Replacement text : +197 lineedit.c |Line now reads: +198 lineedit.c |Save +199 filesub.c |Possible VIRUS found! +200 filesub.c offline.c |Ok +201 filesub.c offline.c |Unpacking archive +202 mail.c |Saving message to disk +203 lineedit.c |Enter line # to center +204 lineedit.c |Line is maximum length and cannot be centered +205 mail.c |There are no messages in this area. +206 mail.c |Date : +207 mail.c file.c YN=|More (Y/n/=/Area #): +208 mail.c |To : +209 mail.c |From : +210 mail.c |Subject : +211 mail.c |Next reply: +212 mail.c |Reply to: +213 mail.c |messages in +214 mail.c ANLREQDX|(A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (D)elete, (Q)uit, e(X)port +215 mail.c |(A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (Q)uit, e(X)port +216 mail.c |Next +217 filesub.c offline.c |ERROR +218 mail.c RNQ|(R)eply, (N)ext, (Q)uit: +219 mail.c |Enter to keep Subject. +220 mail.c |# From To Subject +221 mail.c |Message area +222 mail.c |contains +223 mail.c |messages. +224 mail.c |Please enter a message between +225 mail.c |Message number [ +226 mail.c |Area Type description Messages Personal +227 mail.c |thread +228 offline.c |Enter the name of the conference, or ? for a list: +229 offline.c |Conference Area Msgs Description +230 mail.c |Deleting message +231 mail.c | Message Areas +232 file.c mail.c |Select Area: +233 file.c mail.c |Invalid area specified - Please try again ... +234 file.c mail.c |Password is incorrect +235 file.c mail.c |Password is correct +236 file.c |You don't have enough security to list this area +237 filesub.c |Can't open file database for this area +238 filesub.c file.c |Uploaded by: +239 file.c |D E L E T E D +240 file.c |M I S S I N G +241 mail.c YN|Node not known, continue anayway [y/N]: +242 file.c |Total Files: +243 filesub.c |FATAL: Unable to open areas database +244 filesub.c |You do not have enough access to download from this area. +245 file.c mail.c |Please enter filename: +246 file.c |No filename entered, Aborting. +247 file.c offline.c |Illegal Filename! +248 file.c |Sorry that file is unavailable for download +249 file.c filesub.c |You have +250 file.c filesub.c |extra download KBytes. +251 filesub.c |You do not have enough time to download that file. +252 filesub.c |You do not have enough bytes to download " +253 filesub.c |You must upload before you can download. +254 filesub.c |Kilobytes currently available: +255 file.c |Checking your marked downloads, please wait... +256 offline.c |Untag Offline Reader message areas +257 filesub.c |Found FILEID.DIZ in +258 file.c |No files marked for download. +259 filesub.c |extra minutes. +260 offline.c |You have selected the following Conference(s): +261 file.c |Filename Size Date +262 change.c |Protocol: Can't open protocol file. +263 change.c |Select your preferred file transfer protcol +264 change.c |Select Protocol (Enter to Quit): +265 change.c |Ivalid selection, please try again! +266 change.c |Protocol now set to: +267 file.c |Enter keyword to use for Search: +268 file.c |File Search by Keyword +269 file.c |Accepts wildcards such as : *.zip, *.gz, .tar* +270 file.c | : *.zip is the same as .zip +271 file.c |Enter filename to search for : +272 file.c |File Search by Filename +273 file.c YN|Search for new since your last call [Y/n]: +274 file.c |Enter new date to search for [DD-MM-YYYY]: +275 file.c |File Search by Date +276 file.c offline.c |Please enter file to upload: +277 offline.c |Offline Reader Download +278 file.c |You do not have enough access to upload to this area. +279 file.c |You have not enough diskspace free to copy this file +280 file.c |files( +281 file.c |bytes) marked for download. +282 file.c |The file already exists on the system +283 file.c offline.c |Please start your upload now ... +284 filesub.c |Upload was unsuccessful for: +285 filesub.c YN|Do you want to password protect your upload ? [y/N]: +286 filesub.c |REMEMBER: Passwords are "CaSe SeNsITiVe!" +287 filesub.c |Please enter description of file +288 filesub.c |Your upload time has been returned to you. Thank you for your upload! +289 file.c |Start copy: +290 file.c |Can't open directory for listing: +291 file.c |Home directory listing for +292 file.c |Please enter filename to delete: +293 file.c |Sorry you may not delete hidden files ... +294 file.c |Unable to delete file ... +295 file.c |Invalid filename, please try again ... +296 file.c |File does not exist, please try again ... +297 offline.c |Forum Description Msgs. Pers. +298 file.c | File Areas +299 file.c |Please enter Area Password: +300 bbslist.c |Adding BBS +301 bbslist.c |BBS Name: +302 bbslist.c |Response needed ... +303 bbslist.c |Phone Number: +304 bbslist.c |Sysop Name: +305 bbslist.c |BBS Software: +306 bbslist.c |Storage (GigaByte): +307 bbslist.c |Speeds: +308 bbslist.c YN|Would you like to add a extended discription? [Y/n]: +309 bbslist.c |Please a enter discription for +310 bbslist.c |BBS Listing +311 bbslist.c |# BBS Name Number Software GigaByte Speed +312 bbslist.c |Search for a BBS +313 bbslist.c |Please enter 3 letters of BBS to search for: +314 bbslist.c |I need at least 3 letters ... +315 bbslist.c YN|View this BBS? [Y/n]: +316 bbslist.c |Could not find the BBS Listed ... +317 bbslist.c |Show a BBS +318 bbslist.c |Please enter number to list: +319 bbslist.c oneline.c |Record does not exist +320 bbslist.c | Record : +321 bbslist.c | BBS Name : +322 bbslist.c | Number : +323 bbslist.c | Software : +324 bbslist.c | GigaByte : +325 bbslist.c | Speeds : +326 bbslist.c | Sysop Name : +327 bbslist.c | Available : +328 bbslist.c | Date of Entry : +329 bbslist.c | Entry Name : +330 bbslist.c |Delete BBS +331 bbslist.c oneline.c |Please enter number to delete: +332 bbslist.c oneline.c |Record +333 bbslist.c oneline.c |does not belong to you. +334 bbslist.c oneline.c |already marked for deletion +335 bbslist.c |marked for deletion +336 bbslist.c |The Sysop will purge the list once he has +337 bbslist.c |seen you have marked a record for deletion. +338 offline.c |Total messages found: +339 menu.c |Unknown Menu Command! +340 nextuser.c |Saving... +341 oneline.c |MBSE BBS Oneliners will randomly appear on the main menu. +342 oneline.c |Obscene or libellous oneliners will be deleted!! +343 oneline.c |Please enter your oneliner below. You have 75 characters. +344 oneline.c |Oneliner added +345 oneline.c | # A Date User Description +346 oneline.c | # Description +347 oneline.c |Please enter number to list: +348 mbsebbs.c |Connected on port +349 file.c |File(s) : +350 file.c |Size : +351 file.c |Protocol : +352 file.c |Updating download counter, please wait ... +353 file.c |Failed! +354 file.c |Bytes +355 file.c | # Area Active File Size Cost +356 file.c lineedit.c |Yes +357 file.c |No +358 file.c TE|(T)oggle active, (E)rase all, (ENTER) to continue: +359 file.c |Enter file number, 1.. +360 filesub.c |Marked: +361 file.c |No files tagged. +362 lineedit.c |Replace +363 newuser.c |Loading BBS, please wait ... +364 offline.c |New or deleted mail areas at +365 offline.c |Area State Type Description +366 change.c |New Mail check is now ON +367 change.c |New Mail check is now OFF +368 file.c |Delete file: +369 file.c YN|Are you Sure? [Y/n]: +370 change.c |New Files check is now ON +371 change.c |New Files check is now OFF +372 change.c |Fullscreen Editor is now ON +373 change.c |Fullscreen Editor is now OFF +374 offline.c |No messages found to download! +375 funcs4.c |Press (Enter) to continue: +376 lineedit.c |Center +377 offline.c |Too much messages. Only the first +378 change.c |Select your preferred language +379 change.c |Select Language: +380 change.c |Language now set to: +381 funcs4.c |The system will now ask you for a "Unix Account" +382 funcs4.c |Your "Unix Account" is created, you may use it the next time you call. +383 funcs4.c |Please enter a login name (Maximum 8 characters) +384 funcs4.c |ie. John Doe, login = jdoe +385 funcs4.c |login > +386 funcs4.c |That login name already exists, please choose another one. +387 | +388 newuser.c |Your new Unix and BBS password will be the same. +389 user.c |FATAL ERROR: You are not in the BBS users file. +390 user.c | Please run 'newuser' to create an account +391 offline.c |New +392 offline.c |Local +393 offline.c |Netmail +394 offline.c |Echomail +395 offline.c |News +396 offline.c |E-Mail +397 offline.c |Del +398 funcs4.c |Jan +399 funcs4.c |Feb +400 funcs4.c |Mar +401 funcs4.c |Apr +402 funcs4.c |May +403 funcs4.c |Jun +404 funcs4.c |Jul +405 funcs4.c |Aug +406 funcs4.c |Sep +407 funcs4.c |Oct +408 funcs4.c |Nov +409 funcs4.c |Dec +410 newuser.c timeout.c |Autologout: idletime reached. +411 offline.c |will be packed! +412 newuser.c change.c |Enter your handle (Enter for none): +413 user.c |You are now ready to use the bbs +414 exitinfo.c |Callers On-Line to +415 exitinfo.c |Name Device Status Location +416 change.c |Do not disturb turned OFF +417 change.c |Do not disturb turned ON +418 exitinfo.c |Browsing +419 exitinfo.c |Downloading +420 exitinfo.c |Uploading +421 exitinfo.c |Msg Section +422 exitinfo.c |External Door +423 exitinfo.c |Chatting +424 exitinfo.c |Listing Files +425 offline.c YN|Do you want to download these messages [Y/n]? +426 exitinfo.c |Banking Door +427 exitinfo.c |Safe Door +428 exitinfo.c |WhosOn List +429 exitinfo.c |Idle +430 exitinfo.c |Please enter username to send message to: +431 exitinfo.c |Sorry, there is no user on +432 exitinfo.c |doesn't wish to be disturbed +433 exitinfo.c |Please enter in message to send (Max 76 Characters) +434 misc.c |** Message ** from +435 user.c |Your password is expired, new password : +436 funcs.c |Press ENTER to continue +437 mail.c |Posting not allowed, this area is Read Only! +438 |notdefined +439 offline.c |Offline Reader Upload +440 offline.c |Invalid packet received +441 offline.c |Unknown compression type +442 offline.c |Archiver not available +443 offline.c |Unknown type mailpacket +444 offline.c |BlueWave Offline download +445 offline.c |Preparing packet +446 offline.c |Packing with +447 offline.c |Download failed +448 offline.c |Download successfull +449 offline.c |Updating lastread pointers +450 offline.c |Processing BlueWave reply packet +451 offline.c |ERROR in packet +452 offline.c |Import messages +453 offline.c |No Write access to area +454 offline.c |Messages imported +455 offline.c |Processing Offline Configuration +456 offline.c |Message areas selected +457 offline.c |Processing file requests +458 offline.c |QWK Offline Download +459 offline.c |Processing QWK reply packet +460 offline.c |ASCII Offline Download +461 mail.c YN|Crash [y/N]: +462 mail.c YN|Warning: node is not CM, send immediate [y/N]: +463 mail.c YN|Attach file [y/N]: +464 mail.c |File +465 mail.c |will be attached +466 mail.c |File not within +467 email.c |mailbox - Incoming and outgoing email +468 email.c |archive - Archive of your email +469 email.c |trash - Trashcan, your old email +470 email.c |Area # +471 funcs.c |minutes. diff --git a/lang/Makefile.am b/lang/Makefile.am new file mode 100644 index 00000000..ca7040e0 --- /dev/null +++ b/lang/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in +## There are special tricks in this one .... + +SUBDIRS = . +LIBS = + +EXTRA_DIST = Language.xref + +CONFIG_CLEAN_FILES = english.lang dutch.lang italian.lang spanish.lang + +noinst_PROGRAMS = english.lang dutch.lang italian.lang spanish.lang + +english_lang_SOURCES = english.txt +dutch_lang_SOURCES = dutch.txt +italian_lang_SOURCES = italian.txt +spanish_lang_SOURCES = spanish.txt + + + +install-exec-local: + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 english.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 dutch.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 italian.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 spanish.lang $(sysconfdir) + +english.lang: english.txt + ../mbsebbs/mblang english.lang english.txt + +dutch.lang: dutch.txt + ../mbsebbs/mblang dutch.lang dutch.txt + +italian.lang: italian.txt + ../mbsebbs/mblang italian.lang italian.txt + +spanish.lang: spanish.txt + ../mbsebbs/mblang spanish.lang spanish.txt + diff --git a/lang/Makefile.in b/lang/Makefile.in new file mode 100644 index 00000000..d95fb97e --- /dev/null +++ b/lang/Makefile.in @@ -0,0 +1,372 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . +LIBS = + +EXTRA_DIST = Language.xref + +CONFIG_CLEAN_FILES = english.lang dutch.lang italian.lang spanish.lang + +noinst_PROGRAMS = english.lang dutch.lang italian.lang spanish.lang + +english_lang_SOURCES = english.txt +dutch_lang_SOURCES = dutch.txt +italian_lang_SOURCES = italian.txt +spanish_lang_SOURCES = spanish.txt +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +english_lang_OBJECTS = +english_lang_LDADD = $(LDADD) +english_lang_DEPENDENCIES = +english_lang_LDFLAGS = +dutch_lang_OBJECTS = +dutch_lang_LDADD = $(LDADD) +dutch_lang_DEPENDENCIES = +dutch_lang_LDFLAGS = +italian_lang_OBJECTS = +italian_lang_LDADD = $(LDADD) +italian_lang_DEPENDENCIES = +italian_lang_LDFLAGS = +spanish_lang_OBJECTS = +spanish_lang_LDADD = $(LDADD) +spanish_lang_DEPENDENCIES = +spanish_lang_LDFLAGS = +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(english_lang_SOURCES) $(dutch_lang_SOURCES) $(italian_lang_SOURCES) $(spanish_lang_SOURCES) +OBJECTS = $(english_lang_OBJECTS) $(dutch_lang_OBJECTS) $(italian_lang_OBJECTS) $(spanish_lang_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lang/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lang + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 english.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 dutch.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 italian.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 spanish.lang $(sysconfdir) + +english.lang: english.txt + ../mbsebbs/mblang english.lang english.txt + +dutch.lang: dutch.txt + ../mbsebbs/mblang dutch.lang dutch.txt + +italian.lang: italian.txt + ../mbsebbs/mblang italian.lang italian.txt + +spanish.lang: spanish.txt + ../mbsebbs/mblang spanish.lang spanish.txt + +# 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/lang/README b/lang/README new file mode 100644 index 00000000..57121f46 --- /dev/null +++ b/lang/README @@ -0,0 +1,28 @@ + LANGUAGE SOURCES FOR MBSE BBS. + ============================== + + +This directory contains the language sources for MBSE BBS. The file +Language.xref is only a reference file with linenumbers and source +references. The files english.txt, dutch.txt and italian.txt are the +real language sources. The resulting files dutch.lang, english.lang +and italian.lang are placed in the ~/etc directory where the bbs +will expect them to be. + +If you make your own language files, use Language.xref as a guide. +The syntax for each language line is: + +KEYS|Language line + +The keys are the keys that the users must press for the right response. +Order is important. The "|" character is a seperator, the rest of the +language line is the line shown to the user. Trailing spaces are important! + +If you do create language sources then I would like that you make them +public available and send them to me so I can include them in the +source distribution. + +The Italian language was translated by nervous@nervous.it + +Michiel. + diff --git a/lang/dutch.txt b/lang/dutch.txt new file mode 100644 index 00000000..acf3a3f0 --- /dev/null +++ b/lang/dutch.txt @@ -0,0 +1,472 @@ +|Geef Voor en Achternaam: +|Geef Achternaam: +|Verbreken gebruiker ... +|Doorzoeken gebruikers bestand ... +JN|Is Uw naam juist gespeld? [J/n] +|Opgegeven naam: +|Dit is een PRIVE Systeem. Tik "off" om eruit te gaan +|Markeer bestand nummer of toets voor stop +|Wachtwoord: +|Maximum aantal inlog pogingen overschreden ... +|Of Uw NAAM of Uw WACHTWOORD is fout +| MBSE BBS Systeem Bank +|Bank Rekening: +|Tijd op de rekening +|Bytes op de rekening +|Tijd gestort vandaag +|Bytes gestort vandaag +|Tijd opgenomen vandaag +|Bytes opgenomen vandaag +SOE|(S)torten, (O)pnemen, (E)inde: +|Bank > +TBE|(T)ijd, (B)ytes, (E)inde: +|U moet minstens 5 minuten tijd over hebben om te storten +|Hoeveel tijd. Aantal minuten beschikbaars is +|U heeft geprobeerd meer dan de dagelijkse limiet te storten. +|Maximaal aantal te storten minuten per dag: +|U heeft Uw rekening balans overschreden. +|Maximaal aantal minuten op de bankrekening is: +|U mag storten: +|U heeft geprobeerd meer dan de dagelijkse limiet op te nemen. +|Maximaal per dag op te nemen: +|U heeft geprobeert meer tijd op te nemen dan op de rekening staat. +|Huidige bank balans: +|Maximaal aantal kilobytes te storten per dag: +|U heeft Uw bank balans overschreden. +|Maximaal aantal kilobytes op de bankrekening is: +|Hoeveel kilobytes. Aantal Kilobytes beschikbaar is +|MBSE Bulletin Board Systeem - NIEUWE GEBRUIKER REGISTRATIE +|Gebruik deze naam: +|Geef een nieuw wachtwoord : +|Geef het wachtwoord opnieuw : +|De wachtwoorden zijn niet gelijk! Opnieuw. +|Uw wachtwoord moet minstens +|karakters bevatten! Opnieuw. +JN|Wilt U ANSI karakters en kleuren [J/n]: +|Geef Uw Spraak Telefoonnummer +|Bericht weggeschreven naar Uw prive directory als: +|Geef het nummer in een goed formaat +|Geef Uw Data Telefoonnummer +|Geef Uw woonplaats: +|Geef een langere woonplaats naam +MV|Wat is Uw geslacht? (M)an of (V)rouw: +|Man +|Vrouw +|Antwoord met M of V +|Onbekend +|Geef Uw geboorte datum DD-MM-YYYY: +|Sorry maar dat is dit jaar. +|Gebruik het juiste datum formaat +|*** De Sysop komt erin om te kletsen *** +|*** De Sysop stopt met kletsen *** +JN=|Meer (J/n/=) +JN|Wilt U sneltoets menus? [J/n]: +|Antwoord met J of N +|Wat is Uw scherm lengte? [24]: +|Geen +|Selecteer Offline Reader berichten gebieden +|Uw gebruikers account is gemaakt: +|Inlog naam : +|Wachtwoord : +|onzichtbaar +|Nieuwe gebruiker registratie is klaar. +|Niet gevonden +|Oude woonplaats: +|Geef een langere woonplaats naam (minimaal +|ANSI kleuren staan nu AAN +|ANSI kleuren staan nu UIT +|Bericht bestaat niet +|News berichten staan nu AAN +|News berichten staan nu UIT +|Scherm lengte is 24 +|De scherm lengte staat nu op: +|Prive bericht, niet van U +|Geef het juiste datum formaat +|Bellers vandaag bij +|# Gebruiker Poort Tijd Keren Woonplaats +|Kluis kraker programma +|Druk een toets om verder te gaan: +|In de kluis ligt ... +|Geef drie nummers tussen 1 en +|Geef drie kombinaties. +|Eerste cijfer: +|Probeer opnieuw! U moet een nummer geven groter dan 0 en kleiner dan +|Tweede cijfer: +|Derde cijfer : +| Links: +|Rechts: +JN|Proberen de kluis met deze kombinatie te openenen [J/n]: +|U hebt het volgende gewonnen ... +|Spijtig - U hebt de kluis niet geopend! +|De cijferkombinatie was: +JN|Wilt U het opnieuw proberen ? [J/n]: +JN|Wilt U de kluis openenen ? [J/n]: +|DE KLUIS ZIT NU OP SLOT +|heeft de kluis grkraakt. +|De kluis blijft op slot tot de sysop de gebruiker beloond heeft. +|Maximaal aantal pogingen perdag bereikt! +|Bericht naar volgende gebruiker +|De VAN, AAN en ONDERWERP velden zijn opties. +| Van: +| Aan: +|Onderwerp: +| Type maximaal 10 regels van 74 karakters per regel +|Beschikbare functies: +LVWAB|(L)ijst, (V)ervang tekst, (W)ijzig regel, (A)fbreken, (B)ewaar +|Kies: +|Afbreken ... +|Terug naar +|Wijzig welke regel: +|Regel bestaat niet. +|Oud wachtwoord: +|Nieuw wachtwoord: +|Bevestig nieuw wachtwoord: +|Wachtwoorden zijn niet gelijk! +|Het wachtwoord is gewijzigd +|Oude wachtwoord is fout! +|gebruikers lijst +|Geef gebruikersnaam zoekfragment of (Enter) voor alle gebruikers: +|Naam Woonplaats Laatst hier Hoevaak +|Zoekargument niet gevonden ... +|Tijd limiet overschreden ... verbreken! +JN=M|Meer (J/n/=) M=Markeer +|Scannen +|met +|TIJD STATISTIEK voor +|op +|Huidige tijd : +|Huidige datum : +|Verbindings tijd : +|Tijd gebruikt vandaag : +|Tijd over vandaag : +|Dagelijkse tijdslimiet : +|U heeft +JN|berichten, nu de post lezen? [J/n]: +|Er zijn geen nieuwe berichten in Uw postbus ... +|Sneltoetsen staan nu AAN +|Sneltoetsen staan nu UIT +|Aan +|Uit +|Gebruikersnaam bestaat al +|Even in Uw postbus kijken ... +| MBSE BBS Kletsen +|De Sysop is nu even met iemand anders in gesprek op +|Probeer het opnieuw in enkele minuten ... +|U heeft de Sysop meer dan het maximaal aantal keren geroepen. +|De Sysop is niet aanwezig ... laat een bericht achter +|Nieuw bericht in gebied: +|Van : +|Aan : +|Kontroleren gebruiker ... +|Gebruiker niet gevonden. Opnieuw proberen of (Enter) voor stop +|Onderwerp: +JN|Afbreken bericht [j/N] ?: +JN|Prive [j/N]: +|Begin nu met het bericht, Een lege regel is stoppen +|Maximaal 60 regels, 73 karakters per regel +|maximale berichtlengte overschreden +|Functies beschikbaar: (Huidig bericht: +|Regels) +|L - Lijst bericht B - Bewaar bericht D - Doorgaan bericht +|A - Afbreken W - Wissen regel I - Invoegen regel +|T - Tekst wijzigen R - Regel wijzigen V - Vervang regel +LBDADITRVC|C - Centreer regel +|Kies +|Doorgaan +|Wis +|Wis vanaf regel +|Afgebroken. +|Geef een nummer in het bereik van +|Wissen eindigt met regel +|Wijzig +|Geef regel # te wijzigen +|Invoegen +|Geef het regel # waarvoor in te voegen +|Lijst +|Geef regel # te vervangen +|De regel is: +|Onveranderd. +|De regel is nu: +|Stop +JN|Wet U het zeker [j/N]: +|Bericht afgebroken. +|Nee +|Tekst wijzigen +|Geef regel # te wijzigen +|Oude tekst : +|Nieuwe tekst: +|De regel is nu: +|Bewaar +|Een mogelijk VIRUS gevonden! +|Ok +|Uitpakken archief +|Opslaan bericht op disk +|Geef regel # te centreren +|De regel is op maximale breedte en kan niet worden gecentreerd. +|Er zijn geen breichten in dit gebied. +|Datum : +JN=|Meer (J/n/=/Gebied #): +|Aan : +|Van : +|Onderwerp: +|Reactie: +|Antwoord op: +|berichten in +OVLAPSWX|(O)pnieuw, (V)olgend, (L)aatst, (A)ntwoord, (P)laats, (W)is, (S)top, e(X)port +|(O)pnieuw, (V)olgend, (L)aatst, (A)ntwoord, (P)laats, (S)top, e(X)port +|Volgende +|FOUT +AVS|(A)ntwoord, (V)olgende, (S)top: +|Enter is zelfde onderwerp. +|# Van Aan Onderwerp +|Berichten gebied +|bevat +|berichten. +|Geef een bericht tussen +|Bericht nummer [ +|Nr. Soort Omschrijving Aantal Persoonlijk +|draad +|Geef de naam van de confrentie, of ? voor een lijst: +|Conferentie Gebied Tot. Omschrijving +|Wissen bericht +| Berichten gebieden +|Kies gebied: +|Ongeldig nummer opgegeven - Probeer het opnieuw ... +|Wachtwoord is fout +|Wachtwoord is goed +|U heeft niet genoeg autorisatie voor de lijst in dit gebied +|Kan de database niet openen voor dit gebied +|Upload door: +|GEWIST +|ONTBREEKT +JN|Node onbekend, toch doorgaan [j/N]: +|Aantal bestanden: +|FATAAL: kan de bestanden database niet openen +|U heeft niet genoeg autorisatie om uit dit gebied te downloaden. +|Geef de bestandsnaam: +|Geen bestandsnaam, Afgebroken. +|Ongeldige bestandsnaam! +|Sorry maar dat bestand is niet beschikbaar voor download +|U heeft +|extra download KBytes. +|U heeft niet genoeg tijd om dat bestand te downloaden. +|U heeft niet genoeg bijtes over om te downloaden " +|U moet uploaden vorrdat U kunt downloaden. +|Kilobytes op dit moment beschikbaar: +|Kontroleren gemarkeerde bestanden, een ogenblik ... +|Verwijder selectie Offline Reader berichten gebieden +|FILEID.DIZ gevonden in +|Geen bestanden gemarkeerd voor download. +|extra minuten. +|De volgende conferentie(s) zijn geselecteerd: +|Bestand Grootte Datum +|Protocol: Kan protocollen bestand niet openen. +|Kies Uw favourite overdracht protocol +|Kies Protocol (Enter is Stop): +|Ongeldige keuze, Probeer het opnieuw! +|Het protocol is nu: +|Geef sleutelwoord om op te zoeken : +|Bestanden zoeken op sleutelwoord +|Accepteerd jokers zoals : *.zip, *.gz, .tar* +| : *.zip is hetzelfde als .zip +|Geef bestandsnaam om naar te zoeken : +|Bestanden zoeken op naam +JN|Zoeken naar nieuwe bestanden sinds de laatste keer? [J/n]: +|Geef nieuwe datum om vanaf te zoeken [DD-MM-JJJJ]: +|Bestanden zoeken op datum +|Geef bestandsnaam voor upload: +|Offline Reader Download +|U heeft niet genoeg rechten om in dit gebied te uploaden. +|U heeft niet genoeg vrije diskruimte om dit bestand te kopieren +|bestanden( +|bytes) gemarkeerd voor download. +|Dat bestand bestaat al op het systeem +|Begin u met Uw upload ... +|Upload is mislukt voor : +JN|Wilt U Uw upload beschermen met een wachtwoord ? [j/N]: +|ONTHOUDT: Wachtwoorden zijn "HoOfDLEtTer GeVoElIg!" +|Geef een omschrijving van bestand +|Uw upload tijd is terruggegeven. Bedankt voor de upload! +|Start kopieren: +|Kan de directory niet openen voor de lijst: +|Prive directory lijst voor +|Geef bestandsnaam om te wissen: +|Spijtig, maar verborgen bestanden mag U niet wissen ... +|Kan bestand niet wissen ... +|Ongeldige bestandsnaam, Probeer het opnieuw ... +|Bestand bestaat niet, Probeer het opnieuw ... +|Conferentie Omschrijving Aant. Pers. +| Bestanden gebieden +|Geef gebieds wachtwoord: +|Toevoegen BBS +|BBS Naam: +|Invoer is nodig ... +|Telefoon nummer: +|Sysop Naam: +|BBS Software: +|Diskruimte (GigaByte): +|Snelheden: +JN|Wilt U het BBS uitgebreider omschrijven? [J/n]: +|Geef een omschrijving voor +|BBS Lijst +|# BBS Naam Nummer Software GigaByte Snelheid +|Zoek een BBS +|Geef 3 letters van het BBS om op te zoeken: +|Ik heb minstens 3 letters nodig ... +JN|Bekijk dit BBS? [J/n]: +|Ik kon dat BBS niet vinden ... +|Toon een BBS +|Geef het nummer om te bekijken: +|Record bestaat niet +| Record : +| BBS Naam : +| Nummer : +| Software : +| GigaBytes : +| Snelheden : +| Sysop Naam : +| Beschikbaar : +| Invoer datum : +| Invoer naam : +|Verwijder BBS +|Geef het nummer om te verwijderen: +|Record +|is niet van U. +|is al gemarkeerd om te verwijderen +|gemarkeerd om te verwijderen +|De Sysop zal dit BBS verwijderen zodra hij +|heeft gezien dat er een record gemarkeerd is. +|Totaal aantal berichten gevonden: +|Onbekend menu kommando! +|Bewaren ... +|MBSE BBS Spreuken kunne willekeurig verschijnen. +|Obscene en racistische opmerkingen worden verwijderd!! +|Geef hieronder Uw spreuk. U heeft 75 karakters. +|Spreuk toegevoegd +| # A Datum Gebruiker Omschrijving +| # Omschrijving +|Geef nummer om te bekijken: +|Verbonden via poort +|Bestand(en): +|Grootte : +|Protocol : +|Bijwerken download tellers, een ogenblik ... +|Mislukt! +|Bytes +| # Geb. Aktief Bestand Grootte Kosten +|Ja +|Nee +SV|(S)chakel aktief, (V)erwijder alles, (ENTER) voor doorgaan: +|Geef bestand nummer, 1.. +|Gemarkeerd: +|Geen bestanden gemarkeerd. +|Vervang +|Het BBS wordt geladen, een moment ... +|Nieuwe of verwijderde berichten gebieden bij +|Geb. Status Soort Omschrijving +|Tonen nieuwe Post is nu AAN +|Tonen nieuwe Post is nu UIT +|Verwijder bestand: +JN|Zeker weten? [J/n]: +|Tonen nieuwe Bestanden is nu AAN +|Tonen nieuwe Bestanden is nu UIT +|Schermgestuurde Tekstverwerker is nu AAN +|Schermgestuurde Tekstverwerker is nu UIT +|Geen berichten gevonden voor download! +|Geef (Enter) voor doorgaan: +|Centreer +|Teveel berichten. Alleen de eerste +|Kies Uw favourite taal +|Kies taal: +|De taal is nu: +|Het systeem zal nu een "Unix gebruikersnaam" vragen +|Uw "Unix gerbuikersnaam" is gemaakt, U kunt dit de volgende keer gebruiken. +|Geef een inlog naam (Maximaal 8 karakters, kleine letters) +|bv. Piet Snot, login = psnot +|login > +|Die login naam bestaat al, kies iets anders. +|FATAL: Cannot open language definition file +|Uw nieuwe Unix en BBS wachtwoord worden hetzelfde. +|FATAL ERROR: Niet gevonden in het BBS gebruikers bestand. +| Start 'newuser' om een account te maken +|Nieuw +|Lokaal +|Netmail +|Echomail +|Nieuws +|E-Mail +|Gewist +|Jan +|Feb +|Mrt +|Apr +|Mei +|Jun +|Jul +|Aug +|Sep +|Okt +|Nov +|Dec +|Autologuit: non-aktief tijd bereikt. +|worden ingepakt! +|Geef Uw Alias (Enter voor geen): +|Je kunt het bbs nu gaan gebruiken +|Gebruikers aanwezig bij +|Naam Poort Bezig met Woonplaats +|Niet storen staat nu UIT +|Niet storen staat nu AAN +|Rondkijken +|Downloaden +|Uploaden +|Berichten +|Extern Prog. +|Kletsen +|Bestanden +JN|Wilt U deze berichten downloaden [J/n]? +|Tijd Bank +|Kluis kraken +|Wie is hier +|Vrij +|Geef de gebruikersnaam waar het bericht heen moet: +|Sorry, er is niemand op +|wil niet gestoord worden +|Geef te versturen bericht (Maximaal 76 karakters) +|** Bericht ** van +|Uw wachtwoord is verlopen, geef nieuw wachtwoord: +|Toets ENTER voor doorgaan +|Plaatsen berichten niet toegestaan, dit gebied is alleen lezen! +|Antwoorden is niet toegestaan in dit gebied! +|Offline Reader Upload +|Ongeldig pakket ontvangen +|Onbekende compressie methode +|Compressie programma niet beschikbaar +|Onbekend type mail pakket +|BlueWave Offline download +|Voorbereiden pakket +|Comprimeren met +|Download mislukt +|Download is gelukt +|Bijwerken laatstgelezen wijzers +|Verwerken BlueWave antwoord pakket +|FOUT in pakket +|Inlezen berichten +|Geen schrijftoegang in gebied +|Berichten ingelezen +|Verwerken Offline Configuratie +|Berichten gebieden gelecteerd +|Verwerken bestands verzoeken +|QWK Offline Download +|Verwerken QWK antwoord pakket +|ASCII Offline Download +JN|Direct [j/N]: +JN|Let op: node is niet CM, onmiddelijk sturen [j/N]: +JN|Bestand meesturen [j/N]: +|Bestand +|wordt meegestuurd +|Bestand niet binnen +|mailbox - Inkomende en uitgaande post +|archive - Het archief van Uw email +|trash - De vuilnisbak, oude email. +|Gebied # +|minuten. diff --git a/lang/english.txt b/lang/english.txt new file mode 100644 index 00000000..6b757bb5 --- /dev/null +++ b/lang/english.txt @@ -0,0 +1,472 @@ +|Please enter your First and Last name: +|Please enter your Last name: +|Disconnecting user ... +|Scanning User File ... +YN|Did you spell your name correctly? [Y/n] +|Name Entered: +|This is a PRIVATE System. Type "off" to leave +|Mark file number or press to stop +|Password: +|Maximum login attempts have been exceeded ... +|Either your NAME or PASSWORD is incorrect +| MBSE BBS System Bank +|Bank Account: +|Time in account +|Bytes in account +|Time deposited today +|Bytes deposited today +|Time withdrawn today +|Bytes withdrawn today +DWQ|(D)eposit, (W)ithdraw, (Q)uit: +|Bank > +TBQ|(T)ime, (B)ytes, (Q)uit : +|You must have at least 5 minutes remaining to deposit +|How much time. Minutes available to you is +|You have tried to deposit more than the maximum limit today. +|Maximum allowed minutes to deposit per day: +|You have exeeded your account balance. +|Maximum allowable minutes in bank account is: +|You are allowed to deposit: +|You have tried to withdraw more than the maximum limit today. +|Maximum allowed to withdraw per day: +|You have tried to withdraw more time than is in your bank account. +|Current bank balance: +|Maximum allowed kilobytes to deposit per day: +|You have exeeded your account balance. +|Maximum allowable kilobytes in bank account is: +|How many kilobytes. KBytes available to you is +|MBSE Bulletin Board System - NEW USER REGISTRATION +|Use this name: +|Please enter new password : +|Please enter password again : +|Your passwords do not match! Try again. +|Your password must contain at least +|characters! Try again. +YN|Do you want ANSI and graphics mode [Y/n]: +|Please enter you Voice Number +|Message exported to your private directory as: +|Please enter a proper phone number +|Please enter you Data Number +|Please enter your location: +|Please enter a longer location +MF|What is your sex? (M)ale or (F)emale: +|Male +|Female +|Please answer M or F +|Unknown +|Please enter your Date of Birth DD-MM-YYYY: +|Sorry you entered this year by mistake. +|Please enter the correct date format +|*** Sysop is starting chat *** +|*** Sysop has terminated chat *** +YN=|More (Y/n/=) +YN|Would you like Hot-Keyed menus? [Y/n]: +|Please answer Y or N +|Please enter your Screen Length? [24]: +|None +|Tag Offline Reader message areas +|Your user account has been created: +|Login Name : +|Password : +|not displayed +|Login to the BBS with the above name +|Could not find +|Old Location: +|Please enter a longer location (min +|Ansi Mode turned ON +|Ansi Mode turned OFF +|Message doesn't exist +|News bulletins turned ON +|News bulletins turned OFF +|Screen length is 24 +|Screen length is now set to: +|Private message, not owner +|Please enter the correct date format +|Todays Callers to +|# User Name Device TimeOn Calls Location +|Safe Cracker Door +|Please press a key to continue: +|In the safe lies ... +|Please enter three numbers consisting from 1 to +|Please enter three combinations. +|1st digit: +|Please try again! You must input a number greater than Zero and less than +|2nd digit: +|3rd digit: +| Left: +|Right: +YN|Attempt to open safe with this combination [Y/n]: +|You have won the following... +|Sorry - You didn't open the safe! +|The safe code was: +YN|Do you want to try again ? [Y/n]: +YN|Do you want to open the safe ? [Y/n]: +|THE SAFE IS CURRENTLY LOCKED +|has cracked the safe. +|The safe will remain locked until the sysop rewards the user. +|Maximum trys per day Exceeded! +|Message to Nextuser Door +|The FROM, TO and SUBJECT fields are optional. +| From: +| To: +|Subject: +| Type up to 10 lines 74 Characters per line +|Functions available: +LREAS|(L)ist, (R)eplace text, (E)dit line, (A)bort, (S)ave +|Select: +|Aborting... +|Returning to +|Edit which line: +|Line does not exist. +|Old Password: +|New password: +|Confirm new password: +|Passwords do not match! +|Password Change Successful +|Old password incorrect! +|User List +|Enter Username search string or (Enter) for all users: +|Name Location Last On Calls +|Could not find search string ... +|Time limit exceeded ... disconnecting! +YN=M|More (Y/n/=) M=Mark +|Scanning +|with +|TIME STATISTICS for +|on +|Current Time : +|Current Date : +|Connect time : +|Time used today : +|Time remaining today : +|Daily time limit : +|You have +YN|messages, read your mail now? [Y/n]: +|You have no new mail in your mail box ... +|Hotkeys are now ON +|Hotkeys are now OFF +|On +|Off +|User name already exists +|Checking your mail box ... +| MBSE BBS Chat +|The SysOp is currently speaking to somebody else on +|Try paging him again in a few minutes ... +|You have paged the Sysop the maximum times allowed. +|Sysop currently is not available ... please leave a comment +|Posting message in area: +|From : +|To : +|Verifying user ... +|User not found. Try again, or (Enter) to quit +|Subject : +YN|Abort Message [y/N] ?: +YN|Private [y/N]: +|Begin your message now, Blank line to end +|Maximum of 60 lines, 73 characters per line +|Maximum message length exceeded +|Functions available: (Current Message: +|Lines) +|L - List message S - Save message C - Continue message +|Q - Quit message D - Delete line I - Insert line +|T - Text edit E - Edit line R - Replace line +LSCQDITERZ|Z - Center line +|Select +|Continue +|Delete +|Delete starting at line +|Aborted. +|Please enter a number in the range of +|Delete ending at line +|Edit +|Enter line # to edit +|Insert +|Enter line # to insert text before +|List +|Enter line # to replace +|Line reads: +|Unchanged. +|Line now reads: +|Quit +YN|Are you sure [y/N]: +|Message aborted. +|No +|Text Edit +|Enter line # to edit +|Text to replace : +|Replacement text : +|Line now reads: +|Save +|Possible VIRUS found! +|Ok +|Unpacking archive +|Saving message to disk +|Enter line # to center +|Line is maximum length and cannot be centered +|There are no messages in this area. +|Date : +YN=|More (Y/n/=/Area #): +|To : +|From : +|Subject : +|Next reply: +|Reply to: +|messages in +ANLREQDX|(A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (D)el, (Q)uit, e(X)port +|(A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (Q)uit, e(X)port +|Next +|ERROR +RNQ|(R)eply, (N)ext, (Q)uit: +|Enter to keep Subject. +|# From To Subject +|Message area +|contains +|messages. +|Please enter a message between +|Message number [ +|Area Type Description Messages Personal +|thread +|Enter the name of the conference, or ? for a list: +|Conference Area Msgs Description +|Deleting message +| Message Areas +|Select Area: +|Invalid area specified - Please try again ... +|Password is incorrect +|Password is correct +|You don't have enough security to list this area +|Can't open file database for this area +|Uploaded by: +|D E L E T E D +|M I S S I N G +YN|Node not known, continue anyway [y/N]: +|Total Files: +|FATAL: Unable to open areas database +|You do not have enough access to download from this area. +|Please enter filename: +|No filename entered, Aborting. +|Illegal Filename! +|Sorry that file is unavailable for download +|You have +|extra download KBytes. +|You do not have enough time to download that file. +|You do not have enough bytes to download " +|You must upload before you can download. +|Kilobytes currently available: +|Checking your marked downloads, please wait... +|Untag Offline Reader message areas +|Found FILEID.DIZ in +|No files marked for download. +|extra minutes. +|You have selected the following Conference(s): +|Filename Size Date +|Protocol: Can't open protocol file. +|Select your preferred file transfer protcol +|Select Protocol (Enter to Quit): +|Ivalid selection, please try again! +|Protocol now set to: +|Enter keyword to use for Search: +|File Search by Keyword +|Accepts wildcards such as : *.zip, *.gz, .tar* +| : *.zip is the same as .zip +|Enter filename to search for : +|File Search by Filename +YN|Search for new since your last call [Y/n]: +|Enter new date to search for [DD-MM-YYYY]: +|File Search by Date +|Please enter file to upload: +|Offline Reader Download +|You do not have enough access to upload to this area. +|You have not enough diskspace free to copy this file +|files( +|bytes) marked for download. +|The file already exists on the system +|Please start your upload now ... +|Upload was unsuccessful for: +YN|Do you want to password protect your upload ? [y/N]: +|REMEMBER: Passwords are "CaSe SeNsITiVe!" +|Please enter description of file +|Your upload time has been returned to you. Thank you for your upload! +|Start copy: +|Can't open directory for listing: +|Home directory listing for +|Please enter filename to delete: +|Sorry you may not delete hidden files ... +|Unable to delete file ... +|Invalid filename, please try again ... +|File does not exist, please try again ... +|Forum Description Msgs. Pers. +| File Areas +|Please enter Area Password: +|Adding BBS +|BBS Name: +|Response needed ... +|Phone Number: +|Sysop Name: +|BBS Software: +|Storage (GigaByte): +|Speeds: +YN|Would you like to add a extended discription? [Y/n]: +|Please a enter discription for +|BBS Listing +|# BBS Name Number Software GigaByte Speed +|Search for a BBS +|Please enter 3 letters of BBS to search for: +|I need at least 3 letters ... +YN|View this BBS? [Y/n]: +|Could not find the BBS Listed ... +|Show a BBS +|Please enter number to list: +|Record does not exist +| Record : +| BBS Name : +| Number : +| Software : +| GigaBytes : +| Speeds : +| Sysop Name : +| Available : +| Date of Entry : +| Entry Name : +|Delete BBS +|Please enter number to delete: +|Record +|does not belong to you. +|already marked for deletion +|marked for deletion +|The Sysop will purge the list once he has +|seen you have marked a record for deletion. +|Total messages found: +|Unknown Menu Command! +|Saving... +|MBSE BBS Oneliners will randomly appear on the main menu. +|Obscene or libellous oneliners will be deleted!! +|Please enter your oneliner below. You have 75 characters. +|Oneliner added +| # A Date User Description +| # Description +|Please enter number to list: +|Connected on port +|File(s) : +|Size : +|Protocol : +|Updating download counters, please wait ... +|Failed! +|Bytes +| # Area Active File Size Cost +|Yes +|No +TE|(T)oggle active, (E)rase all, (ENTER) to continue: +|Enter file number, 1.. +|Marked: +|No files tagged. +|Replace +|Loading BBS, please wait ... +|New or deleted mail areas at +|Area State Type Description +|New Mail check is now ON +|New Mail check is now OFF +|Delete file: +YN|Are you Sure? [Y/n]: +|New Files check is now ON +|New Files check is now OFF +|Fullscreen Editor is now ON +|Fullscreen Editor is now OFF +|No messages found to download! +|Press (Enter) to continue: +|Center +|Too much messages. Only the first +|Select your preferred language +|Select Language: +|Language now set to: +|The system will now ask you for a "Unix Account" +|Your "Unix Account" is created, you may use it the next time you call. +|Please enter a login name (Maximum 8 characters) +|ie. John Doe, login = jdoe +|login > +|That login name already exists, please choose another one. +|FATAL: Cannot open language definition file +|Your new Unix and BBS password will be the same. +|FATAL ERROR: You are not in the BBS users file. +| Please run 'newuser' to create an account +|New +|Local +|Netmail +|Echomail +|News +|E-Mail +|Del +|Jan +|Feb +|Mar +|Apr +|May +|Jun +|Jul +|Aug +|Sep +|Oct +|Nov +|Dec +|Autologout: idletime reached. +|Will be packed! +|Enter your handle (Enter for none): +|You are now ready to use the bbs +|Callers On-Line to +|Name Device Status Location +|Do not disturb turned OFF +|Do not disturb turned ON +|Browsing +|Downloading +|Uploading +|Msg Section +|External Door +|Chatting +|Listing Files +YN|Do you want to download these messages [Y/n]? +|Banking Door +|Safe Door +|WhosOn List +|Idle +|Please enter username to send message to: +|Sorry, there is no user on +|doesn't wish to be disturbed +|Please enter in message to send (Max 76 Characters) +|** Message ** from +|Your password is expired, new password : +|Press ENTER to continue +|Posting not allowed, this area is Read Only! +|Replies are not allowed in this area! +|Offline Reader Upload +|Invalid packet received +|Unknown compression type +|Archiver not available +|Unknown type mailpacket +|BlueWave Offline download +|Preparing packet +|Packing with +|Download failed +|Download successfull +|Updating lastread pointers +|Processing BlueWave reply packet +|ERROR in packet +|Import messages +|No Write access to area +|Messages imported +|Processing Offline Configuration +|Message areas selected +|Processing file requests +|QWK Offline Download +|Processing QWK reply packet +|ASCII Offline Download +YN|Crash [y/N]: +YN|Warning: node is not CM, send immediate [y/N]: +YN|Attach file [y/N]: +|File +|will be attached +|File not within +|mailbox - Incoming and outgoing email +|archive - Archive of your email +|trash - Trashcan, your old email +|Area # +|minutes. diff --git a/lang/italian.txt b/lang/italian.txt new file mode 100644 index 00000000..2fbb93ac --- /dev/null +++ b/lang/italian.txt @@ -0,0 +1,472 @@ +|Digita Nome e Cognome: +|Digita il tuo Cognome: +|Scollegamento in corso ... +|Controllo User File in corso... +SN|Hai scritto il tuo nome e cognome correttamente? [S/n] +|Nome inserito: +|Questo e' un sistema telematico PRIVATO. Scrivi "off" per uscire ora +|Scegli il numero del file o premi per interrompere +|Password: +|Numero massimo di tentativi per il login raggiunto ... +|Hai inserito un NOME o una PASSWORD errata +| MBSE BBS Banca di Sistema +|Account bancario di : +|Tempo disponibile : +|Byte disponibili : +|Tempo depositato oggi: +|Byte depositati oggi : +|Tempo prelevato oggi : +|Byte prelevati oggi : +DPE|(D)eposita, (P)releva, (E)sci: +|Banca > +TBE|(T)empo, (B)yte, (E)sci : +|Devi avere almeno 5 minuti restanti per poter depositare +|Scegli la quantita di tempo. Hai a disposizione minuti +|Hai cercato di depositare piu del limite massimo oggi. +|Massimo numero di minuti che puoi depositare ogni giorno: +|Hai superato il limite per il tuo account. +|Massimo numero di minuti disponibili nel tuo account: +|Puoi depositare: +|Hai cercato di prelevare piu del limite massimo oggi. +|Massimo numero di minuti che puoi prelevare ogni giorno: +|You have tried to withdraw more time than is in your bank account. +|Stato attuale del tuo account: +|Numero massimo di KB che puoi depositare ogni giorno: +|Hai superato il limite per il tuo account. +|Numero massimo di KB che puoi tenere nel tuo account: +|Scegli la quantita di KB. KB disponibili: +|MBSE Bulletin Board System - REGISTRAZIONE DEI NUOVI UTENTI +|Usa questo nome: +|Inserisci una nuova password: +|Verifica la nuova password : +|Le password inserite non sono uguali! Prova ancora. +|La password deve contenere almeno +|caratteri! Prova ancora. +SN|Vuoi usare la grafica ANSI [S/n]: +|Inserisci il tuo numero di telefono voce +|Messaggio esportato nella tua home con nome: +|Inserisci un numero di telefono corretto +|Inserisci il tuo numero di telefono dati +|Inserisci la localita da cui chiami +|La localita' inserita e' troppo breve +MF|Sesso? (M)aschio o (F)emmina: +|Maschio +|Femmina +|Per favore rispondi con M o F +|Sconosciuto +|Inserisci la tua data di nascita nel formato: GG-MM-AAAA: +|Mi dispiace, hai inserito un anno errato. +|Per favore inserisci la data nel formato corretto +|*** Il Sysop sta lanciando la chat *** +|*** Il Sysop ha chiuso la chat *** +SN=|Ancora (S/n/=) +SN|Vuoi abilitare le Hot-Key? [S/n]: +|Per favore rispondi con S o N +|Scegli la lunghezza in righe delle schermate? [24]: +|Nessuno +|Marca le aree messaggi dell'Offline Reader +|Il tuo account e' stato creato il: +|Nome utente : +|Password : +|riservato +|Loggati nella BBS usando il nome utente sopra riportato. +|Non trovo +|Vecchia Localita': +|Per favore inserisci un nome piu' lungo (almeno +|La modalita' ANSI ora e': ON +|La modalita' ANSI ora e': OFF +|Il messaggio non esiste +|Le News ora sono: ON +|Le News ora sono: OFF +|Il numero di righe per schermata e' 24 +|Il numero di righe per schermata e' ora fissato a: +|Messaggio privati, non sei autorizzato +|Per favore usa il formato corretto per la data +|Hanno chiamato oggi +|# Nome Utente Linea Durata Calls Localita' +|Apri la cassaforte DOOR +|Premi un tasto per continuare: +|In the safe lies ... +|Per favore inserisci 3 numeri compresi tra 1 e +|Devi indovinare la combinazione della cassaforte. +|Prima cifra: +|Prova ancora! Devi scegliere un numero maggiore di 0 e minore di +|Seconda cifra: +|Terza cifra: +| Sinistra: +| Destra: +SN|Provo a aprire la cassaforte con questa combinazione [S/n]: +|Hai vinto... +|Mi dispiace - Non sei riuscito a aprire la cassaforte! +|La combinazione giusta era: +SN|Vuoi provare ancora ? [S/n]: +SN|Vuoi aprire la cassaforte ? [S/n]: +|LA CASSAFORTE AL MOMENTO RISULTA BLOCCATA +|ha aperto la cassaforte. +|La cassaforte restera' chiusa finche' il SysOp non consegnera' il premio. +|Numero massimo di tentativi giornalieri raggiunto! +|Messaggio per il prossimo utente DOOR +|I campi DA, A e OGGETTO sono facoltativi. +| Da: +| A: +|Oggetto: +| Scrivi fino a un massimo di 10 righe con 74 caratteri per riga +|Funzioni disponibili: +MREAS|(M)ostra, (R)impiazza testo, (E)dita la linea, (A)nnulla, (S)alva +|Seleziona: +|Messaggio annullato... +|Sto ritornando a +|Numero linea da editare: +|Quella linea non esiste. +|Vecchia Password: +|Nuova Password: +|Verifica la nuova Password: +|Le Password non corrispondono! +|Cambio Password accettato +|La vecchia password e' errata! +|Lista Utenti +|Inserisci una stringa da cercare o premi (Invio) per la lista completa: +|Nome Localita' Ultima volta Chiamate +|Non ho trovato corrispondenze ... +|Tempo massimo raggiunto ... scollegamento in corso! +SN=M|Ancora (S/n/=) M=Marca +|Sto cercando +|con +|STATISTICHE del tempo per +|il +|Ora attuale : +|Data attuale : +|Ora di connessione : +|Tempo usato oggi : +|Tempo rimasto per oggi : +|Limite di tempo odierno: +|Hai +SN|nuovi messaggi, vuoi leggere la posta ora? [S/n]: +|Non hai nuovi messaggi nella tua mail box ... +|Hotkeys ABILITATE +|Hotkeys DISABILITATE +|On +|Off +|Nome utente gia' in uso +|Sto controllando la tua mail box ... +| MBSE BBS Chat +|Il SysOp sta parlando con un altro utente su +|Prova a chiamarlo di nuovo fra pochi minuti ... +|Hai gia' chiamato il SysOp per il massimo numero di volte consentito. +|Il SysOp non e' al momento disponibile ... lascia un messaggio +|Area di destinazione: +|Da : +|A : +|Controllo nome utente ... +|Nome utente non trovato. Prova ancora, o premi (Enter) per uscire +|Oggetto : +SN|Annulla Messaggio [s/N] ?: +SN|Privato [s/N]: +|Comincia a scrivere il messaggio, lascia una riga vuota per terminare +|Massimo 60 righe da 73 caratteri ciascuna +|Lunghezza massima del messaggio raggiunta +|Funzioni disponibili: (Messaggio attuale: +|Righe) +|L - Leggi messaggio S - Salva messaggio C - Continua messaggio +|A - Abbandona D - Cancella riga I - Inserisci riga +|M - Edita tutto E - Edita riga R - Rimpiazza riga +LSCADIMERZ|Z - Linea centrale +|Seleziona +|Continua +|Cancella +|Cancella a partire dalla riga +|Abbandonato. +|Inserisci un numero nell'intervallo +|Cancella fino a alla riga +|Edita +|Inserisci il numero della riga da editare +|Inserisci +|Inserisci il numero della riga prima della quale inserire il testo +|Leggi +|Inserisci il numero della riga da rimpiazzare +|La linea contiene: +|Immutato. +|La linea e' diventata: +|Esci +SN|Confermi [s/N]: +|Messaggio annullato. +|No +|Edita il Testo +|Inserisci la linea da modificare +|Testo da rimpiazzare : +|Nuovo testo : +|La linea e' diventata: +|Salva +|Possibile VIRUS rilevato! +|Ok +|Decompressione archivio +|Salvataggio del messaggio su disco +|Inserisci la linea da centrare +|La linea e' troppo lunga per essere centrata +|Non ci sono messaggi in quest'area. +|Data : +SN=|Ancora (S/n/=/Area #): +|A : +|Da : +|Oggetto : +|Prossima risposta: +|Rispondi a: +|messaggi in +APURSCEO|(A)ncora,(P)rossimo,(U)ltimo,(R)ispondi,(S)rivi,(C)ancella,(E)sci,esp(O)rta +|(A)ncora, (P)rossimo, (U)ltimo, (R)ispondi, (S)crivi, (E)sci, esp(O)rta +|Prossimo +|ERRORE +RPE|(R)ispondi, (P)rossimo, (E)sci: +|Premi Invio per mantenere il Subject. +|# Da A Oggetto +|Area messaggi +|contiene +|messaggi. +|Per favore scegli un messaggio tra +|Numero Messaggio [ +|Area Tipo Descrizione Messaggi Personali +|thread +|Inserisci il nome della conferenza o premi ? per avere la lista: +|Conferenza Area Msgs Descrizione +|Cancello il messaggio +| Aree Messaggi +|Seleziona Area: +|Area specificata non valida - Prova di nuovo ... +|Password errata +|Password corretta +|Non hai livello d'accesso sufficiente per sfogliare quest'area +|Non trovo il database dei file di quest'area +|Uploadato da: +|C A N C E L L A T O +|M A N C A N T E +SN|Nodo sconosciuto, continua lo stesso [s/N]: +|File Totali: +|FATAL: Non trovo il database dell'area +|Non hai livello d'accesso sufficiente per scaricare da quest'area. +|Digita il nome del file: +|Nome del file non valido, operazione annullata. +|Filename non valido! +|Mi dispiace quel file non e' disponibile per il download +|Ora hai +|KBytes in piu' da scaricare. +|Non hai abbastanza tempo per scaricare quel file. +|Non hai abbastanza crediti per scaricare " +|Devi uplodare prima di scaricare. +|Kilobytes disponibili: +|Controllo della lista di download in corso, attendere prego... +|Untag aree messaggi per l'Offline Reader +|Trovato FILEID.DIZ in +|Nessun file selezionato per il download. +|minuti extra. +|Hai selezionato le seguenti Conferenze: +|Filename Dimensione Data +|Protocollo: Non posso aprire il file del protocollo. +|Seleziona il tuo protocollo di trasferimento preferito +|Seleziona Protocollo (Invio per uscire): +|Selezione errata, per favore prova ancora! +|Protocollo impostato su: +|Inserisci la parola da cercare: +|Ricerca file per parola chiave +|Accetto caratteri jolly come : *.zip, *.gz, .tar* +| : *.zip e' equivalente a .zip +|Scegli il filename da cercare: +|Ricerca per nome del file +SN|Cerca nuovi file dall'ultima chiamata [S/n]: +|Scegli una data per la ricerca dei nuovi file [GG-MM-AAAA] +|Ricerca per data +|Scegli il file da uploadare: +|Offline Reader Download +|Non hai livello di accesso sufficiente per uploadare in quest'area. +|Non hai abbastanza spazio libero per copiare questo file +|file( +|byte) marcati per il download. +|Il file e' gia' presente nel sistema +|Per favore comincia l'upload ... +|Upload terminato con successo: +SN|Vuoi proteggere con password il tuo upload ? [s/N]: +|RICORDA: Le password sono "CaSe SeNsITiVe!" +|Inserisci una descrizione per il file +|Il tempo impiegato per l'upload ti e' stato restituito. +|Inizia la copia: +|Non posso aprire la directory in lettura: +|Contenuto della Home per +|Scegli il nome del file da cancellare: +|Mi dispiace non puoi cancellare i file nascosti ... +|Impossibile cancellare il file ... +|Nome del file errato, prova ancora ... +|File non trovato, prova ancora ... +|Forum Descrizione Msgs. Pers. +| Aree File +|Inserisci la password per l'Area: +|Aggiungo la BBS +|Nome BBS: +|E' richiesta una risposta ... +|Numero di telefono: +|Nome del SysOp: +|BBS Software: +|Capacita' (GigaByte): +|Velocita' connessione: +SN|Vuoi aggiungere una ulteriore descrizione? [S/n]: +|Per favore inserisci una descrizione per +|Lista BBS +|# Nome BBS Numero Software GigaByte Velocita' +|Cerca una BBS +|Inserisci le prime 3 lettere del nome da cercare: +|Ho bisogno di almeno 3 lettere ... +SN|Mostra questa BBS? [S/n]: +|Non ho trovato la BBS nella lista ... +|Mostra una BBS +|Inserisci il numero da mostrare: +|Elemento non presente in lista +| Record : +| Nome BBS : +| Numero : +| Software : +| GigaByte : +| Velocita' : +| Nome SySop : +| Attiva : +| Data : +| Nome entry : +|Cancella BBS +|Inserisci il numero da cancellare: +|Record +|non appartiene a te. +|e' gia' marcata per l'eliminazione +|marcata per l'eliminazione +|The SySop pulira' la lista una volta accortosi +|che una BBS e' stata marcata per l'eliminazione. +|Totale messaggi trovati: +|Comando sconosciuto! +|Sto salvando... +|MBSE BBS Oneliners appariranno sul menu principale. +|Non sono ammesse frasi oscene o offensive!! +|Inserisci la tua frase. Hai a disposizione 75 caratteri. +|Oneliner aggiunto +| # A Data Utente Descrizione +| # Descrizione +|Inserisci il numero della corrispondeza da mostrare: +|Connesso sulla porta +|File : +|Dimensione: +|Protocollo: +|Aggiornamento del contatore dei download, attendere ... +|Fallito! +|Byte +| # Area Attivo File Size Costo +|Si +|No +CE|(C)ambia aree attive, (E)limina tutto, (INVIO) per continuare: +|Scegli il numero del file, 1.. +|Marcati: +|Nessun file marcato. +|Rimpiazza +|Sto caricando la BBS, attendere prego ... +|Nuove aree o aree cancellate su ... +|Area Stato Tipo Descrizione +|Controllo per posta in arrivo ATTIVATO +|Controllo per posta in arrivo DISATTIVATO +|Cancella file: +SN|Sei sicuro? [S/n]: +|Controllo per i nuovi file ATTIVATO +|Controllo per i nuovi file DISATTIVATO +|Editor a schermo pieno ATTIVATO +|Editor a schermo pieno DISATTIVATO +|Nessun messaggio da scaricare trovato! +|Premi (Invio) per continuare: +|Centra +|Troppi messaggi. Solo il primo +|Segli la lingua preferita +|Seleziona Lingua: +|Lingua impostata su: +|Ti verra' ora chiesto di scegliere un "Account Unix" +|L' Account Unix e' stato creato, dovrai usarlo la prossima volta che chiami. +|Scegli uno username per il login (Massimo 8 caratteri) +|es. Mario Rossi, login = mrossi +|login > +|Quel login esiste gia', scegline uno leggermente diverso. +|FATAL: Non riesco a aprire il file per quella lingua +|La tua password per l' "Account Unix" e la BBS saranno identiche. +|FATAL ERROR: Non sei nel database degli utenti della BBS. +| Lancia 'newuser' per creare un account +|Nuovo +|Locale +|Netmail +|Echomail +|News +|E-Mail +|Canc +|Gen +|Feb +|Mar +|Apr +|Mag +|Giu +|Lug +|Ago +|Set +|Ott +|Nov +|Dic +|Autologout: tempo di inattivita' massimo raggiunto. +|Sara' impachettato! +|Inserisci il tuo soprannome (Invio se non ne vuoi uno): +|Sei pronto per usare la BBS +|Utenti online per +|Nome Device Stato Localita' +|Modalita' "Do not disturb" DISATTIVATA +|Modalita' "Do not disturb" ATTIVATA +|Esplorazione +|Downloading +|Uploading +|Sezione Msg +|Door Esterna +|Chatting +|Lista File +SN|Vuoi scaricare questi messaggi [S/n]? +|Banking Door +|Safe Door +|WhosOn +|Idle +|Digita il nome della persona a cui inviare il messaggio: +|Mi dispiace, non c'e' tale utente +|l'utente non vuole essere disturbato +|Scrivi il messaggio da spedire (Max 76 Caratteri) +|** Messaggio ** da +|La tua password e' scaduta, nuova password : +|Premi INVIO per continuare +|Posting non consentito, quest'area e' in sola lettura! +|Non e' consentito rispondere in quest'area! +|Offline Reader Upload +|Ricevuto pacchetto non valido +|Algoritmo di compressione sconosciuto +|Compressore non disponibile +|Tipo di pacchetto di posta sconosciuto +|BlueWave Offline download +|Preparo il pacchetto +|Impacchetto con +|Download fallito +|Download completato +|Aggiornamento puntatori all'ultimo messaggio +|Processo il pacchetto BlueWave delle risposte +|ERRORE nel pacchetto +|Importa messaggi +|Non hai accesso in scrittura all'area +|Messaggi importati +|Sto processando la configurazione per la lettura Offline +|Aree messaggi selezionate +|Sto processando i file request +|QWK Offline Download +|Processo il pacchetto QWK delle risposte +|ASCII Offline Download +SN|Crash [s/N]: +SN|Attenzione: il nodo non e' in CM, spedisci immediatamente [s/N]: +SN|Allega file [s/N]: +|Il File +|sara' allegato +|File non e' all'interno +|mailbox - Email in arrivo e in uscita +|archive - Archivio delle tue email +|trash - Cestino, la tua posta vecchia +|Area # +|minuti. diff --git a/lang/spanish.txt b/lang/spanish.txt new file mode 100644 index 00000000..0169ebb2 --- /dev/null +++ b/lang/spanish.txt @@ -0,0 +1,472 @@ +|Por favor teclee su nombre y apellidos: +|Por favor teclee sus apellidos: +|Desconectando usuario ... +|Explorando fichero de usuarios ... +SN|¨Has escrito correctamente tu nombre? [S/n] +|Nombre escrito: +|Este es un sistema PRIVADO. Teclea "off" para salir +|Teclee n£mero de fichero o para terminar : +|Password: +|El n£mero de errores permitidos se ha sobrepasado ... +|Tu nombre o tu PASSWORD son incorrectos +| Banco de PAROLAS BBX +|Cuenta: +|Tiempo en la cuenta : +|Bytes en la cuenta : +|Tiempo depositado hoy : +|Bytes depositados hoy : +|Tiempo retirado hoy : +|Bytes retirados hoy : +DRS|(D)epositar, (R)etirar, (S)alir : +|Banco > +TBS|(T)iempo, (B)ytes, (S)alir : +|Debes tener al menos 5 minutos para poder depositar +|¨Cuanto tiempo?. Disponible en minutos : +|Has intentado depositar mas del m ximo permitido para hoy. +|M ximo tiempo diario que se puede depositar: +|Has excedido el saldo de tu cuenta. +|Minutos disponibles en tu cuenta : +|Se te permite depositar: +|Has intentado retirar m s del l¡mite m ximo diario. +|M ximo permitido diario para retirar: +|Has intentado retirar m s tiempo del que tienes en tu cuenta. +|El saldo de tu cuenta es : +|M ximo de Kb permitido depositar diariamente: +|Has excedido el saldo de tu cuenta. +|Kilobytes disponible en tu cuenta : +|¨Cuantos kilobytes. Dispones de +|Parolas BBX - REGISTRO DE NUEVO USUARIO +|Use este nombre: +|Por favor teclee el nuevo password : +|Por favor tecleelo de nuevo...... : +|­No coinciden! Vuelta a empezar... +|El password debe tener como m¡nimo +|caracteres. Vuelta a empezar... +SN|¨Quieres gr ficos ANSI [S/n]: +|Teclea tu n£mero de tel‚fono de VOZ +|Mensaje exportado a tu directorio privado como: +|N£mero de tel‚fono incorrecto. Repite... +|Teclea tu n£mero de tel‚fono de MODEM +|¨Donde vives? (Ciudad): +|El nombre de tu ciudad es demasiado corto. Repite por favor +HM|¨Tu que eres (H)ombre o (M)ujer: +|Hombre +|Mujer +|Responde solo H o M +|Desconocido +|Fecha de nacimiento (DD-MM-AAAA): +|Has tecleado este a¤o por error. +|Teclea la fecha en formato correcto (DD-MM-AAAA) +|*** Atenci¢n: Te habla el SysOp *** +|*** Fin de la charla. Que tengas un buen d¡a *** +SN=|M s (S/n/=) +SN|¨Quieres men£s r pidos? [S/n]: +|Por favor contesta S ¢ N +|Longitud en l¡neas de tu pantalla [24]: +|Nada +|Marcar  reas para lectura Off-Line +|Tu cuenta de usuario ha sido creada: +|Nombre de Login : +|Password : +|no visualizable +|Puedes entrar en la BBS con el nombre anterior +|No encuentro +|Localidad anterior : +|Localidad demasiado corta: (min. +|Modo ANSI activado +|Modo ANSI desactivado +|No existe el mensaje +|Noticias activadas +|Noticias desactivadas +|Lineas de pantalla 24 +|Lineas de pantalla : +|Mensaje privado, y no es tuyo +|Teclee el formato de fecha correcto +|Hoy llamaron a +|# Usr. Nombre Puerto Tiempo Llams Localidad +|Juego de Robar la Caja Fuerte +|Pulse una tecla para seguir: +|En la caja hay ... +|Teclee tres n£meros de 1 a +|Teclee tres combinaciones. +|1er digito: +|­Repita! Debe ser un n£mero mayor que cero y menor que +|2§ digito : +|3er digito: +|Izquierda : +| Derecha : +SN|Intento abrir con esta combinaci¢n [S/n]: +|Has ganado ... +|­Ohhh! - No se abre... +|La combinaci¢n era: +SN|¨Quieres volver a intentarlo? [S/n]: +SN|¨Quieres intentar abrir la caja? [S/n]: +|LA CAJA ESTA BLOQUEADA. +|ha abierto la caja. +|la caja permanecer  bloqueada hasta que el SysOp recompense al usuario. +|­Has excedido el m ximo n£mero de intentos diarios! +|Mensaje al siguiente usuario: +|Los campos De, Para y Asunto son opcionales. +| De: +| Para: +| Asunto: +| Teclea hasta 10 lineas de 74 Caracteres por linea +|Funciones disponibles: +LCEAG|(L)istar, (C)ambiar texto, (E)ditar linea, (A)bandonar (G)uardar +|Elija: +|Abandonando... +|Volviendo a +|Editar la linea n§: +|Esa no existe. +|Password viejo: +|Password nuevo: +|Repite el nuevo: +|­No coinciden! +|Password cambiado. No lo olvides... +|­Password viejo incorrecto! +|Lista de usuarios +|Buscar un nombre (Enter para listar todos): +|Nombre Localidad U.Llamada Llamadas +|No lo encuentro ... +|Limite de tiempo sobrepasado ... desconectando! +SN=M|M s (S/n/=) M=Marcar +|Buscando +|con +|Estad¡sticas de TIEMPO de +|en +|Hora Actual : +|Fecha Actual : +|Tiempo de conexion : +|Tiempo usado hoy : +|Tiempo que queda : +|L¡mite diario : +|Tienes +SN|mensajes, ¨Quieres leerlos ahora? [S/n]: +|No tienes correo nuevo a tu nombre ... +|Men£s r pidos activados +|Men£s r pidos desactivados +|Activado +|Desactivado +|El nombre ya existe +|Buscando correo nuevo ... +| Charla de PAROLAS BBS +|El Sysop est  hablando con otro usuario en +|Intenta llamarlo de nuevo dentro de un rato ... +|Ya has llamado muchas veces. +|El SysOp no est  ... ¨por que no le dejas un mensaje? +|Poniendo mensaje en el  rea: +|De : +|Para : +|Verificando usuario... +|Usuario no existe. Repite, o (Enter) para salir +|Asunto : +SN|¨ Cancelar Mensaje [s/N] ?: +SN|Privado [s/N]: +|Comienza a escribir tu mensaje. (Enter) en una nueva linea para salir. +|M ximo 60 lineas, 73 caracteres por linea +|Longitud m xima sobrepasada +|Funciones disponibles: (Mensaje Actual: +|Lineas) +|L - Listar mensaje G - Guardar mensaje C - Continuar escribiendo +|A - Abandonar B - Borrar l¡neas I - Insertar linea +|T - editar Texto E - Editar l¡nea S - Sustituir linea +LGCABITESZ|Z - Centrar linea +|Elija +|Continuar +|Borrar +|Borrar desde la l¡nea +|Abandonar. +|Teclee un n£mero comprendido entre +|Borrar hasta la l¡nea +|Editar +|N§ de linea a editar +|Insertar +|Insertar antes de la l¡nea n§ +|Listar +|N§ de Linea a susutituir +|La linea dice: +|No modificada. +|La linea ahora dice: +|Abandonar. +SN|¨Est s seguro? [s/N]: +|Mensaje anulado. +|No +|Editar texto +|N§ de l¡nea a editar +|Texto a cambiar : +|Texto nuevo : +|La l¡nea ahora dice: +|Guardar +|­Posible VIRUS encontrado! +|Ok +|Descomprimiendo +|Guardando mensaje en disco +|N§ de linea # a centrar +|La linea es demasiado larga y no se puede centrar +|No hay mensajes en esta  rea. +|Fecha : +SN=|M s (S/n/=/n§  rea): +|Para : +|De : +|Asunto : +|Sig. resp.: +|Resp. a: +|mensajes en +OSARETBX|(O)tra vez (S)ig. (A)nt. (R)esp. (E)ntrar (B)orrar (T)erminar e(X)port. +|(O)tra vez (S)ig. (A)nt. (R)esponder (E)ntrar (T)erminar e(X)portar +|Siguiente +|ERROR +RST|(R)esponder, (S)iguiente, (T)erminar: +|Enter para mantener el mismo asunto +|n§ De Para Asunto +|El  rea +|tiene +|mensajes. +|Teclee un mensaje entre +|N£mero de mensaje [ +|Area Tipo Descripci¢n Mensajes Personal +|hilo +|Teclee TAG del  rea, ? para ver lista: +|TAG Area Msjs Descripci¢n +|Borrando mensaje +| Areas de Mensajes +|Elija un  rea: +| rea elegida no v lida - Elija otra ... +|Password incorrecto +|Password correcto +|No tienes permiso para listar esta  rea +|No puedo abrir la base de ficheros de esta  rea +|Enviado por: +|B O R R A D O +|P E R D I D O +SN|Nodo desconocido. ¨Continuar? [s/N]: +|Total Fichs: +|FATAL: Imposible abrir base de  reas +|No tienes permiso para descargar ficheros de esta  rea. +|Nombre del fichero: +|Nombre vac¡o, cancelando. +|­Nombre de fichero no v lido! +|Ese fichero no est  disponible para descargar +|Tienes +|KBytes extra para descargar. +|No tienes tiempo suficiente para descargar ese fichero. +|No tienes suficiente cr‚dito para descargar " +|Debes enviar algo antes de descargar. +|Kilobytes disponibles: +|Verificando ficheros marcados, espera un poco... +|Desmarcar  reas para lectura Off-Line +|Encontrado FILEID.DIZ en +|No hay ficheros marcados. +|minutos extra. +|Has deleccionado las siguientes  reas: +|Fichero Tama¤o Fecha +|Protocolo: No puedo abrir fichero de protocolos. +|Elija el protocolo de transferencia predeterminado +|Elija Protocolo (Enter para salir): +|Ese no vale, ­Elija otro! +|Protocolo predeterminado: +|Palabra a buscar: +|Buscar fichero por una palabra +|Se aceptan comodines como : *.zip, *.gz, .tar* +| : *.zip es lo mismo que .zip +|Nombre de fichero a buscar: +|Buscar fichero por nombre +SN|Buscar nuevos ficheros desde tu £ltima llamada [S/n]: +|Fecha desde la que buscar [DD-MM-YYYY]: +|Buscar ficheros por fecha +|Nombre del fichero a enviar: +|Descargar Correo para lectura OFF-LINE +|No tienes permiso para enviar ficheros a esta  rea. +|No hay suficiente espacio libre para copiar este fichero +|ficheros( +|bytes) marcados para descargar. +|El fichero ya existe en este sistema +|Comienza a enviar ahora ... +|Env¡o no completado por: +SN|¨Quieres proteger con password el fichero enviado? [s/N]: +|­RECUERDA! La password es "CaSe SeNsITiVe!" +|Teclee la descripci¢n del fichero +|El tiempo del env¡o se te devuelve. ­Gracias por tu fichero! +|Copiando a directorio personal : +|No puedo abrir directorio para listar: +|Listado del directorio personal de +|Nombre del fichero a borrar: +|No puedes borrar ficheros ocultos ... +|Imposible borrar fichero ... +|Nombre no v lido, prueba otra vez ... +|El fichero no existe, prueba otra vez ... +|Area Descripci¢n Msgs. Pers. +| Areas de ficheros +|Teclee password del  rea: +|A¤adiendo BBS +|Nombre de la BBS: +|Respuesta obligatoria ... +|N£mero de tel‚fono: +|Nombre del SysOp: +|Software de BBS: +|Almacenamiento (GigaBytes): +|Velocidades: +SN|¨Quieres a¤adir una descripcion? [S/n]: +|Teclea la descripci¢n de +|Listado de BBSs +|n§ Nombre BBS N£mero Software GigaByte Veloc. +|Buscar una BBS +|Teclee 3 letras de la BBS que quiere buscar: +|Necesito al menos 3 letras ... +SN|¨Ver esta BBS? [S/n]: +|No puedo encontrar BBS ... +|Mostrar una BBS +|N£mero a listar: +|Registro inexistente +| Registro : +| Nombre BBS : +| N£mero : +| Software : +| GigaBytes : +| Velocidades : +| SysOp : +| Disponible : +| Fecha entrada : +| Entrada por : +|Borrar BBS +|Teclee n£mero de BBS a borrar: +|El Registro +|no te pertenece. +|ya estaba marcado para borrar +|queda marcado para borrar +|El SysOp eliminar  de la lista un d¡a de estos +|todos los registros marcados para borrar. +|Total de mensajes encontrados: +|­Comando desconocido! +|Guardando... +|Oneliners: Aparecer n de forma aleatoria en el men£ de la BBS. +|Los textos obscenos u ofensivos ser n borrados +|Teclee su 'oneliner' abajo. Máx 75 caracteres. +|Oneliner añadida +|nº A Fecha Usuario Descripci¢n +| # Descripci¢n +|Teclee n£mero a listar: +|Connectado en puerto +|Ficheros : +|Tama¤o : +|Protocolo : +|Actualizando contadores de descarga... +|­FALLO! +|Bytes +| n§ Area Activa Fichero Tam. Coste +|Si +|No +AT|(A)ctivar/desactivar, desactivar (T)odos, (ENTER) para seguir: +|N£mero de fichero, 1.. +|Marcado: +|No hay ficheros marcados. +|Replace +|Cargando BBS, espere por favor ... +|Areas de correo nuevas o borradas en +|Area Estado Tipo Descripci¢n +|Comprobar correo nuevo ACTIVADO +|Comprobar correo nuevo DESACTIVADO +|Borrar fichero: +SN|¨Est s seguro? [S/n]: +|Comprobar ficheros nuevos ACTIVADO +|Comprobar ficheros nuevos DESACTIVADO +|Editor a pantalla completa ACTIVADO +|Editor a pantalla completa DESACTIVADO +|Demasiados mensajes. S¢lo los primeros +|Pulsa (Enter) para seguir: +|Centrar +|Idioma: No puedo abrir fichero de idiomas. +|Elija su Idioma / Escolla idioma / Select language +|Elija Idioma: +|Idioma: +|El sistema va a crear tu cuenta UNIX. Se te preguntar n unos datos: +|Tu "Cuenta UNIX" ha sido creada. Puedes usarla para entrar en el 'Login'. +|Teclea un nombre de login (M ximo 8 caracteres) por ejemplo si te llamas +|'Elena Nito del Bosque ' puedes usar 'enitob', 'elenanb' o 'enbosque' +|login > +|Ese nombre de LOGIN ya existe. Elije otro... +|FATAL: No puedo abrir fichero de idioma +|El password de su Login será igual que el de la BBS. +|ERROR FATAL: No est s en el fichero de usuarios de la BBS. +| Ejecuta 'newuser' para crear un nuevo usuario +|New +|Local +|Netmail +|Echomail +|News +|E-Mail +|Del +|Ene +|Feb +|Mar +|Abr +|May +|Jun +|Jul +|Ago +|Sep +|Oct +|Nov +|Dic +|Autologout: ¨Te has dormido o es que se ha cortado? +|se empaquetar n. +|Alias (Enter si no quieres ninguno): +|Hala, Ya puedes usar la BBS +|Usuarios conectados a +|Nombre Puerto Estado Localidad +|'No molesten' DESACTIVADO +|'No molesten' ACTIVADO +|Navegando +|Descargando +|Enviando +|S. Mensajes +|Door Externa +|Charlando +|Lst. Ficheros +SN|¨Quieres descargar estos mensajes [S/N]? +|En el Banco +|Safe Door +|L. Conectados +|Desocupado +|Teclea usuario al que enviar un aviso: +|No hay usuario en +|No quiere ser molestado +|Teclea texto del aviso (Max 76 Caracteres) +|** Mensaje ** de +|Tu password ha caducado, nuevo password : +|Pulsa ENTER para seguir +|No puedes escribir, ­esta  rea es de Solo Lectura! +|!No se permite responder en esta  rea! +|Upload de correo Off-Line +|El paquete recibido no es v lido +|Comprimido con un compresor desconocido +|El compresor no est  disponible +|Paquete de correo de tipo desconocido +|Descarga de BlueWave +|Preparando paquete +|Comprimiendo con +|Descarga fallida +|Descarga completa +|Actualizando punteros de lectura +|Procesando paquete de respuestas BlueWave +|ERROR en el paquete +|Importando mensajes +|Imposible escribir en  rea +|Mensajes importados +|Procesando Configuraci¢n Off-Line +|Areas seleccionadas +|Procesando peticiones de ficheros +|Descarga de QWK +|Procesando paquete de respuestas QWK +|Descarga ASCII +SN|Crash [s/N]: +SN|Aviso: el nodo no es CM, enviar immediato [s/N]: +YN|Adjuntar fichero [s/N]: +|Fichero +|adjuntado +|El fichero no esta en +|buzon - Email entrante/saliente +|archivo - Email Archivado +|papelera - Papelera, Email borrado +|Area # +|minutos. diff --git a/lib/FAQ b/lib/FAQ new file mode 100644 index 00000000..a585c759 --- /dev/null +++ b/lib/FAQ @@ -0,0 +1,106 @@ +Frequently Asked Questions for memwatch + +Q. I'm not getting any log file! What's wrong?? + +A. Did you define MEMWATCH when compiling all files? + Did you include memwatch.h in all the files? + If you did, then...: + + Memwatch creates the file when it initializes. If you're not + getting the log file, it's because a) memwatch is not + initializing or b) it's initializing, but can't create the + file. + + Memwatch has two functions, mwInit() and mwTerm(), that + initialize and terminate memwatch, respectively. They are + nestable. You USUALLY don't need to call mwInit() and + mwTerm(), since memwatch will auto-initialize on the first + call to a memory function, and then add mwTerm() to the + atexit() list. + + You can call mwInit() and mwTerm() manually, if it's not + initializing properly or if your system doesn't support + atexit(). Call mwInit() as soon as you can, and mwTerm() at + the logical no-error ending of your program. Call mwAbort() + if the program is stopping due to an error; this will + terminate memwatch even if more than one call to mwTerm() is + outstanding. + + If you are using C++, remember that global and static C++ + objects constructors execute before main() when considering + where to put mwInit(). Also, their destructors execute after + main(). You may want to create a global object very early + with mwInit() in the constructor and mwTerm() in the + destructor. Too bad C++ does not guarantee initialization + order for global objects. + + If this didn't help, try adding a call to mwDoFlush(1) after + mwInit(). If THAT didn't help, then memwatch is unable to + create the log file. Check write permissions. + + If you can't use a log file, you can still use memwatch by + redirecting the output to a function of your choice. See the + next question. + +Q. I'd like memwatch's output to pipe to my fave debugger! How? + +A. Call mwSetOutFunc() with the addres of a "void func(int c)" + function. You should also consider doing something about + the ARI handler, see memwatch.h for more details about that. + +Q. Why isn't there any C++ support? + +A. Because C++ is for sissies! =) Just kidding. + C++ comes with overridable allocation/deallocation + built-in. You can define your own new/delete operators + for any class, and thus circumvent memwatch, or confuse + it to no end. Also, the keywords "new" and "delete" may + appear in declarations in C++, making the preprocessor + replacement approach shaky. You can do it, but it's not + very stable. + + If someone were to write a rock solid new/delete checker + for C++, there is no conflict with memwatch; use them both. + +Q. I'm getting "WILD free" errors, but the code is bug-free! + +A. If memwatch's free() recieves a pointer that wasn't allocated + by memwatch, a "WILD free" message appears. If the source of + the memory buffer is outside of memwatch (a non-standard + library function, for instance), you can use mwFree_() to + release it. mwFree_() calls free() on the pointer given if + memwatch can't recognize it, instead of blocking it. + + Another source of "WILD free" messages is that if memwatch + is terminated before all memory allocated is freed, memwatch + will have forgotten about it, and thus generate the errors. + This is commonly caused by having memwatch auto-initialize, + and then using atexit() to clean up. When auto-initializing, + memwatch registers mwTerm() with atexit(), but if mwTerm() + runs before all memory is freed, then you will get "unfreed" + and "WILD free" messages when your own atexit()-registered + cleanup code runs, and frees the memory. + +Q. I'm getting "unfreed" errors, but the code is bug-free! + +A. You can get erroneous "unfreed" messages if memwatch + terminates before all memory has been freed. Try using + mwInit() and mwTerm() instead of auto-initialization. + + If you _are_ using mwInit() and mwTerm(), it may be that + some code in your program executes before mwInit() or + after mwTerm(). Make sure that mwInit() is the first thing + executed, and mwTerm() the last. + +Q. When compiling memwatch I get these 'might get clobbered' + errors, and something about a longjmp() inside memwatch. + +A. You are using a non-Win32 platform, and most likely using + gcc or egcs, and is probably running with the highest + possible warning levels. This is a Good Thing. + + Unfortunately, it seems some compilers get a bit too + paranoid at those levels. There is nothing wrong with + memwatch's code. Nothing that matters will get + clobbered, if the compiler adheres to the ANSI C + standard. Just ignore the warnings. diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..cff62867 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,35 @@ +## Makefile.am for mbsebbs ./lib + +SUBDIRS = . + +EXTRA_DIST = README ftscprod.006 mkprod.awk FAQ README.memwatch USING test.c memwatch.c.org + +CONFIG_CLEAN_FILES = ftscprod.c + +noinst_HEADERS = libs.h structs.h records.h mbse.h ansi.h bluewave.h + +noinst_LIBRARIES = libclcomm.a libcommon.a libdbase.a libmsgbase.a libmbinet.a libmemwatch.a + +libclcomm_a_SOURCES = clcomm.c client.c crc.c semafore.c signame.c clcomm.h + +libcommon_a_SOURCES = ftscprod.c attach.c charconv_utf.c falists.c hdr.c msgflags.c parsedate.c rfcmsg.c unpacker.c \ +batchrd.c charset.c ftn.c nodelist.c pktname.c \ +charconv.c dostran.c ftnmsg.c mbfile.c nodelock.c rawio.c strcasestr.c \ +charconv_hz.c execute.c expipe.c getheader.c mime.c noderecord.c rfcaddr.c strutil.c \ +charconv_jp.c faddr.c gmtoffset.c packet.c rfcdate.c term.c common.h + +libdbase_a_SOURCES = dbcfg.c dbdupe.c dbftn.c dbmsgs.c dbnode.c dbtic.c dbuser.c \ +dbcfg.h dbdupe.h dbftn.h dbmsgs.h dbnode.h dbtic.h dbuser.h + +libmsgbase_a_SOURCES = jam.h jammsg.c jammsg.h jamsys.h msg.c msg.h msgtext.c msgtext.h + +libmbinet_a_SOURCES = mbinet.h nntp.c pop3.c smtp.c + +libmemwatch_a_SOURCES = memwatch.c memwatch.h + +BUILT_SOURCES = ftscprod.c + +ftscprod.c: ftscprod.??? + @AWK@ -F, -f mkprod.awk ftscprod.??? >ftscprod.c + + diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 00000000..4484a319 --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,504 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = README ftscprod.006 mkprod.awk FAQ README.memwatch USING test.c memwatch.c.org + +CONFIG_CLEAN_FILES = ftscprod.c + +noinst_HEADERS = libs.h structs.h records.h mbse.h ansi.h bluewave.h + +noinst_LIBRARIES = libclcomm.a libcommon.a libdbase.a libmsgbase.a libmbinet.a libmemwatch.a + +libclcomm_a_SOURCES = clcomm.c client.c crc.c semafore.c signame.c clcomm.h + +libcommon_a_SOURCES = ftscprod.c attach.c charconv_utf.c falists.c hdr.c msgflags.c parsedate.c rfcmsg.c unpacker.c batchrd.c charset.c ftn.c nodelist.c pktname.c charconv.c dostran.c ftnmsg.c mbfile.c nodelock.c rawio.c strcasestr.c charconv_hz.c execute.c expipe.c getheader.c mime.c noderecord.c rfcaddr.c strutil.c charconv_jp.c faddr.c gmtoffset.c packet.c rfcdate.c term.c common.h + + +libdbase_a_SOURCES = dbcfg.c dbdupe.c dbftn.c dbmsgs.c dbnode.c dbtic.c dbuser.c dbcfg.h dbdupe.h dbftn.h dbmsgs.h dbnode.h dbtic.h dbuser.h + + +libmsgbase_a_SOURCES = jam.h jammsg.c jammsg.h jamsys.h msg.c msg.h msgtext.c msgtext.h + +libmbinet_a_SOURCES = mbinet.h nntp.c pop3.c smtp.c + +libmemwatch_a_SOURCES = memwatch.c memwatch.h + +BUILT_SOURCES = ftscprod.c +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libclcomm_a_LIBADD = +libclcomm_a_OBJECTS = clcomm.o client.o crc.o semafore.o signame.o +libcommon_a_LIBADD = +libcommon_a_OBJECTS = ftscprod.o attach.o charconv_utf.o falists.o \ +hdr.o msgflags.o parsedate.o rfcmsg.o unpacker.o batchrd.o charset.o \ +ftn.o nodelist.o pktname.o charconv.o dostran.o ftnmsg.o mbfile.o \ +nodelock.o rawio.o strcasestr.o charconv_hz.o execute.o expipe.o \ +getheader.o mime.o noderecord.o rfcaddr.o strutil.o charconv_jp.o \ +faddr.o gmtoffset.o packet.o rfcdate.o term.o +libdbase_a_LIBADD = +libdbase_a_OBJECTS = dbcfg.o dbdupe.o dbftn.o dbmsgs.o dbnode.o dbtic.o \ +dbuser.o +libmsgbase_a_LIBADD = +libmsgbase_a_OBJECTS = jammsg.o msg.o msgtext.o +libmbinet_a_LIBADD = +libmbinet_a_OBJECTS = nntp.o pop3.o smtp.o +libmemwatch_a_LIBADD = +libmemwatch_a_OBJECTS = memwatch.o +AR = ar +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(libclcomm_a_SOURCES) $(libcommon_a_SOURCES) $(libdbase_a_SOURCES) $(libmsgbase_a_SOURCES) $(libmbinet_a_SOURCES) $(libmemwatch_a_SOURCES) +OBJECTS = $(libclcomm_a_OBJECTS) $(libcommon_a_OBJECTS) $(libdbase_a_OBJECTS) $(libmsgbase_a_OBJECTS) $(libmbinet_a_OBJECTS) $(libmemwatch_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libclcomm.a: $(libclcomm_a_OBJECTS) $(libclcomm_a_DEPENDENCIES) + -rm -f libclcomm.a + $(AR) cru libclcomm.a $(libclcomm_a_OBJECTS) $(libclcomm_a_LIBADD) + $(RANLIB) libclcomm.a + +libcommon.a: $(libcommon_a_OBJECTS) $(libcommon_a_DEPENDENCIES) + -rm -f libcommon.a + $(AR) cru libcommon.a $(libcommon_a_OBJECTS) $(libcommon_a_LIBADD) + $(RANLIB) libcommon.a + +libdbase.a: $(libdbase_a_OBJECTS) $(libdbase_a_DEPENDENCIES) + -rm -f libdbase.a + $(AR) cru libdbase.a $(libdbase_a_OBJECTS) $(libdbase_a_LIBADD) + $(RANLIB) libdbase.a + +libmsgbase.a: $(libmsgbase_a_OBJECTS) $(libmsgbase_a_DEPENDENCIES) + -rm -f libmsgbase.a + $(AR) cru libmsgbase.a $(libmsgbase_a_OBJECTS) $(libmsgbase_a_LIBADD) + $(RANLIB) libmsgbase.a + +libmbinet.a: $(libmbinet_a_OBJECTS) $(libmbinet_a_DEPENDENCIES) + -rm -f libmbinet.a + $(AR) cru libmbinet.a $(libmbinet_a_OBJECTS) $(libmbinet_a_LIBADD) + $(RANLIB) libmbinet.a + +libmemwatch.a: $(libmemwatch_a_OBJECTS) $(libmemwatch_a_DEPENDENCIES) + -rm -f libmemwatch.a + $(AR) cru libmemwatch.a $(libmemwatch_a_OBJECTS) $(libmemwatch_a_LIBADD) + $(RANLIB) libmemwatch.a + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lib + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +attach.o: attach.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +batchrd.o: batchrd.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +charconv.o: charconv.c libs.h ../config.h memwatch.h structs.h records.h \ + common.h clcomm.h +charconv_hz.o: charconv_hz.c libs.h ../config.h memwatch.h structs.h \ + common.h clcomm.h +charconv_jp.o: charconv_jp.c libs.h ../config.h memwatch.h structs.h \ + common.h +charconv_utf.o: charconv_utf.c libs.h ../config.h memwatch.h structs.h \ + common.h +charset.o: charset.c libs.h ../config.h memwatch.h structs.h common.h \ + clcomm.h +clcomm.o: clcomm.c libs.h ../config.h memwatch.h clcomm.h +client.o: client.c libs.h ../config.h memwatch.h clcomm.h +crc.o: crc.c libs.h ../config.h memwatch.h clcomm.h +dbcfg.o: dbcfg.c libs.h ../config.h memwatch.h mbse.h structs.h \ + records.h dbcfg.h +dbdupe.o: dbdupe.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + dbdupe.h +dbftn.o: dbftn.c libs.h ../config.h memwatch.h structs.h records.h \ + dbcfg.h dbftn.h +dbmsgs.o: dbmsgs.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h dbcfg.h dbmsgs.h +dbnode.o: dbnode.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h dbcfg.h dbnode.h +dbtic.o: dbtic.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h dbcfg.h dbtic.h +dbuser.o: dbuser.c libs.h ../config.h memwatch.h structs.h records.h \ + dbcfg.h dbuser.h +dostran.o: dostran.c libs.h ../config.h memwatch.h structs.h records.h \ + common.h +execute.o: execute.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +expipe.o: expipe.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +faddr.o: faddr.c libs.h ../config.h memwatch.h structs.h common.h +falists.o: falists.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +ftn.o: ftn.c libs.h ../config.h memwatch.h structs.h records.h clcomm.h \ + dbftn.h common.h +ftnmsg.o: ftnmsg.c libs.h ../config.h memwatch.h structs.h common.h \ + clcomm.h +ftscprod.o: ftscprod.c libs.h ../config.h memwatch.h structs.h common.h +getheader.o: getheader.c libs.h ../config.h memwatch.h structs.h \ + records.h clcomm.h common.h +gmtoffset.o: gmtoffset.c libs.h ../config.h memwatch.h structs.h \ + common.h +hdr.o: hdr.c libs.h ../config.h memwatch.h structs.h common.h +jammsg.o: jammsg.c libs.h ../config.h memwatch.h clcomm.h msgtext.h \ + msg.h jam.h jamsys.h jammsg.h +mbfile.o: mbfile.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +memwatch.o: memwatch.c ../config.h libs.h memwatch.h memwatch.h +mime.o: mime.c libs.h ../config.h memwatch.h structs.h clcomm.h common.h +msg.o: msg.c libs.h ../config.h memwatch.h msgtext.h msg.h jammsg.h +msgflags.o: msgflags.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +msgtext.o: msgtext.c libs.h ../config.h memwatch.h msgtext.h msg.h +nntp.o: nntp.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h mbinet.h +nodelist.o: nodelist.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +nodelock.o: nodelock.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +noderecord.o: noderecord.c libs.h ../config.h memwatch.h structs.h \ + records.h dbnode.h common.h +packet.o: packet.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h dbnode.h +parsedate.o: parsedate.c libs.h ../config.h memwatch.h structs.h \ + common.h +pktname.o: pktname.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +pop3.o: pop3.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h mbinet.h +rawio.o: rawio.c libs.h ../config.h memwatch.h structs.h common.h +rfcaddr.o: rfcaddr.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +rfcdate.o: rfcdate.c libs.h ../config.h memwatch.h structs.h common.h \ + clcomm.h +rfcmsg.o: rfcmsg.c libs.h ../config.h memwatch.h structs.h records.h \ + common.h clcomm.h +semafore.o: semafore.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +signame.o: signame.c libs.h ../config.h memwatch.h clcomm.h +smtp.o: smtp.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h mbinet.h +strcasestr.o: strcasestr.c libs.h ../config.h memwatch.h +strutil.o: strutil.c libs.h ../config.h memwatch.h structs.h common.h +term.o: term.c libs.h ../config.h memwatch.h structs.h ansi.h records.h \ + common.h +unpacker.o: unpacker.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(LIBRARIES) $(HEADERS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs-am \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +ftscprod.c: ftscprod.??? + @AWK@ -F, -f mkprod.awk ftscprod.??? >ftscprod.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/README b/lib/README new file mode 100644 index 00000000..f5a3b123 --- /dev/null +++ b/lib/README @@ -0,0 +1,35 @@ + Database structures. + + +Most databases have a structure with a header record. The header record +is at the beginning of the datafile and contains information about the +size of the header record and size of the database records. When a data +file is opened for reading the first thing to read the header record. +The field recsize contains the size of the datarecords and the field +hdrsize the offset to the first datarecord in the file. + +If in the structure the size of the datarecords changes (grows), we can +allways read the old format in the correct way. + +When a datafile is changed the datafile has to be rewritten completly. +Of course the new format is used then, and the new size must be stored in +the header. + +The advantage of this technique is that updates can be performed automatic. +There is no need for free space for future use in the datarecords, the files +are thus smaller. + + +One other important thing, with some DOS based bbs'es, mail/tic processors +are using index files together with the data files to speed up the search in +the databases. Also some of them use internal memory cache for the data records. +I choose not to do this for two reasons, Linux like other Unices handles +file I/O very fast and when your system is not low on memory the kernel will +buffer all disk I/O in memory. Also Linux disks are very low fragmented due to +the design of the ext2fs. Whith all this in mind, using index files is only +extra overhead. +However, because of this you should not put the data files on a msdos +dos partition or on a nfs server. + +The only exeption that uses index files are the nodelists. + diff --git a/lib/README.memwatch b/lib/README.memwatch new file mode 100644 index 00000000..a15ca538 --- /dev/null +++ b/lib/README.memwatch @@ -0,0 +1,98 @@ +README for MEMWATCH 2.62 + + This file should be enough to get you started, and should be + enough for small projects. For more info, see the files USING + and the FAQ. If this is not enough, see memwatch.h, which is + well documented. + + If you choose to use memwatch to validate your projects, I + would love to hear about it. Please drop me a line at + johan@link-data.com about the project itself, the hardware, + operating system, compiler and any URL(s) you feel is + appropriate. I will then post it at: + + http://www.link-data.com/memwatchusers.html + +***** To run the test program: + + Look at the source code for test.c first. It does some really + nasty things, and I want you to be aware of that. If memwatch + can't capture SIGSEGV (General Protection Fault for Windoze), + your program will dump core (crash for Windoze). + + Once you've done that, you can build the test program. + + Linux and other *nixes with gcc: + + gcc -o test -DMEMWATCH -DMEMWATCH_STDIO test.c memwatch.c + + Windows 95, Windows NT with MS Visual C++: + + cl -DMEMWATCH -DMEMWATCH_STDIO test.c memwatch.c + + Then simply run the test program. + + ./test + + +***** Quick-start instructions: + + 1. Make sure that memwatch.h is included in all of the + source code files. If you have an include file that + all of the source code uses, you might be able to include + memwatch.h from there. + + 2. Recompile the program with MEMWATCH defined. See your + compiler's documentation if you don't know how to do this. + The usual switch looks like "-DMEMWATCH". To have MEMWATCH + use stderr for some output (like, "Abort, Retry, Ignore?"), + please also define MW_STDIO (or MEMWATCH_STDIO, same thing). + + 3. Run the program and examine the output in the + log file "memwatch.log". If you didn't get a log file, + you probably didn't do step 1 and 2 correctly, or your + program crashed before memwatch flushed the file buffer. + To have memwatch _always_ flush the buffer, add a call + to "mwDoFlush(1)" at the top of your main function. + + 4. There is no fourth step... but remember that there + are limits to what memwatch can do, and that you need + to be aware of them: + +***** Limits to memwatch: + + Memwatch cannot catch all wild pointer writes. It can catch + those it could make itself due to your program trashing + memwatch's internal data structures. It can catch, sort of, + wild writes into No Mans Land buffers (see the header file for + more info). Anything else and you're going to get core dumped, + or data corruption if you're lucky. + + There are other limits of course, but that one is the most + serious one, and the one that you're likely to be suffering + from. + +***** Can use memwatch with XXXXX? + + Probably the answer is yes. It's been tested with several + different platforms and compilers. It may not work on yours + though... but there's only one way to find out. + +***** Need more assistance? + + I don't want e-mail on "how to program in C", or "I've got a + bug, help me". I _do_ want you to send email to me if you + find a bug in memwatch, or if it won't compile cleanly on your + system (assuming it's an ANSI-C compiler of course). + + If you need help with using memwatch, read the header file. + If, after reading the header file, you still can't resolve the + problem, please mail me with the details. + + I can be reached at "johan@link-data.com". + + The latest version of memwatch should be found at + "http://www.link-data.com/". + + Johan Lindh + diff --git a/lib/USING b/lib/USING new file mode 100644 index 00000000..571fde7b --- /dev/null +++ b/lib/USING @@ -0,0 +1,169 @@ +Using memwatch +============== + +What is it? + + Memwatch is primarily a memory leak detector for C. Besides + detecting leaks, it can do a bunch of other stuff, but lets + stay to the basics. If you _really_ want to know all the + gory details, you should check out the header file, + memwatch.h, and the source code. It's actually got some + comments! (Whoa, what a concept!) + +How do I get the latest version? + + http://www.link-data.com/sourcecode.html + ftp://ftp.link-data.com/pub/memwatch/ + +How does it work? + + Using the C preprocessor, memwatch replaces all your + programs calls to ANSI C memory allocation functions with + calls to it's own functions, which keeps a record of all + allocations. + + Memwatch is very unobtrusive; unless the define MEMWATCH is + defined, memwatch removes all traces of itself from the + code (using the preprocessor). + + Memwatch normally writes it's data to the file + memwatch.log, but this can be overridden; see the section + on I/O, later. + +Initialization and cleanup + + In order to do it's work in a timely fashion, memwatch + needs to do some startup and cleanup work. mwInit() + initializes memwatch and mwTerm() terminates it. Memwatch + can auto-initialize, and will do so if you don't call + mwInit() yourself. If this is the case, memwatch will use + atexit() to register mwTerm() to the atexit-queue. + + The auto-init technique has a caveat; if you are using + atexit() yourself to do cleanup work, memwatch may + terminate before your program is done. To be on the safe + side, use mwInit() and mwTerm(). + + mwInit() and mwTerm() is nestable, so you can call mwInit() + several times, requiring mwTerm() to be called an equal + number of times to terminate memwatch. + + In case of the program aborting in a controlled way, you + may want to call mwAbort() instead of mwTerm(). mwAbort() + will terminate memwatch even if there are outstanding calls + to mwTerm(). + +I/O operations + + During normal operations, memwatch creates a file named + memwatch.log. Sometimes, memwatch.log can't be created; + then memwatch tries to create files name memwatNN.log, + where NN is between 01 and 99. If that fails, no log will + be produced. + + If you can't use a file log, or don't want to, no worry. + Just call mwSetOutFunc() with the address of a "void + func(int c)" function, and all output will be directed + there, character by character. + + Memwatch also has an Abort/Retry/Ignore handler that is + used when an ASSERT or VERIFY fails. The default handler + does no I/O, but automatically aborts the program. You can + use any handler you want; just send the address of a "int + func(const char*)" to mwSetAriFunc(). For more details on + that, see memwatch.h. + +TRACE/ASSERT/VERIFY macros + + Memwatch defines (if not already defined) the macros TRACE, + ASSERT and VERIFY. If you are already using macros with + these names, memwatch 2.61 and later will not override + them. Memwatch 2.61 and later will also always define the + macros mwTRACE, mwASSERT and mwVERIFY, so you can use these + to make sure you're talking to memwatch. Versions previous + to 2.61 will OVERRIDE TRACE, ASSERT and VERIFY. + + To make sure that existing TRACE, ASSERT and VERIFY macros + are preserved, you can define MW_NOTRACE, MW_NOASSERT and + MW_NOVERIFY. All versions of memwatch will abide by these. + +Stress-testing the application + + You can simulate low-memory conditions using mwLimit(). + mwLimit() takes the maximum number of bytes to be + allocated; when the limit is hit, allocation requests will + fail, and a "limit" message will be logged. + + If you hit a real low-memory situation, memwatch logs that + too. Memwatch itself has some reserve memory tucked away so + it should continue running even in the worst conditions. + +Hunting down wild writes and other Nasty Things + + Wild writes are usually caused by using pointers that arent + initialized, or that were initialized, but then the memory + they points to is moved or freed. The best way to avoid + these kind of problems is to ALWAYS initialize pointers to + NULL, and after freeing a memory buffer, setting all + pointers that pointed to it to NULL. + + To aid in tracking down uninitialized pointers memwatch + zaps all memory with certain values. Recently allocated + memory (unless calloc'd, of course), contains 0xFE. + Recently freed memory contains 0xFD. So if your program + crashes when using memwatch and not without memwatch, it's + most likely because you are not initializing your allocated + buffers, or using the buffers after they've been freed. + + In the event that a wild pointer should damage memwatch's + internal data structures, memwatch employs checksums, + multiple copies of some values, and can also repair it's + own data structures. + + If you are a paranoid person, and as programmer you should + be, you can use memwatch's mwIsReadAddr() and + mwIsSafeAddr() functions to check the accessibility of + memory. These are implemented for both ANSI C systems and + Win32 systems. Just put an mwASSERT() around the check and + forget about it. + +Can I help? + + Well, sure. For instance, I like memwatch to compile + without any warnings or errors. If you are using an ANSI C + compliant compiler, and are getting warnings or errors, + please mail me the details and instructions on how to fix + them, if you can. + + Another thing you can do if you decide to use memwatch is + to mail me the name of the project(s) (and URL, if any), + hardware and operating system, compiler and what user + (organization). I will then post this info on the list of + memwatch users. + (http://www.link-data.com/memwatchusers.html) + +Top five problems using memwatch + + 5. Passed a non-memwatch allocated pointer to memwatch's + free(). Symtom: Causes an erroneous "WILD free" log + entry to appear. Cure: Either include memwatch.h for + the file that allocates, or use mwFree_() to free it. + + 4. Relied on auto-initialization when using atexit(). + Symptom: Causes incorrect "unfreed" and "WILD free" + messages. Cure: Use mwInit() and mwTerm(). + + 3. Forgot to include memwatch.h in all files. Symptom: + Tends to generate "WILD free" and "unfreed" messages. + Cure: Make sure to include memwatch.h! + + 2. No write permissions in currect directory. Symptom: + Seems like memwatch 'just aint working'. Cure: Use + mwSetOutFunc() to redirect output. + + ...and the number one problem is... + + 1. Didn't define MEMWATCH when compiling. Symptom: + Memwatch dutifully disables itself. Cure: Try adding + -DMEMWATCH to the command line. + diff --git a/lib/ansi.h b/lib/ansi.h new file mode 100644 index 00000000..f52e90fc --- /dev/null +++ b/lib/ansi.h @@ -0,0 +1,56 @@ +/***************************************************************************** + * + * File ..................: mbse.h + * Purpose ...............: ANSI Screen definitions + * Last modification date : 10-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#ifndef _ANSI_H +#define _ANSI_H + + +#define ANSI_RED "\x1B[31;1m" +#define ANSI_YELLOW "\x1B[33;1m" +#define ANSI_BLUE "\x1B[34;1m" +#define ANSI_GREEN "\x1B[32;1m" +#define ANSI_WHITE "\x1B[37;1m" +#define ANSI_CYAN "\x1B[36;1m" +#define ANSI_MAGENTA "\x1B[35m" + +#define ANSI_HOME "\x1B[H" +#define ANSI_UP "\x1B[A" +#define ANSI_DOWN "\x1B[B" +#define ANSI_RIGHT "\x1B[C" +#define ANSI_LEFT "\x1B[D" + +#define ANSI_BOLD "\x1B[1m" +#define ANSI_NORMAL "\x1B[0m" +#define ANSI_CLEAR "\x1B[2J" +#define ANSI_CLREOL "\x1B[K" + + +#endif diff --git a/lib/attach.c b/lib/attach.c new file mode 100644 index 00000000..29655218 --- /dev/null +++ b/lib/attach.c @@ -0,0 +1,113 @@ +/***************************************************************************** + * + * File ..................: common/attach.c + * Purpose ...............: Attach files to outbound + * Last modification date : 25-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + + +int attach(faddr noden, char *ofile, int mode, char flavor) +{ + FILE *fp; + char *flofile; + + if (ofile == NULL) + return FALSE; + + flofile = calloc(PATH_MAX, sizeof(char)); + sprintf(flofile, "%s", floname(&noden, flavor)); + + /* + * Check if outbound directory exists and + * create if it doesn't exist. + */ + mkdirs(ofile); + + /* + * Attach file to .flo + * + * Not that mbcico when connected to a node opens the file "r+", + * locks it with fcntl(F_SETLK), F_RDLCK, whence=0, start=0L, len=0L. + * It seems that this lock is released after the files in the .flo + * files are send. I don't know what will happen if we add entries + * to the .flo files, this must be tested! + */ + if ((fp = fopen(flofile, "a+")) == NULL) { + WriteError("$Can't open %s", flofile); + WriteError("May be locked by mbcico"); + free(flofile); + return FALSE; + } + + switch (mode) { + case LEAVE: + if (strlen(CFG.dospath)) { + if (CFG.leavecase) + fprintf(fp, "%s\r\n", Unix2Dos(ofile)); + else + fprintf(fp, "%s\r\n", tu(Unix2Dos(ofile))); + } else { + fprintf(fp, "%s\r\n", ofile); + } + break; + case KFS: + if (strlen(CFG.dospath)) { + if (CFG.leavecase) + fprintf(fp, "^%s\r\n", Unix2Dos(ofile)); + else + fprintf(fp, "^%s\r\n", tu(Unix2Dos(ofile))); + } else { + fprintf(fp, "^%s\r\n", ofile); + } + break; + + case TFS: + if (strlen(CFG.dospath)) { + if (CFG.leavecase) + fprintf(fp, "#%s\r\n", Unix2Dos(ofile)); + else + fprintf(fp, "#%s\r\n", tu(Unix2Dos(ofile))); + } else { + fprintf(fp, "#%s\r\n", ofile); + } + break; + } + + fclose(fp); + free(flofile); + return TRUE; +} + + + diff --git a/lib/batchrd.c b/lib/batchrd.c new file mode 100644 index 00000000..6b2c8b33 --- /dev/null +++ b/lib/batchrd.c @@ -0,0 +1,91 @@ +/***************************************************************************** + * + * File ..................: common/batchrd.c + * Purpose ...............: Batch reading + * Last modification date : 28-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +static long counter = 0L; +static int batchmode = -1; +int usetmp = 0; + +char *bgets(char *buf, int count, FILE *fp) +{ + if (usetmp) { + return fgets(buf,count,fp); + } + + if ((batchmode == 1) && (counter > 0L) && (counter < (long)(count-1))) + count=(int)(counter+1L); + if (fgets(buf,count,fp) == NULL) + return NULL; + + switch (batchmode) { + case -1: if (!strncmp(buf,"#! rnews ",9) || !strncmp(buf,"#!rnews ",8)) { + batchmode=1; + sscanf(buf+8,"%ld",&counter); + Syslog('m', "first chunk of input batch: %ld",counter); + if (counter < (long)(count-1)) + count=(int)(counter+1L); + if (fgets(buf,count,fp) == NULL) + return NULL; + else { + counter -= strlen(buf); + return(buf); + } + } else { + batchmode=0; + return buf; + } + + case 0: return buf; + + case 1: if (counter <= 0L) { + while (strncmp(buf,"#! rnews ",9) && strncmp(buf,"#!rnews ",8)) { + Syslog('+', "batch out of sync: %s",buf); + if (fgets(buf,count,fp) == NULL) + return NULL; + } + sscanf(buf+8,"%ld",&counter); + Syslog('m', "next chunk of input batch: %ld",counter); + return NULL; + } else { + counter -= (long)strlen(buf); + Syslog('m', "bread \"%s\", %ld left of this chunk", buf,counter); + return buf; + } + } + return buf; +} + + diff --git a/lib/bluewave.h b/lib/bluewave.h new file mode 100644 index 00000000..dc3d2027 --- /dev/null +++ b/lib/bluewave.h @@ -0,0 +1,1162 @@ +/*****************************************************************************/ +/* */ +/* The Blue Wave Offline Mail System Packet Structures */ +/* Copyright 1990-1995 by Cutting Edge Computing. All rights reserved. */ +/* Created by George Hatchew */ +/* */ +/* Version 3 - November 30, 1995 */ +/* */ +/* --------------------------------------------------------- */ +/* DISTRIBUTION OF THIS FILE IS LIMITED BY THE TERMS */ +/* SPECIFIED IN THE BLUE WAVE STRUCTURE DOCUMENTATION! */ +/* --------------------------------------------------------- */ +/* */ +/* These data structures should be usable with any C compiler that */ +/* supports the 1989 ANSI/ISO C language standard. They are NOT */ +/* guaranteed to be usable with older compilers, which largely relied */ +/* on the definition of the language as specified in Kernighan & Ritchie's */ +/* _The C Programming Language (1st Edition)_. */ +/* */ +/*****************************************************************************/ + +#ifndef __BLUEWAVE_H /* An extra safeguard to prevent this header from */ +#define __BLUEWAVE_H /* being included twice in the same source file */ + + +#define PACKET_LEVEL 3 /* The current mail packet revision level, */ + /* used in the "ver" field of the *.INF */ + /* file header. */ + + +/* +** This header defines the data structures for the following files in the +** official Blue Wave offline mail specification: +** +** Door: *.INF BBS and message area information +** *.MIX Quick index to *.FTI records +** *.FTI Information for all packet messages +** *.DAT Packet message text +** +** Reader: *.NET NetMail reply message information +** *.UPI Information for all other reply messages +** *.UPL Reply message information +** (alternative to *.NET and *.UPI) +** *.REQ List of files to download from BBS +** *.PDQ Offline door configuration information +** (packet version 2 and earlier) +** *.OLC Offline door configuration information +** (packet version 3 and later) +** +** Misc: *.MSG Fido-style message header +** (used *only* in the *.NET structure) +** *.XTI Extended message packet information +** (not an official part of the Blue Wave +** packet specification; is used by the Blue +** Wave reader only) +** +** The door files (plus individual files for BBS bulletins) comprise a Blue +** Wave message packet, and the reader files (plus individual files for each +** message) comprise a Blue Wave reply packet. +** +** In order to cover ALL BASES, and to be able to say that you were warned, +** *ALL* unused fields should be set to ASCII NUL (0). Any future +** implementation of reserved fields will rely on the premise that the field +** will be 0 if not implemented! The same warning follows for BITMAPPED +** fields. If a bit is not implemented or is not used, TURN IT OFF (0). +** (Clearing an entire structure can be easily accomplished via the memset() +** function. Example: "memset(&ftirec, 0, sizeof(FTI_REC))".) +*/ + + +/*****************************************************************************/ +/* >>>>>>>>>>>>>>>>>>>>>>> DATA TYPE DEFINITIONS <<<<<<<<<<<<<<<<<<<<<<<<< */ +/*****************************************************************************/ + + +/* +** The data type definitions below help make these structures a little more +** universal between environments. The 8-bit, 16-bit, and 32-bit data types +** defined below can be used as-is with virtually all MS-DOS and OS/2 C/C++ +** compilers, but can be changed if necessary should your compiler define +** data types in a different fashion. (Note that the tCHAR and tINT types +** are currently not used; they are included simply for completeness.) +** +** If you are programming for a system that employs a CPU which stores multi- +** byte integers in a manner other than in Intel format (LSB-MSB, or "little +** endian"), simply #define BIG_ENDIAN before #including this header. As +** shown below, this will define the data types as arrays of bytes; the +** drawback is that *YOU* will have to write functions to convert the data, +** since the Blue Wave packet specification requires the data to be in Intel- +** style little-endian format. +** +** IMPORTANT NOTE ABOUT COMPILERS AND STRUCTURES: +** All structures *must* be "packed" (i.e., the compiler MUST NOT insert +** padding bytes between structure elements in order to force elements onto +** word boundaries). The Blue Wave products expect them to be packed; if +** they aren't, you're bound to get some *very* interesting results. +*/ + +//#ifdef BIG_ENDIAN + +//typedef signed char tCHAR; /* 8 bit signed values */ +//typedef unsigned char tBYTE; /* 8 bit unsigned values */ +//typedef unsigned char tINT[2]; /* little-endian 16 bit signed */ +//typedef unsigned char tWORD[2]; /* little-endian 16 bit unsigned */ +//typedef unsigned char tLONG[4]; /* little-endian 32 bit signed */ +//typedef unsigned char tDWORD[4]; /* little-endian 32 bit unsigned */ + +//#else + +typedef signed char tCHAR; /* 8 bit signed values */ +typedef unsigned char tBYTE; /* 8 bit unsigned values */ +typedef signed short tINT; /* 16 bit signed values */ +typedef unsigned short tWORD; /* 16 bit unsigned values */ +typedef signed long tLONG; /* 32 bit signed values */ +typedef unsigned long tDWORD; /* 32 bit unsigned values */ + +//#endif + + +/*****************************************************************************/ +/* >>>>>>>>>>>>>>>>>>>>> DOOR DATA FILE STRUCTURES <<<<<<<<<<<<<<<<<<<<<<< */ +/*****************************************************************************/ + + +/* +** Name of file: *.INF +** +** Description: The *.INF file is the source of information for just about +** everything from the host BBS, as well as definitions for +** all of the message areas that are available to the user +** and their status (Local, EchoMail, NetMail, Read Only, +** etc.). +** +** File format: INF_HEADER { only included one time! } +** INF_AREA_INFO { repeated for as many msg bases } +** INF_AREA_INFO { as are available to the user } +** ... +*/ + +/* Bit-masks for INF_HEADER.UFLAGS field */ + +#define INF_HOTKEYS 0x0001 /* User uses "hotkeys" in door prompts */ +#define INF_XPERT 0x0002 /* Short menus displayed in door */ +#define INF_RES1 0x0004 /* RESERVED -- DO NOT USE! */ +#define INF_GRAPHICS 0x0008 /* Enable ANSI control sequences in door */ +#define INF_NOT_MY_MAIL 0x0010 /* Do not bundle mail from user */ +#define INF_EXT_INFO 0x0020 /* Download extended info with messages */ + /* (* VERSION 3 AND LATER ONLY *) */ +#define INF_NUMERIC_EXT 0x0040 /* Use numeric extensions on packets */ + /* (* VERSION 3 AND LATER ONLY *) */ + +/* Bit-masks for INF_HEADER.NETMAIL_FLAGS field */ + +#define INF_CAN_CRASH 0x0002 /* Allow Crash status */ +#define INF_CAN_ATTACH 0x0010 /* Allow File Attach messages */ +#define INF_CAN_KSENT 0x0080 /* Allow Kill/Sent status */ +#define INF_CAN_HOLD 0x0200 /* Allow Hold status */ +#define INF_CAN_IMM 0x0400 /* Allow Immediate status */ +#define INF_CAN_FREQ 0x0800 /* Allow File Request messages */ +#define INF_CAN_DIRECT 0x1000 /* Allow Direct status */ + +/* Bit-masks for INF_HEADER.CTRL_FLAGS field */ + +#define INF_NO_CONFIG 0x0001 /* Do not allow offline configuration */ +#define INF_NO_FREQ 0x0002 /* Do not allow file requesting */ + +/* Values for INF_HEADER.FILE_LIST_TYPE field */ + +#define INF_FLIST_NONE 0 /* Door does not generate a list file */ +#define INF_FLIST_TEXT 1 /* Door generates plain text list file */ +#define INF_FLIST_ANSI 2 /* Door generates ANSI list file */ + +typedef struct /* INF_HEADER */ +{ + tBYTE ver; /* Packet version type (currently 2) */ + tBYTE readerfiles[5][13]; /* Files to be displayed by reader */ + tBYTE regnum[9]; /* User's registration number */ + tBYTE mashtype; /* Currently unused (door fills with 0) */ + /* Reserved for Blue Wave reader to store */ + /* the compression type the packet uses. */ + tBYTE loginname[43]; /* Name user types at BBS login */ + tBYTE aliasname[43]; /* User's "other" name */ + tBYTE password[21]; /* Password */ + /* All bytes should be the actually ASCII */ + /* value plus 10. Lame security, yes, */ + /* but it does prevent "TYPE *.INF" from */ + /* showing the password. */ + tBYTE passtype; /* Password type */ + /* 0=none 1=door 2=reader 3=both */ + tWORD zone; /* Main network address of host BBS */ + tWORD net; /* (zone:net/node.point) */ + tWORD node; + tWORD point; + tBYTE sysop[41]; /* Name of SysOp of host BBS */ + tWORD ctrl_flags; /* Flags to control reader capabilities */ + /* (* VERSION 3 AND LATER ONLY *) */ + tBYTE systemname[65]; /* Name of host BBS */ + tBYTE maxfreqs; /* Max number of file requests allowed */ + tWORD is_QWK; /* Whether *.INF belongs to a QWK packet */ + tBYTE obsolete2[4]; /* OBSOLETE -- DO NOT USE! */ + tWORD uflags; /* Bit-mapped door options/toggles */ + tBYTE keywords[10][21]; /* User's entire set of door keywords */ + tBYTE filters[10][21]; /* User's entire set of door filters */ + tBYTE macros[3][80]; /* User's door bundling command macros */ + tWORD netmail_flags; /* Bit-mapped NetMail options */ + tWORD credits; /* NetMail credits */ + tWORD debits; /* NetMail debits */ + tBYTE can_forward; /* 0=Message forwarding not allowed */ + tWORD inf_header_len; /* Size of INF_HEADER structure */ + tWORD inf_areainfo_len; /* Size of INF_AREA_INFO structure */ + tWORD mix_structlen; /* Size of MIX_REC structure */ + tWORD fti_structlen; /* Size of FTI_REC structure */ + tBYTE uses_upl_file; /* If this field is not zero, the door that */ + /* created this packet can receive reply */ + /* packets in the new *.UPL file format. */ + /* Otherwise, the old *.UPI and *.NET */ + /* files must be used. */ + tBYTE from_to_len; /* The maximum length of the FROM: and TO: */ + /* fields that the host BBS can support. */ + /* If this value is 0 or is greater than */ + /* 35, then 35 must be used (the upload */ + /* file formats only allow for a maximum */ + /* of 35 characters). */ + tBYTE subject_len; /* The maximum length of the SUBJECT: field */ + /* that the host BBS can support. If */ + /* this value is 0 or is greater than 71, */ + /* then 71 must be used (the upload file */ + /* formats only allow for a maximum of 71 */ + /* characters). */ + tBYTE packet_id[9]; /* Original root name of the mail packet, */ + /* as specified by the mail door. All */ + /* files in the packet that are created */ + /* by the mail door will use this root */ + /* name, as will the reader when creating */ + /* the upload files. Thus, even if the */ + /* packets themselves are renamed to */ + /* something completely different, the */ + /* mail doors and readers will still be */ + /* able to work with the proper files. */ + tBYTE file_list_type; /* New file listing type */ + /* (* VERSION 3 AND LATER ONLY *) */ + /* Specifies the type of new file list */ + /* that is generated by the door (see */ + /* INF_FLIST_xxx, above). This field is */ + /* intended for use with offline config. */ + tBYTE auto_macro[3]; /* Auto-macro indicator flags */ + /* (* VERSION 3 AND LATER ONLY *) */ + /* Specifies which macros are auto macros */ + /* (i.e. execute automatically after mail */ + /* is scanned). */ + tINT max_packet_size; /* Maximum size of uncompressed packet */ + /* (* VERSION 3 AND LATER ONLY *) */ + /* Specifies, in K, the maximum size of */ + /* an uncompressed mail packet. A value */ + /* of 0 indicates no maximum length. */ + /* This field is intended for use with */ + /* offline config. */ + tBYTE reserved[228]; /* RESERVED FOR FUTURE USE */ + /* This field MUST be filled with ASCII */ + /* NUL (0x00) characters in order for */ + /* future additional features to work */ + /* properly! */ +} +INF_HEADER; + +/* +** Notes about the INF_HEADER.XXXXX_LEN fields, above: +** +** Door authors should take the few extra lines of code to fill in the +** structure lengths defined above. Doing so will make the Blue Wave data +** structures extensible and adaptable to almost any kind of file change that +** may be required in the future. The readers that use this mail packet +** format should contain code to handle a structure length that is longer or +** shorter than they expect. +** +** Reader authors need to take the time to code for possible extensions to +** this file format. If the data fields are LONGER than expected, simply do +** a seek to move to the next record, and ignore the extra information. If +** the data fields are SHORTER than expected, a simple "Please upgrade your +** reader" should suffice. However, you should never encounter a +** record size smaller than the ones defined here. Any extra information +** that is sent in the packets probably would not be crucial, and you may be +** able to continue with reading the packet anyway. +** +** It should be noted that all current Blue Wave doors set these fields to 0, +** as this extensibility was not added until recently. If the structure +** sizes are 0, the reader will assume that all records are of the sizes +** defined here. (Blue Wave readers below version 2.10 do NOT allow for +** extensible data files. Version 2.10, and all subsequent versions, WILL +** handle them properly.) DO NOT EXTEND THESE STRUCTURE FORMATS WITHOUT +** NOTIFYING CUTTING EDGE COMPUTING FIRST! If the extended information will +** benefit programs/users, it will be officially added to the packet format. +** +** The original values for the INF_HEADER.XXXXX_LEN structures are as below, +** defined as macros which you can use in your programs. Remember, if the +** value in INF_HEADER.XXXXX_LEN is 0, you must use these values instead! +*/ + +#define ORIGINAL_INF_HEADER_LEN 1230 /* Original *.INF header len */ +#define ORIGINAL_INF_AREA_LEN 80 /* Original *.INF area rec len */ +#define ORIGINAL_MIX_STRUCT_LEN 14 /* Original *.MIX record len */ +#define ORIGINAL_FTI_STRUCT_LEN 186 /* Original *.FTI record len */ + +/* +** Below is some sample C code for reading in the variable length *.INF +** structure, which is the most "difficult" one to do. Note the sections of +** code which use the ORIGINAL_XXXXX_LEN macros; these are the sections that +** determine the proper structure length. (Comments are preceeded by "#" +** signs, since using C comment symbols would make most compilers think that +** nested comments are in use, a practice which normally is not allowed.) +** +** int read_inf_file(void) +** { +** INF_HEADER inf_header; +** INF_AREA_INFO inf_info; +** FILE *inf_file=NULL; +** tWORD record_num=0u; +** tWORD inf_header_slen, inf_area_slen; +** tLONG seek_pos=0L; +** +** inf_file = fopen("WILDBLUE.INF", "rb"); +** if (inf_file == NULL) +** return 0; +** +** fread(&inf_header, sizeof(INF_HEADER), 1, inf_file); +** puts(inf_header.loginname); +** puts(inf_header.aliasname); +** +** # Test and verify the validity of the structure lengths. +** +** if (inf_header.inf_header_len < ORIGINAL_INF_HEADER_LEN) +** inf_header_slen = ORIGINAL_INF_HEADER_LEN; +** else +** inf_header_slen = inf_header.inf_header_len; +** +** if (inf_header.inf_areainfo_len < ORIGINAL_INF_AREA_LEN) +** inf_area_slen = ORIGINAL_INF_AREA_LEN; +** else +** inf_area_slen = inf_header.inf_areainfo_len; +** +** # now, move to the END of the header, since it may be longer +** # than we expect it to be. Use fseek()... +** +** fseek(inf_file, (long)inf_header_slen, SEEK_SET); +** +** record_num = 0U; +** while(fread(&inf_info, sizeof(INF_AREA_INFO), 1, inf_file)) +** { +** puts(inf_info.title); +** record_num++; +** +** # we need to seek past the header, and then [record_num] +** # number of recs. +** +** seek_pos = (long)(inf_header_slen+(record_num*inf_area_slen)); +** fseek(inf_file, seek_pos, SEEK_SET); +** } +** +** fclose(inf_file); +** return 1; +** } +*/ + +/* Bit-masks for INF_AREA_INFO.AREA_FLAGS field */ + +#define INF_SCANNING 0x0001 /* On=User is active for area */ +#define INF_ALIAS_NAME 0x0002 /* On=Alias name, Off=Login name */ + /* If ON, use INF_HEADER.ALIASNAME when */ + /* addressing new mail or replies for the */ + /* message area. If OFF, the reader uses */ + /* the INF_HEADER.LOGINNAME for this */ + /* purpose. */ +#define INF_ANY_NAME 0x0004 /* On=Allow any name to be entered */ + /* If ON, any name can be entered in the */ + /* From: field when addressing new mail */ + /* or replies for the message area. If */ + /* OFF, the normal rules apply. */ +#define INF_ECHO 0x0008 /* On=Network mail, Off=Local mail */ +#define INF_NETMAIL 0x0010 /* On=E-mail, Off=Conference mail */ + /* Refer to the chart below (the values */ + /* for the NETWORK_TYPE field) for info */ + /* on how these two flags should be set */ + /* for message areas. */ +#define INF_POST 0x0020 /* On=User can post, Off=User CANNOT post */ +#define INF_NO_PRIVATE 0x0040 /* On=Private messages are NOT allowed */ +#define INF_NO_PUBLIC 0x0080 /* On=Public messages are NOT allowed */ +#define INF_NO_TAGLINE 0x0100 /* On=Taglines are not allowed */ +#define INF_NO_HIGHBIT 0x0200 /* On=ASCII 1-127 only, Off=ASCII 1-255 */ + /* If ON, only ASCII values 1 to 127 are */ + /* allowed in messages. If OFF, all */ + /* values from 1 to 255 are allowed. Due */ + /* to the fact that ASCII value 0 is used */ + /* in C as a string terminator, the value */ + /* 0 should not be allowed in messages at */ + /* all. */ +#define INF_NOECHO 0x0400 /* On=User can prevent messages from being */ + /* sent through the network */ +#define INF_HASFILE 0x0800 /* On=User can attach files to messages */ +#define INF_PERSONAL 0x1000 /* On=User is downloading only personal */ + /* msgs in this message area. The flag */ + /* INF_SCANNING also needs to be ON. */ + /* (* VERSION 3 AND LATER ONLY *) */ +#define INF_TO_ALL 0x2000 /* On=User is downloading messages to "All" */ + /* and personal messages only in this */ + /* area. The flag INF_SCANNING also */ + /* needs to be ON. INF_PERSONAL should */ + /* *not* be set, as this flag implies the */ + /* downloading of personal messages also. */ + /* (* VERSION 3 AND LATER ONLY *) */ + +/* Values for INF_AREA_INFO.NETWORK_TYPE field */ + +#define INF_NET_FIDONET 0 /* FidoNet-style E-mail and conferences */ + /* Local = INF_ECHO=off, NETMAIL=off */ + /* EchoMail = INF_ECHO=on, NETMAIL=off */ + /* GroupMail = INF_ECHO=on, NETMAIL=off */ + /* NetMail = INF_ECHO=on, NETMAIL=on */ +#define INF_NET_INTERNET 1 /* Internet E-mail and Usenet newsgroups */ + /* Local = INF_ECHO=off, NETMAIL=off */ + /* Newsgroup = INF_ECHO=on, NETMAIL=off */ + /* E-mail = INF_ECHO=on, NETMAIL=on */ + +typedef struct /* INF_AREA_INFO */ +{ + tBYTE areanum[6]; /* Area number this record corresponds to */ + tBYTE echotag[21]; /* Area tag name (*.BRD name for Telegard) */ + tBYTE title[50]; /* Area description/title */ + tWORD area_flags; /* Bit-mapped area options */ + tBYTE network_type; /* Network mail type (see above) */ +} +INF_AREA_INFO; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.MIX +** +** Description: The *.MIX file is a very small file, with one record for +** every message area that was scanned. It contains the +** information to get into the *.FTI file. +** +** File format: MIX_REC { repeated for each message area scanned } +** MIX_REC +** ... +*/ + +typedef struct /* MIX_REC */ +{ + tBYTE areanum[6]; /* Area number this record corresponds to */ + /* This is the ASCII representation of the */ + /* actual area number shown on the host BBS. */ + tWORD totmsgs; /* Total number of messages for this area */ + tWORD numpers; /* Total number of personal messages in this area */ + tLONG msghptr; /* Pointer to first message header in *.FTI file */ +} +MIX_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.FTI +** +** Description: The *.FTI file contains the information for each message +** in the packet. Each record includes all of the +** information about the message, including the pointer to +** the actual message text in the *.DAT file. +** +** NOTE: Messages in the *.FTI file will ALWAYS be in area +** number order. That is to say, if the MIX_REC +** indicates there are 100 messages for this area, +** all 100 messages will follow in sequential order. +** +** File format: FTI_REC { repeated for as many messages } +** FTI_REC { as obtained from the host BBS } +** ... +*/ + +/* Bit-masks for FTI_REC.FLAGS field */ + +#define FTI_MSGPRIVATE 0x0001 /* Private = For addressee ONLY */ +#define FTI_MSGCRASH 0x0002 /* Crash = High priority mail */ +#define FTI_MSGREAD 0x0004 /* Read = Message read by addressee */ +#define FTI_MSGSENT 0x0008 /* Sent = Message sent */ +#define FTI_MSGFILE 0x0010 /* File Attach = Send file(s) */ +#define FTI_MSGFWD 0x0020 /* Forward = Message to/from others */ +#define FTI_MSGORPHAN 0x0040 /* Orphan = Message destination unknown */ +#define FTI_MSGKILL 0x0080 /* Kill/Sent = Delete after sending */ +#define FTI_MSGLOCAL 0x0100 /* Local = Message originated here */ +#define FTI_MSGHOLD 0x0200 /* Hold = Hold for pickup, don't send */ +#define FTI_MSGIMMEDIATE 0x0400 /* Immediate = Send message NOW */ +#define FTI_MSGFRQ 0x0800 /* File Request = Request file(s) */ +#define FTI_MSGDIRECT 0x1000 /* Direct = Send direct, no routing */ +#define FTI_MSGUNUSED1 0x2000 /* */ +#define FTI_MSGUNUSED2 0x4000 /* */ +#define FTI_MSGURQ 0x8000 /* Update Request = Req updated file(s) */ + +typedef struct /* FTI_REC */ +{ + tBYTE from[36]; /* Person message is from */ + tBYTE to[36]; /* Person message is to */ + tBYTE subject[72]; /* Subject/title of message */ + tBYTE date[20]; /* Origin date of message */ + /* Depending on the host BBS's date storage */ + /* format, the EXACT format of this field */ + /* will change. Some will take all 19 bytes, */ + /* others may take only 10. */ + tWORD msgnum; /* Number of THIS message on BBS */ + tWORD replyto; /* "This is a reply to #xx" */ + /* Not used for every message. When non- */ + /* zero, there is a previous message in */ + /* the thread. */ + tWORD replyat; /* "There is a reply at #xx" */ + /* Not used for every message. When non- */ + /* zero, there is a reply to this message. */ + tLONG msgptr; /* Offset to start of message in *.DAT file */ + /* Seek to this exact offset in the *.DAT */ + /* file, then read "msglength" bytes from */ + /* the file to load the entire message text. */ + tLONG msglength; /* Length of message text (in bytes) */ + tWORD flags; /* Bit-mapped message status flags */ + tWORD orig_zone; /* Origin address of message */ + /* These three fields will most likely be 0, */ + /* unless the current message belongs to a */ + /* NetMail message base. */ + tWORD orig_net; + tWORD orig_node; +} +FTI_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.DAT +** +** Description: The *.DAT file is an unstructured file which contains the +** text of every message obtained from the host BBS. +** Valid messages begin with an ASCII space (0x20) character +** (which is NOT to be considered part of the message!) +** followed by zero or more bytes which constitute the +** message text. The pointer to the text for each message is +** stored in FTI_REC.MSGPTR, and the length of the text for +** each message is stored in FTI_REC.MSGLENGTH. +** +** File format: Unstructured +*/ + + +/*****************************************************************************/ +/* >>>>>>>>>>>>>>>>> MISCELLANEOUS DATA FILE STRUCTURES <<<<<<<<<<<<<<<<<< */ +/*****************************************************************************/ + + +/* +** Name of file: *.MSG +** +** Description: The Fido *.MSG message (named for the BBS program on which +** it originated) has become a de-facto standard among BBS +** implementations, due to the sheer number of utilities +** available that operate with *.MSG messages. It is as +** close to a universal message format as one can get in +** FidoNet (and FidoNet-style networks), and is the reason +** why it is used here (well, the *.MSG header, anyway). +** +** NOTE: Most of the fields in the FTI_REC structure (shown +** above) correspond to similar fields in MSG_REC. +** This was done deliberately, in order to make +** *.FTI file processing a little more intuitive for +** programmers. Also note that MSG_REC is only used +** by the NET_REC structure, which will soon become +** obsolete (replaced by UPL_REC). +** +** File format: MSG_REC { only included one time! } +** message text { text can be terminated by an ASCII NUL } +** { character (0x00), or by an ASCII CR, } +** { LF, NUL (0x0D 0x0A 0x00) sequence } +*/ + +/* Bit-masks for MSG_REC.ATTR field */ + +#define MSG_NET_PRIVATE 0x0001 /* Private */ +#define MSG_NET_CRASH 0x0002 /* Crash mail */ +#define MSG_NET_RECEIVED 0x0004 /* Received */ +#define MSG_NET_SENT 0x0008 /* Sent */ +#define MSG_NET_FATTACH 0x0010 /* File attached */ +#define MSG_NET_INTRANSIT 0x0020 /* In-transit */ +#define MSG_NET_ORPHAN 0x0040 /* Orphaned */ +#define MSG_NET_KILL 0x0080 /* Kill after sending */ +#define MSG_NET_LOCAL 0x0100 /* Local message */ +#define MSG_NET_HOLD 0x0200 /* Hold for pickup */ +#define MSG_NET_RESERVED 0x0400 /* RESERVED */ +#define MSG_NET_FREQ 0x0800 /* File request */ +#define MSG_NET_RREQ 0x1000 /* Return receipt request */ +#define MSG_NET_RECEIPT 0x2000 /* Return receipt message */ +#define MSG_NET_AREQ 0x4000 /* Audit request */ +#define MSG_NET_FUREQ 0x8000 /* File update request */ + +typedef struct /* MSG_REC (will soon be obsolete) */ +{ + tBYTE from[36]; /* Person message is from */ + tBYTE to[36]; /* Person message is to */ + tBYTE subj[72]; /* Subject/title of message */ + tBYTE date[20]; /* Creation date/time */ + /* This date/time is usually in either of the */ + /* Fido-sanctioned formats "DD MMM YY HH:MM:SS" */ + /* or "WWW DD MMM YY HH:MM", but due to the */ + /* chaotic nature of FidoNet-compatible software, */ + /* this CANNOT be relied upon! */ + tWORD times; /* Number of times read (fairly obsolete) */ + tWORD dest; /* Destination node (of net/node) */ + tWORD orig; /* Origin node (of net/node) */ + tWORD cost; /* Cost of sending message (usually in US cents) */ + tWORD orig_net; /* Origin net (of net/node) */ + tWORD destnet; /* Destination net (of net/node) */ + tLONG unused1; /* Undefined */ + tLONG unused2; /* Some software (Opus and Maximus, for example) */ + /* uses these fields to store the sent/received */ + /* date/time as bit-packed fields, using the same */ + /* format used in MS-DOS directory entries. */ + tWORD reply; /* Message # that this message replies to */ + tWORD attr; /* Message attributes and behavior flags */ + tWORD up; /* Message # that replies to this message */ +} +MSG_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.XTI +** +** Description: The *.XTI file contains extended information for each +** message in the packet. The number of records in the *.XTI +** file will always equal the number of messages in the +** packet, with each record corresponding to a record in the +** *.FTI file (i.e. record #1 in the *.XTI file corresponds +** to record #1 in the *.FTI file, and so on). +** +** NOTE: This file is currently created ONLY by the Blue +** Wave reader, and is not a part of the official +** Blue Wave packet specification; it is merely +** documented here for third party programmers to use +** if they so desire. How other readers store which +** messages have been read/replied-to/marked is left +** as an option to be implemented by the individual +** reader authors. You may use this method if you so +** desire; however, PLEASE do not name any external +** files not conforming to this specification as +** .XTI, due to the fact that the Blue +** Wave reader will expect the file to be in the +** format described. If it's not in the expected +** format, things will get interesting. :-) +** +** File format: XTI_REC { repeated for as many messages } +** XTI_REC { as obtained from the host BBS } +** ... +*/ + +/* Bit-masks for XTI_REC.FLAGS field */ + +#define XTI_HAS_READ 0x01 /* Message has been read */ +#define XTI_HAS_REPLIED 0x02 /* Message has been replied to */ +#define XTI_IS_PERSONAL 0x04 /* Message is personal */ +#define XTI_IS_TAGGED 0x08 /* Message has been 'tagged' */ +#define XTI_HAS_SAVED 0x10 /* Message has been saved */ +#define XTI_HAS_PRINTED 0x20 /* Message has been printed */ + +/* Bit-masks for XTI_REC.MARKS field */ + +#define XTI_MARK_SAVE 0x01 /* Message marked for saving */ +#define XTI_MARK_REPLY 0x02 /* Message marked for replying */ +#define XTI_MARK_PRINT 0x04 /* Message marked for printing */ +#define XTI_MARK_DELETE 0x08 /* Message marked for deletion */ + +typedef struct /* XTI_REC */ +{ + tBYTE flags; /* Bit-mapped message flags */ + tBYTE marks; /* Bit-mapped message markers */ +} +XTI_REC; + + +/*****************************************************************************/ +/* >>>>>>>>>>>>>>>>>>>> READER DATA FILE STRUCTURES <<<<<<<<<<<<<<<<<<<<<< */ +/*****************************************************************************/ + + +/* +** Name of file: *.NET +** +** Description: The *.NET file is created ONLY when there is NetMail to be +** sent. It contains the FULL header of the Fido-style *.MSG +** structure plus the fields defined below (which aren't part +** of the standard *.MSG structure yet required by the door). +** +** NOTE: Readers should only generate a *.NET file if +** INF_HEADER.USES_UPL_FILE is not set *AND* the +** mail packet format is version 2 or earlier. +** Doors should process *.NET files *ONLY* in cases +** where a *.UPL file is not present. +** +** File format: NET_REC { repeated for as many NetMail } +** NET_REC { messages as exist in the packet } +** ... +*/ + +typedef struct /* NET_REC */ +{ + MSG_REC msg; /* The Fido-style *.MSG header */ + tBYTE fname[13]; /* Filename the message text is in */ + tBYTE echotag[21]; /* NetMail area tag (*.BRD name for Telegard) */ + tWORD zone; /* Destination zone (of zone:net/node.point) */ + tWORD point; /* Destination point (of zone:net/node.point) */ + tLONG unix_date; /* Date/time of message */ + /* This Unix-style date/time value (number */ + /* of seconds since 01/01/70) is converted */ + /* to the date/time storage method used by */ + /* the host BBS. */ +} +NET_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.UPI +** +** Description: The *.UPI file contains the information for each message +** in the reply packet, as well as information on the reader +** version and registration numbers. Each record includes +** all of the information about the message. +** +** NOTE: Readers should only generate a *.UPI file if +** INF_HEADER.USES_UPL_FILE is not set *AND* the +** mail packet format is version 2 or earlier. +** Doors should process *.UPI files *ONLY* in cases +** where a *.UPL file is not present. +** +** File format: UPI_HEADER { only included one time! } +** UPI_REC { repeated for as many msg bases } +** UPI_REC { as are available to the user } +** ... +*/ + +typedef struct /* UPI_HEADER */ +{ + tBYTE regnum[9]; /* Reader registration number */ + tBYTE vernum[13]; /* Reader version number */ + /* All bytes should be the actually ASCII */ + /* value plus 10. Lame security, yes, but it */ + /* does prevent "TYPE *.UPI" from showing the */ + /* version number. */ + tBYTE future[33]; /* RESERVED FOR FUTURE USE */ +#ifdef PAD_SIZES_EVEN + tBYTE evenpad; /* If your compiler pads structures out to even */ + /* numbered sizes, define PAD_SIZES_EVEN */ + /* before including this header. When the */ + /* *.UPI file is written, be sure to write */ + /* sizeof(UPI_HEADER) - 1 bytes, otherwise */ + /* your compiler may insert an extra byte not */ + /* explicitly specified here. */ +#endif +} +UPI_HEADER; + +/* Bit-masks for UPI_REC.FLAGS field */ + +#define UPI_RES1 0x01 /* RESERVED FOR FUTURE USE */ +#define UPI_RES2 0x02 /* RESERVED FOR FUTURE USE */ +#define UPI_RES3 0x04 /* RESERVED FOR FUTURE USE */ +#define UPI_RES4 0x08 /* RESERVED FOR FUTURE USE */ +#define UPI_RES5 0x10 /* RESERVED FOR FUTURE USE */ +#define UPI_RES6 0x20 /* RESERVED FOR FUTURE USE */ +#define UPI_PRIVATE 0x40 /* Message is PRIVATE */ +#define UPI_NO_ECHO 0x80 /* Message is NOT to be echoed */ + /* This feature is not yet implemented in */ + /* the Blue Wave reader or doors, as none */ + /* of the currently supported BBS software */ + /* has support for this feature. */ + +typedef struct /* UPI_REC */ +{ + tBYTE from[36]; /* Person message is from */ + tBYTE to[36]; /* Person message is to */ + tBYTE subj[72]; /* Subject/title of message */ + tLONG unix_date; /* Date/time of message */ + /* This Unix-style date/time value (number */ + /* of seconds since 01/01/70) is converted */ + /* to the date/time storage method used by */ + /* the host BBS. */ + tBYTE fname[13]; /* Filename the message text is in */ + tBYTE echotag[21]; /* Area tag name (*.BRD name for Telegard) */ + tBYTE flags; /* Bit-mapped flags */ + tBYTE reedit; /* INTERNAL USE ONLY! */ + /* This flag is used internally by the Blue */ + /* Wave reader. Doors should ignore this */ + /* field during reply packet processing. */ +} +UPI_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.UPL +** +** Description: The *.UPL file contains the information for each message +** in the reply packet, as well as information on the reader +** version and registration numbers. Each record includes +** all of the information about the message. +** +** NOTE: Readers should only generate a *.UPL file if +** INF_HEADER.USES_UPL_FILE is set *AND/OR* the mail +** packet format is version 3 or later. Doors should +** process *.UPL files in all cases where one is +** present. +** +** File format: UPL_HEADER { only included one time! } +** UPL_REC { repeated for as many messages } +** UPL_REC { as are included in the packet } +** ... +*/ + +typedef struct /* UPL_HEADER */ +{ + tBYTE regnum[10]; /* Reader registration number (if desired) */ + tBYTE vernum[20]; /* Reader version number as a string. */ + /* All bytes should be the actually ASCII */ + /* value plus 10. Lame security, yes, but it */ + /* does prevent "TYPE *.UPL" from showing the */ + /* version number. */ + /* Examples: "2.10a Beta" */ + /* "2.11" */ + tBYTE reader_major; /* Major version of the reader (number to the */ + /* left of the decimal point) */ + tBYTE reader_minor; /* Minor version of the reader (number to the */ + /* right of the decimal point) */ + tBYTE reader_name[80]; /* String containing name of the reader, such */ + /* as "The Blue Wave Offline Mail Reader". */ + /* This is provided for door programmers that */ + /* wish to display the name of the reader */ + /* that created the reply packet. (Filling */ + /* it is mandatory but using it is optional.) */ + tWORD upl_header_len; /* Size of UPL_HEADER structure */ + tWORD upl_rec_len; /* Size of UPL_REC structure */ + /* NOTE: Refer to the INF_HEADER section for */ + /* more information on using the size */ + /* fields. */ + tBYTE loginname[44]; /* Name found in INF_HEADER.LOGINNAME. This is */ + /* provided for door authors as a security */ + /* measure to implement as they wish. */ + tBYTE aliasname[44]; /* Name found in INF_HEADER.ALIASNAME */ + tBYTE reader_tear[16]; /* String containing abbreviated name of the */ + /* reader, such as "Blue Wave", "Q-Blue", */ + /* "Wave Rider", etc. This is provided for */ + /* doors programmers that wish to add to the */ + /* tear line the name of the reader that */ + /* created the reply packet. (Filling it is */ + /* mandatory but using it is optional.) If */ + /* this field is blank, the tear line to be */ + /* generated is left to the discretion of the */ + /* door author. */ + tBYTE compress_type; /* Compression type required for mail packet */ + /* The Blue Wave reader uses this internally */ + /* to store the compression type required for */ + /* this particular mail packet. */ + tBYTE flags; /* Reader processing flags */ + /* The Blue Wave reader uses this internally */ + /* to store flags required for later */ + /* processing. */ + /* 0x01 = Was a .QWK packet. */ + /* 0x02 = Host requires a *.UPI file */ + tBYTE not_registered; /* Reader is not registered to user */ + /* If this byte is set to a non-zero value, */ + /* the Blue Wave doors will assume that the */ + /* user's reader was not registered, and will */ + /* place "[NR]" at the end of the tear line. */ + /* Third-party doors may use this flag for */ + /* the same purpose; its use is optional by */ + /* mail readers (especially if you don't care */ + /* whether or not "[NR]" shows up on the tear */ + /* line ). */ + tBYTE pad[33]; /* RESERVED FOR FUTURE USE, and to pad struct */ + /* out to a 'nice' 256 bytes */ +} +UPL_HEADER; + +/* Bit-masks for UPL_REC.MSG_ATTR field */ + +#define UPL_INACTIVE 0x0001 /* Message is INACTIVE */ + /* Doors should NOT attempt to import this */ + /* message. */ +#define UPL_PRIVATE 0x0002 /* Message is PRIVATE */ +#define UPL_NO_ECHO 0x0004 /* Message is NOT to be echoed */ + /* This feature is not yet implemented in */ + /* the Blue Wave reader or doors, as none */ + /* of the currently supported BBS software */ + /* has support for this feature. */ +#define UPL_HAS_FILE 0x0008 /* Message has file "attached" to it */ + /* It is up to the door to check the */ + /* validity of this flag. If the file is */ + /* contained in the mail packet, great. */ + /* If not, the door should probably prompt */ + /* the user to begin uploading the file */ + /* after importing the messages. (Not yet */ + /* implemented in the Blue Wave reader.) */ +#define UPL_NETMAIL 0x0010 /* Message is network mail */ + /* Indicates NetMail/E-mail message. The */ + /* NETWORK_TYPE field (see below) will */ + /* indicate which fields should be used */ + /* for addressing the message. */ +#define UPL_IS_REPLY 0x0020 /* Indicates that the message is a reply to */ + /* an existing message, rather than being */ + /* a completely new message. */ +#define UPL_MRES7 0x0040 /* RESERVED FOR FUTURE USE */ +#define UPL_MRES8 0x0080 /* RESERVED FOR FUTURE USE */ + /* All of the other 8 bits of this field are */ + /* also reserved for future use. This */ + /* should provide for plenty of expansion */ + /* for future development. */ + +/* Bit-masks for UPL_REC.NETMAIL_ATTR field */ + +#define UPL_NRES1 0x0001 /* RESERVED FOR FUTURE USE */ +#define UPL_NETCRASH 0x0002 /* Crash = High priority mail */ +#define UPL_NRES2 0x0004 /* RESERVED FOR FUTURE USE */ +#define UPL_NRES3 0x0008 /* RESERVED FOR FUTURE USE */ +#define UPL_NETFILE 0x0010 /* File Attach = Send file(s) listed */ + /* in Subject field */ +#define UPL_NRES4 0x0020 /* RESERVED FOR FUTURE USE */ +#define UPL_NRES5 0x0040 /* RESERVED FOR FUTURE USE */ +#define UPL_NETKILL 0x0080 /* Kill/Sent = Delete after sending */ +#define UPL_NETLOCAL 0x0100 /* Local = Message originated here */ +#define UPL_NETHOLD 0x0200 /* Hold = Hold for pickup, do not send */ +#define UPL_NETIMMEDIATE 0x0400 /* Immediate = Send message NOW */ +#define UPL_NETFRQ 0x0800 /* File Request = Request file(s) */ + /* listed in Subject field */ +#define UPL_NETDIRECT 0x1000 /* Direct = Send direct, no routing */ +#define UPL_NRES6 0x2000 /* RESERVED FOR FUTURE USE */ +#define UPL_NRES7 0x4000 /* RESERVED FOR FUTURE USE */ +#define UPL_NETURQ 0x8000 /* Update Request = Request updated */ + /* file(s) listed in Subject field */ + +/* Values for UPL_REC.NETWORK_TYPE field */ + +#define UPL_NET_FIDONET 0 /* FidoNet-style E-mail and conferences */ + /* UPL_NETMAIL=off - Local, Echo, Group */ + /* UPL_NETMAIL=on - NetMail */ +#define UPL_NET_INTERNET 1 /* Internet E-mail and Usenet newsgroups */ + /* UPL_NETMAIL=off - Local, Newsgroup */ + /* UPL_NETMAIL=on - E-mail */ + +typedef struct /* UPL_REC */ +{ + tBYTE from[36]; /* Person message is from */ + /* NOTE: Doors should validate this field! */ + tBYTE to[36]; /* Person message is to (non-Internet) */ + /* For Internet E-mail, the NET_DEST field */ + /* should be used to store the destination */ + /* name/address, leaving this field blank. */ + /* For Usenet newsgroups, this field should be */ + /* left blank, as newsgroups don't use a "To:" */ + /* field. */ + tBYTE subj[72]; /* Subject/Title of message */ + tWORD destzone; /* Destination address (FidoNet only) */ + /* If the message is not a FidoNet NetMail */ + /* message, this field (and the subsequent */ + /* three fields as well) should be set to */ + /* zero. */ + tWORD destnet; + tWORD destnode; + tWORD destpoint; + tWORD msg_attr; /* Bit-mapped message attributes */ + tWORD netmail_attr; /* Bit-mapped NetMail attributes (FidoNet only) */ + /* If the message is not a FidoNet NetMail */ + /* message, this field should not be used. */ + tLONG unix_date; /* Date/time of message */ + /* This Unix-style date/time value (number */ + /* of seconds since 01/01/70) is converted to */ + /* the date/time storage method used by the */ + /* host BBS. */ + tDWORD replyto; /* This unsigned long word stores the message # */ + /* that this message is a reply to. This */ + /* should be the same as FTI.MSGNUM. Note, */ + /* however, that FTI.MSGNUM is a word. C */ + /* programmers especially will need to */ + /* properly typecast the value (i.e. */ + /* upl.replyto=(tDWORD)fti.msgnum). As */ + /* messaging/BBS systems become more complex, */ + /* FTI.MSGNUM may become obsolete, and a */ + /* tDWORD variable may be used in its place. */ + tBYTE filename[13]; /* Filename the message text is in */ + /* If this file does not exist in the upload */ + /* packet then doors should consider this an */ + /* invalid record. */ + tBYTE echotag[21]; /* Area tag the message goes in */ + /* This must correspond exactly to the */ + /* INF_AREA_INFO.ECHOTAG field for the message */ + /* area this message belongs to. Simple area */ + /* number matching has proven not to work */ + /* simply because sysops are finicky people, */ + /* and seem to constantly renumber/change the */ + /* message area numbers on the host BBS. */ + /* Using an echotag helps to alleviate this */ + /* problem. C_ECHO will be C_ECHO on the BBS, */ + /* whether it is msg area 17 on the host BBS */ + /* or whether it is area 207. Doors should do */ + /* a case-INSENSITIVE compare on this field to */ + /* find where the message belongs. */ + tWORD area_flags; /* The Blue Wave Offline Mail Reader uses this */ + /* word internally to store the same value as */ + /* in INF_AREA_INFO.AREA_FLAGS. The purpose */ + /* of this word is to hold the original */ + /* information about the message area so that */ + /* later message editing processes can be */ + /* controlled properly. For example, if a */ + /* user later wanted to edit this message, the */ + /* reader would know instantly whether this is */ + /* a NETMAIL area, whether PVT messages are */ + /* allowed, etc. This allows re-editing of */ + /* the message, even when there is not a */ + /* corresponding *.INF file laying around, or */ + /* the area is not listed in the *.INF file */ + /* you currently have to work with. DOOR */ + /* AUTHORS SHOULD IGNORE THIS FIELD WHEN */ + /* IMPORTING MESSAGES! */ + tBYTE f_attach[13]; /* If the UPL_HAS_FILE flag is set, this field */ + /* will contain the file name that is attached */ + /* to the message. */ + tBYTE user_area[6]; /* User-defined storage. Doors should ignore */ + /* this field, and reader authors should feel */ + /* free to utilize this field for their own */ + /* internal use, if necessary. */ + tBYTE network_type; /* Indicates the network type. This field must */ + /* hold the same value as the NETWORK_TYPE */ + /* field in INF_AREA_INFO, allowing doors and */ + /* readers to properly handle the message. */ + /* (Values duplicated as UPL_NET_xxx, above.) */ + /* For FidoNet NetMail and Internet E-mail, it */ + /* also indicates which fields should be used */ + /* for addressing and status information (as */ + /* indicated in comments above and below). */ + tBYTE net_dest[100]; /* Network destination address (non-FidoNet) */ + /* Internet E-mail messages should use this */ + /* field to store the destination address. */ +} +UPL_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.REQ +** +** Description: The *.REQ file is simply a list of filenames the user +** wants to request from the host BBS. Wildcard characters +** ("*" and "?" under MS-DOS) are allowed, but are not +** guaranteed to produce accurate results on all door +** implementations. +** +** NOTE: Current Blue Wave doors do not accept wildcard +** characters in filenames, and will consider any +** filenames which contain them as being invalid. +** Additionally, if there are more than 10 entries in +** the *.REQ file, current Blue Wave doors will read +** the first 10 and discard the rest. These are +** limitations of the Blue Wave doors, not of the +** Blue Wave format itself. +** +** File format: REQ_REC { repeated for as many files as } +** REQ_REC { requested from the host BBS } +** ... +*/ + +typedef struct /* REQ_REC */ +{ + tBYTE filename[13]; /* Name of file to request */ +} +REQ_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.PDQ +** +** Description: The *.PDQ file contains the information used for the +** offline configuration feature of the mail door. After the +** header is a series of records which indicate the message +** areas to enable for scanning the next time a mail packet +** is requested. +** +** NOTE: Readers should generate a *.PDQ file *ONLY* if +** the mail packet format is version 2 or earlier; +** otherwise, a *.OLC file should be generated. +** Doors should process *.PDQ files *ONLY* in cases +** where a *.OLC file is not present. +** +** If the AREA_CHANGES flag in PDQ_HEADER.FLAGS is +** set, the door should process the offline +** configuration as well as changes to the list of +** areas the user wants to download. In the Blue +** Wave door, this is done by first turning OFF all +** message areas that were active, then turning ON +** the ones specified in the *.PDQ file. This seems +** to be the simplest, most straight-forward method +** of accomplishing this task, though other, more +** complex schemes could easily have been devised. +** +** File format: PDQ_HEADER { only included one time! +** PDQ_REC { repeated for as many message areas } +** PDQ_REC { as the user wishes to enable } +** ... +*/ + +/* Bit-masks for PDQ_HEADER.FLAGS field */ + +#define PDQ_HOTKEYS 0x0001 /* Toggle "hotkeys" in prompts */ +#define PDQ_XPERT 0x0002 /* Toggle expert mode (menu displays) */ +#define PDQ_AREA_CHANGES 0x0004 /* Change active message areas */ +#define PDQ_GRAPHICS 0x0008 /* Toggle IBM 8-bit ASCII characters */ +#define PDQ_NOT_MY_MAIL 0x0010 /* Toggle bundling mail from user */ + +typedef struct /* PDQ_HEADER */ +{ + tBYTE keywords[10][21]; /* User's entire set of door keywords */ + tBYTE filters[10][21]; /* User's entire set of door filters */ + tBYTE macros[3][78]; /* User's door bundling command macros */ + tBYTE password[21]; /* Password */ + tBYTE passtype; /* Password type */ + /* 0=none 1=door 2=reader 3=both */ + tWORD flags; /* Bit-mapped flags */ +} +PDQ_HEADER; + +typedef struct /* PDQ_REC */ +{ + tBYTE echotag[21]; /* Echo tag of message area to activate */ + /* With Telegard systems, this should */ + /* be the name of the *.BRD file, rather */ + /* than the actual echo tag. */ +} +PDQ_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.OLC +** +** Description: The *.OLC file contains the information used for the +** offline configuration feature of the mail door. +** +** NOTE: Readers should generate a *.OLC file *ONLY* if +** the mail packet format is version 3 or later; +** otherwise, a *.PDQ file should be generated. +** Doors should process *.OLC files in all cases +** where one is present. +** +** File format: ASCII text (lines terminated with CRLF) +** +** Comments: Refer to the Blue Wave Developer's Kit documentation +** for details on the exact format of the *.OLC file. +*/ + +/*---------------------------------------------------------------------------*/ + +#endif /* __BLUEWAVE_H */ + diff --git a/lib/charconv.c b/lib/charconv.c new file mode 100644 index 00000000..b7e69d2d --- /dev/null +++ b/lib/charconv.c @@ -0,0 +1,723 @@ +/***************************************************************************** + * + * File ..................: common/charconv.c + * Purpose ...............: Common utilities + * Last modification date : 21-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "common.h" +#include "clcomm.h" + + +#ifndef BUFSIZ +#define BUFSIZ 512 +#endif + + +char *oldfilemap=NULL; +char maptab[] = { +"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" +"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +"\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" +"\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" +"\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" +"\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" +"\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" +"\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" +"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" +"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" +"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" +"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" +"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" +"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" +"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" +"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" +}; + + + +static int ctoi(char *); +static int ctoi(char *s) +{ + int i; + + if (!strncmp(s,"0x",2)) + sscanf(s+2,"%x",&i); + else if (*s == '0') + sscanf(s,"%o",&i); + else if (strspn(s,"0123456789") == strlen(s)) + sscanf(s,"%d",&i); + else + i=0; + return i; +} + + + +static int getmaptab(char *); +static int getmaptab(char *maptab_name) +{ + FILE *fp; + char buf[BUFSIZ], *p, *q; + int in, on; + + Syslog('M', "getmaptab: %s\n", maptab_name); + if ((fp = fopen(maptab_name, "r")) == NULL) { + WriteError("$can't open mapchan file \"%s\" ", maptab_name); + return 0; + } + + while (fgets(buf, sizeof(buf)-1, fp)) { + p = strtok(buf," \t\n#"); + q = strtok(NULL," \t\n#"); + if (p && q) { + in = ctoi(p); + on = ctoi(q); + if (in && on) + maptab[in] = on; + } + } + fclose(fp); + + return 0; +} + + + +char *strnkconv(const char *src, int incode, int outcode, int n) +{ + char ki[10], ko[10]; + int kolen; + static char *dest; + int destlen; + int i; + + outcode = getkcode(outcode, ki, ko); + kolen = strlen(ko); + + dest = strkconv(src, incode, outcode); + destlen = strlen(dest); + + if(destlen >= kolen && destlen > strlen(src)) { + for(i = 0; i < kolen; i++) + *(dest + n - 1 + i) = ko[i]; + *(dest + n) = '\0'; + } + + return dest; +} + + + +char *strkconv(const char *src, int incode, int outcode) +{ + static char *dest; + + if ((incode==outcode) && (incode!=CHRS_NOTSET) && (incode!=CHRS_AUTODETECT)) + return (char *)src; + + if (!src) + return NULL; + + if((incode == CHRS_AUTODETECT) || (incode == CHRS_NOTSET)) { + if (LANG_BITS == 16) { + incode = iso2022_detectcode((char *)src,incode); + } + } + + if(dest) + free(dest); + /* FIXME: should be + * dest = (char *)malloc((strlen(src) + 1) + (6 * "number of \n + 1")); + */ + dest = (char *)malloc(((strlen(src) + 1) * 2) + 6 ); + + kconv((char *)src, &dest, incode, outcode); + return dest; +} + + + +void kconv(char *in, char **out, int incode, int outcode) +{ + char ki[10], ko[10]; + + outcode = getkcode(outcode, ki, ko); + if (incode == outcode) + noconv(in,out); + else { + switch (incode) { + case CHRS_NOTSET : noconv(in,out); + break; + case CHRS_ASCII : noconv(in,out); + break; + case CHRS_BIG5 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_CP424 : + switch (outcode) { + case CHRS_CP862 : eight2eight(in,out,(char *)CP424__CP862); break; + case CHRS_ISO_8859_8 : eight2eight(in,out,(char *)CP424__ISO_8859_8); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP437 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)CP437__ISO_8859_1); break; + case CHRS_MACINTOSH : eight2eight(in,out,(char *)CP437__MACINTOSH); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP850 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)CP850__ISO_8859_1); break; + case CHRS_MACINTOSH : eight2eight(in,out,(char *)CP850__MACINTOSH); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP852 : + switch (outcode) { + case CHRS_FIDOMAZOVIA : eight2eight(in,out,(char *)CP852__FIDOMAZOVIA); break; + case CHRS_ISO_8859_2 : eight2eight(in,out,(char *)CP852__ISO_8859_2); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP862 : + switch (outcode) { + case CHRS_CP424 : eight2eight(in,out,(char *)CP862__CP424); break; + case CHRS_ISO_8859_8 : eight2eight(in,out,(char *)CP862__ISO_8859_8); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP866 : + switch (outcode) { + case CHRS_ISO_8859_5 : eight2eight(in,out,(char *)CP866__ISO_8859_5); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(in,out,(char *)CP866__KOI8); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP895 : + switch (outcode) { + case CHRS_ISO_8859_2 : eight2eight(in,out,(char *)CP895__ISO_8859_2); break; + case CHRS_CP437 : eight2eight(in,out,(char *)CP895__CP437); break; + default : noconv(in,out); break; + } + break; + case CHRS_EUC_JP : + switch (outcode) { + case CHRS_EUC_JP : euc2euc(in,out,incode,0); break; + case CHRS_ISO_2022_JP : euc2seven(in,out,incode,ki,ko); break; + case CHRS_NEC : euc2seven(in,out,incode,ki,ko); break; + case CHRS_SJIS : euc2shift(in,out,incode,0); break; + default : noconv(in,out); break; + } + break; + case CHRS_EUC_KR : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_FIDOMAZOVIA : + switch (outcode) { + case CHRS_CP852 : eight2eight(in,out,(char *)FIDOMAZOVIA__CP852); break; + case CHRS_ISO_8859_2 : eight2eight(in,out,(char *)FIDOMAZOVIA__ISO_8859_2); break; + default : noconv(in,out); break; + } + break; + case CHRS_GB : + switch (outcode) { + case CHRS_HZ : gb2hz(in,out); break; + default : noconv(in,out); break; + } + case CHRS_HZ : + switch (outcode) { + case CHRS_GB : hz2gb(in,out); break; + default : noconv(in,out); break; + } + case CHRS_ISO_11 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)ISO_11__ISO_8859_1); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_4 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)ISO_4__ISO_8859_1); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_60 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)ISO_60__ISO_8859_1); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_2022_CN : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_2022_JP : + switch (outcode) { + case CHRS_EUC_JP : seven2euc(in,out); break; + case CHRS_ISO_2022_JP : seven2seven(in,out,ki,ko); break; + case CHRS_NEC : seven2seven(in,out,ki,ko); break; + case CHRS_SJIS : seven2shift(in,out); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_2022_KR : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_2022_TW : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: + switch (outcode) { + case CHRS_CP437 : eight2eight(in,out,(char *)ISO_8859_1__CP437); break; + case CHRS_CP850 : eight2eight(in,out,(char *)ISO_8859_1__CP850); break; + case CHRS_MACINTOSH : eight2eight(in,out,(char *)ISO_8859_1__MACINTOSH); break; + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: noconv(in,out); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_2 : + switch (outcode) { + case CHRS_CP852 : eight2eight(in,out,(char *)ISO_8859_2__CP852); break; + case CHRS_CP895 : eight2eight(in,out,(char *)ISO_8859_2__CP895); break; + case CHRS_FIDOMAZOVIA : eight2eight(in,out,(char *)ISO_8859_2__FIDOMAZOVIA); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_3 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_4 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_5 : + switch (outcode) { + case CHRS_CP866 : eight2eight(in,out,(char *)ISO_8859_5__CP866); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(in,out,(char *)ISO_8859_5__KOI8); break; + case CHRS_MIK_CYR : eight2eight(in,out,(char *)ISO_8859_5__MIK_CYR); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_6 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_7 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_8 : + switch (outcode) { + case CHRS_CP424 : eight2eight(in,out,(char *)ISO_8859_8__CP424); break; + case CHRS_CP862 : eight2eight(in,out,(char *)ISO_8859_8__CP862); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_9 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_10 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_11 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : + switch (outcode) { + case CHRS_CP866 : eight2eight(in,out,(char *)KOI8__CP866); break; + case CHRS_ISO_8859_5 : eight2eight(in,out,(char *)KOI8__ISO_8859_5); break; + case CHRS_MIK_CYR : eight2eight(in,out,(char *)KOI8__MIK_CYR); break; + default : noconv(in,out); break; + } + break; + case CHRS_MACINTOSH : + switch (outcode) { + case CHRS_CP437 : eight2eight(in,out,(char *)MACINTOSH__CP437); break; + case CHRS_CP850 : eight2eight(in,out,(char *)MACINTOSH__CP850); break; + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)MACINTOSH__ISO_8859_1); break; + default : noconv(in,out); break; + } + break; + case CHRS_MIK_CYR : + switch (outcode) { + case CHRS_ISO_8859_5 : eight2eight(in,out,(char *)MIK_CYR__ISO_8859_5); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(in,out,(char *)MIK_CYR__KOI8); break; + default : noconv(in,out); break; + } + break; + case CHRS_NEC : + switch (outcode) { + case CHRS_EUC_JP : seven2euc(in,out); break; + case CHRS_ISO_2022_JP : seven2seven(in,out,ki,ko); break; + case CHRS_NEC : seven2seven(in,out,ki,ko); break; + case CHRS_SJIS : seven2shift(in,out); break; + default : noconv(in,out); break; + } + break; + case CHRS_SJIS : + switch (outcode) { + case CHRS_EUC_JP : shift2euc(in,out,incode,0); break; + case CHRS_ISO_2022_JP : shift2seven(in,out,incode,ki,ko); break; + case CHRS_NEC : shift2seven(in,out,incode,ki,ko); break; + case CHRS_SJIS : shift2shift(in,out,incode,0); break; + default : noconv(in,out); break; + } + break; + case CHRS_UTF_7 : + utf7_to_eight(in,out,&outcode); + break; + case CHRS_UTF_8 : + utf8_to_eight(in,out,&outcode); + break; + + case CHRS_ZW : + switch (outcode) { + case CHRS_HZ : zw2hz(in,out); break; + case CHRS_GB : zw2gb(in,out); break; + default : noconv(in,out); break; + } + break; + default : noconv(in,out); break; + } + } +} + + + +int getkcode(int code,char ki[],char ko[]) +{ + if (code == CHRS_ISO_2022_CN) { + strcpy(ki,"$A"); + strcpy(ko,"(T"); + } else if (code == CHRS_ISO_2022_JP) { + strcpy(ki,"$B"); + strcpy(ko,"(B"); + } else if (code == CHRS_ISO_2022_KR) { + strcpy(ki,"$(C"); + strcpy(ko,"(B"); + } else if (code == CHRS_ISO_2022_TW) { + strcpy(ki,"$(G"); + strcpy(ko,"(B"); + } + return code; +} + + + +int SkipESCSeq(FILE *in,int temp,int *intwobyte) +{ + int tempdata; + + tempdata = *intwobyte; + if (temp == '$' || temp == '(') + fgetc(in); + if (temp == 'K' || temp == '$') + *intwobyte = TRUE; + else + *intwobyte = FALSE; + if (tempdata == *intwobyte) + return FALSE; + else + return TRUE; +} + + + +void noconv(char *in, char **out) +{ + char *p; + + p=*out; + while (*in) + *p++=*in++; + *p='\0'; +} + + + +void eight2eight(char *in,char **out, char *filemap) +{ + char *p; + int i; + + if (oldfilemap != filemap) { + oldfilemap = filemap; + filemap = xstrcpy(getenv("MBSE_ROOT")); + filemap = xstrcat(filemap, (char *)"/etc/maptabs/"); + filemap = xstrcat(filemap, oldfilemap); + + for (i = 0; i < 256; i++) + maptab[i] = (unsigned char)i; + + getmaptab(filemap); + } + p=*out; + while (*in) { + *p=maptab[*in & 0xff]; + in++; + p++; + } + *p='\0'; +} + + + +int iso2022_detectcode(char *in,int whatcode) +{ + int c=0; + + while (((whatcode == CHRS_NOTSET) || (whatcode==CHRS_AUTODETECT)) && (*in)) { + if ((c = (unsigned int)(*in++))) { + if (c == ESC) { + c = (unsigned int)(*in++); + if (c == '$') { + c = (unsigned int)(*in++); + switch (c) { + case 'A' : whatcode = CHRS_ISO_2022_CN; break; + case 'B' : + case '@' : whatcode = CHRS_ISO_2022_JP; break; + case '(' : + case ')' : c = (unsigned int)(*in++); + switch (c) { + case 'A' : whatcode = CHRS_ISO_2022_CN; break; + case 'C' : whatcode = CHRS_ISO_2022_KR; break; + case 'D' : whatcode = CHRS_ISO_2022_JP; break; + case 'E' : whatcode = CHRS_ISO_2022_CN; break; + case 'G' : + case 'H' : + case 'I' : + case 'J' : + case 'K' : + case 'L' : + case 'M' : whatcode = CHRS_ISO_2022_TW; break; + case 'X' : whatcode = CHRS_ISO_2022_CN; break; + default: break; + } + break; + case '*' : c = (unsigned int)(*in++); + switch (c) { + case 'H' : + case 'X' : whatcode = CHRS_ISO_2022_CN; break; + default: break; + } + break; + case '+' : c = (unsigned int)(*in++); + switch (c) { + case 'H' : + case 'I' : + case 'J' : + case 'K' : + case 'L' : + case 'M' : + case 'X' : whatcode = CHRS_ISO_2022_CN; break; + default: break; + } + break; + default: break; + } + } + } else if (whatcode == CHRS_NOTSET) + return whatcode; +#if (LANG_DEFAULT == LANG_JAPAN) + else if ((c >= 129 && c <= 141) || (c >= 143 && c <= 159)) + whatcode = CHRS_SJIS; + else if (c == 142) { + c = (unsigned int)(*in++); + if ((c >= 64 && c <= 126) || (c >= 128 && c <= 160) || (c >= 224 && c <= 252)) + whatcode = CHRS_SJIS; + else if (c >= 161 && c <= 223) + whatcode = CHRS_AUTODETECT; + } else if (c >= 161 && c <= 223) { + c = (unsigned int)(*in++); + if (c >= 240 && c <= 254) + whatcode = CHRS_EUC_JP; + else if (c >= 161 && c <= 223) + whatcode = CHRS_AUTODETECT; + else if (c >= 224 && c <= 239) { + whatcode = CHRS_AUTODETECT; + while (c >= 64 && c != EOF && whatcode == CHRS_AUTODETECT) { + if (c >= 129) { + if (c <= 141 || (c >= 143 && c <= 159)) + whatcode = CHRS_SJIS; + else if (c >= 253 && c <= 254) + whatcode = CHRS_EUC_JP; + } + c = (unsigned int)(*in++); + } + } else if (c <= 159) + whatcode = CHRS_SJIS; + } else if (c >= 240 && c <= 254) + whatcode = CHRS_EUC_JP; + else if (c >= 224 && c <= 239) { + c = (unsigned int)(*in++); + if ((c >= 64 && c <= 126) || (c >= 128 && c <= 160)) + whatcode = CHRS_SJIS; + else if (c >= 253 && c <= 254) + whatcode = CHRS_EUC_JP; + else if (c >= 161 && c <= 252) + whatcode = CHRS_AUTODETECT; + } +#endif /* (LANG_DEFAULT == LANG_JAPAN) */ + } + } + return whatcode; +} + + + +char *hdrnconv(char *s, int incode, int outcode, int n) +{ + char ki[10],ko[10]; + int kolen; + static char *dest; + int destlen; + int i; + + getkcode(outcode, ki, ko); + kolen = strlen(ko); + dest = hdrconv(s, incode, outcode); + destlen = strlen(dest); + + if(destlen >= kolen && destlen > n) { + for(i = 0; i < kolen; i++) + *(dest + n - 1 - kolen + i) = ko[i]; + *(dest + n) = '\0'; + } + + return dest; +} + + + +char *hdrconv(char *s, int incode, int outcode) +{ +#define BCODAGE 1 +#define QCODAGE 2 + + char ttbuf[1024]; + char *iptr, *tptr; + char *xbuf=NULL, *buf=NULL, *q; + int codage; + +// Syslog('N', "hdrconv(%s, %d, %d)", s, incode, outcode); + + iptr = s; + while (*iptr) { + if (!strncmp(iptr,"=?",2)) { +// Syslog('N', "hdrconv =?"); + q=strchr(iptr+2,'?'); + if (q) { + incode=getcode(iptr+2); + if (incode==CHRS_NOTSET) + return s; + iptr=q; + } else { + return s; + } + if (!strncasecmp(iptr,"?Q?",3)) { + codage = QCODAGE; + iptr+=3; + } else if (!strncasecmp(iptr,"?B?",3)) { + codage = BCODAGE; + iptr+=3; + } else { + iptr=xstrcpy(iptr); + *(iptr+3)='\0'; + Syslog('+', "mimehdr_decode: unknown codage %s",iptr); + return s; + } + tptr = ttbuf; + while ((*iptr) && (strncmp(iptr,"?=",2))) + *tptr++ = *iptr++; + *tptr = '\0'; + if (!strncmp(iptr,"?=",2)) { + iptr++; + iptr++; + } + if (codage==QCODAGE) { + while ((q = strchr(ttbuf, '_'))) + *q=' '; + xbuf=xstrcat(xbuf,qp_decode(ttbuf)); + } else if (codage==BCODAGE) { + xbuf=xstrcat(xbuf,b64_decode(ttbuf)); + } + } else { /* not coded */ +// Syslog('N', "hdrconv not coded 1"); + *ttbuf=*iptr; +// Syslog('N', "hdrconv not coded 2"); + *(ttbuf+1)='\0'; +// Syslog('N', "hdrconv not coded 3"); + xbuf=xstrcat(xbuf,ttbuf); +// Syslog('N', "hdrconv not coded 4"); + iptr++; +// Syslog('N', "hdrconv not coded 5"); + } + } +// Syslog('N', "hdrconv call strkconv"); + buf=strkconv(xbuf, incode, outcode); +// Syslog('N', "hdrconv return"); + return buf; +} + diff --git a/lib/charconv_hz.c b/lib/charconv_hz.c new file mode 100644 index 00000000..93f2545d --- /dev/null +++ b/lib/charconv_hz.c @@ -0,0 +1,482 @@ +/***************************************************************************** + * + * File ..................: common/charconv_hz.c + * Purpose ...............: Common utilities + * Last modification date : 29-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" +#include "clcomm.h" + + +int LF2CR = FALSE; /* flag for converting ASCII to */ +int CR2LF=FALSE; /* flag for converting ASCII to */ +int pass8 = FALSE; /* flat for parsing all 8 bits of a character */ +int termStyle = FALSE; /* flag for ignoring line-continuation markers */ +int MAXLEN = 77; /* default maximum line length in the above style */ +int MINLEN = 7; /* minimum line length in the above style */ +int errorCount = 0; /* number of parsing errors detected */ + +/* + * internal functions + */ +void EOFerror(void); +void ESCerror(int c); +void GBerror(int c1,int c2); +void GBerror1(int c); +void GBtoSGB(int hi, int lo, int *hi1, int *lo1); +void mac2gb(int hi, int lo, int *hi1, int *lo1); +void dos2gb(int hi, int lo, int *hi1, int *lo1); + + +void zw2gb(char *src,char **dest) +{ + char *buf; + + buf=(char*)malloc(strlen(*dest) * sizeof(char)); + + zw2hz(src,&buf); + hz2gb(buf,dest); + + free(buf); +} + + + +void zw2hz(char *src,char **dest) +{ +/* + Copyright (C) 1989, 1992 Fung F. Lee + + zw2hz 2.0: do a straightforward conversion from a zW file into a HZ file + + This version was an update of version 1.1, because the specification of + zW had been changed by the original authors. + + Since the set of all zW files is a proper subset of the set of all + HZ (HGB) files, it is always possible to do perfect translation from + zW to HZ (HGB); but not vice versa. + * HGB - High-bit-set GB, as used in CCDOS, Macintosh System 6.0.x and later. + + As for error handling, I took the lazy approach. For example, if the + original zW file contains invalid GB codes, they will also show up in + the output HZ file, and can be detected by "hz2gb -v". + + This program is free for general distribution. +*/ + +/* As we do not want to impose any limit of line length (such as 80 characters + per line), we parse the input stream on a character by character basis, + because in the worst case, a line can be as long as a file. + Although in practice the line length (with or without soft CR marker at + its end) is likely to be about 80 characters or so, I am not sure what + the maximum line length is enforced by the zW standard, nor do I think + it is a necessary assumption for proper decoding. + */ + int c1, c2; + int ASCIImode = TRUE; + int lineStart = TRUE; + FILE *fin, *fout; + + OPENINOUTFILES(&fin,&fout,src); + + while ((c1 = fgetc(fin)) != EOF) { + if (ASCIImode) { + if (c1 == '\n') { + fputc('\n', fout); + lineStart = TRUE; + } else if (lineStart && c1 == 'z') { + c2 = fgetc(fin); + if (c2 == EOF) { + fputc(c1, fout); + break; + } + if (c2 == 'W') { + fprintf(fout, "~{"); + ASCIImode = FALSE; + } else { + fputc(c1, fout); + fputc(c2, fout); + } + lineStart = FALSE; + } else { + fputc(c1, fout); + lineStart = FALSE; + } + } else { /* GBmode */ + c2 = fgetc(fin); + if (c1 == '\n') { + ungetc(c2, fin); + fprintf(fout, "~}~\n"); /* soft CR - with line continuation */ + lineStart = TRUE; + ASCIImode = TRUE; + } else if (c2 == EOF) { + fputc(c1, fout); + break; + } else if (c1 == '#' && c2 == '\n') { + fprintf(fout, "~}\n"); /* hard CR */ + lineStart = TRUE; + ASCIImode = TRUE; + } else if (c2 == '\n') { /* This may be an invalid zW sequence, ... */ + /* anyway, for robustness, I choose ... */ + /* eat c1 */ /* c1 may be ' ' or something else */ + fprintf(fout, "~}\n"); /* hard CR */ + lineStart = TRUE; + ASCIImode = TRUE; + } else if (c1 == '#' && c2 == ' ') { + fprintf(fout, "~} ~{"); /* temporary escape and back */ + } else if (c1 == ' ') { /* 0x20?? is now for ASCII characters */ + fprintf(fout, "~}%c~{", c2); /* temporary escape and back */ + } else { /* ASSUME they are GB codes, and fix them in program hz2gb */ + fputc(c1, fout); fputc(c2, fout); + } + } + } + + CLOSEINOUTFILES(&fin,&fout,dest); +} + + + +void hz2gb(char *src,char **dest) +{ +/* + Copyright (C) 1989, 1992 Fung F. Lee + + hz2gb 2.0: convert a HZ file into a Macintosh* / CCDOS SGB file. + *For Macintosh pre-6.0.x Simplified Chinese Operating System. + Later versions use the same internal code (High-bit-set GB) as CCDOS does. + + The HZ specification does not dictate how to convert invalid HZ files, + just as the definition of a programming language usually does not specify + how a compiler should handle illegal programming constructs. + The error recovery procedure of this HZ decoder was designed after + examination of the conversion errors reported by hz2gb 1.1 of some of the + "HZ" files posted on the news group alt.chinese.text. I suspected that + most of the errors occured due to improper manual insertion of escape + sequences, and/or using invalid GB codes, such as those for "space" ($2121). + Such errors should not have occured if the files were first properly edited + as GB codes, and then converted by an HZ encoder, such as gb2hz (preferably + with the -t option.) + + To prevent some hanzi displayers from ill behaviour, the output stream + should be or should be corrected to be valid mixed ASCII and GB sequences. + + The error recovery procedure is by no means unique, and may change in the + future. Users should NOT regard the error recovery features as part of the + HZ specification. + + This program is free for general distribution. +*/ + FILE *fin, *fout; + int c1, c2, c3, c4; + int ASCIImode = TRUE; + + OPENINOUTFILES(&fin,&fout,src); + + while ((c1=fgetc(fin)) != EOF) { + if (!pass8) + c1 = CLEAN7(c1); + if (ASCIImode) { + if (c1 == '~') { + if ((c2 = fgetc(fin)) == EOF) { + EOFerror(); + break; + } + if (!pass8) + c2 = CLEAN7(c2); + switch (c2) { + case '~' : fputc('~', fout); + break; + case '{' : ASCIImode = FALSE; + break; + case '\n': /* line-continuation marker: eat it unless ... */ + if (termStyle) + fputc('\n', fout); + break; + default : ESCerror(c2); + fputc('~', fout); + fputc(c2, fout); + break; + } + } else { + if (LF2CR && c1=='\n') + c1 = '\r'; + fputc(c1, fout); + } + } else { /* GBmode */ + if (isprint(c1)) { + if ((c2 = fgetc(fin)) == EOF) { + EOFerror(); + break; + } + if (!pass8) + c2 = CLEAN7(c2); + if (isGB1(c1) && isGB2(c2)) { + GBtoSGB(c1, c2, &c3, &c4); + fputc(c3, fout); + fputc(c4, fout); + } else if (c1 == '~' && c2 == '}') { /* 0x7E7D */ + ASCIImode = TRUE; + } else if (isGB1U(c1) && isGB2(c2)) { /* 0x78?? - 0x7D?? */ + GBerror(c1, c2); /* non-standard extended code? */ + fputc(HI(BOX), fout); + fputc(LO(BOX), fout); + } else if (c1 == '~') { /* 0x7E */ + GBerror(c1, c2); /* undefined shift-out code? */ + ASCIImode = TRUE; /* safer assumption? */ + fputc(c1, fout); + fputc(c2, fout); + } else if (c1 == ' ') { /* 0x20 */ + GBerror(c1, c2); /* looks like artifacts of zwdos? */ + fputc(c2, fout); + } else if (c2 == ' ') { /* 0x20 */ + GBerror(c1, c2); /* null image looks like "sp"? */ + fputc(HI(SPACE), fout); + fputc(LO(SPACE), fout); + } else { /* isprint(c1) && !isprint(c2)) */ + GBerror(c1, c2); /* premature shift-out? */ + ASCIImode = TRUE; /* safer assumption? */ + fputc(c1, fout); + fputc(c2, fout); + } + } else { /* !isprint(c1) */ + GBerror1(c1); /* premature shift-out? */ + ASCIImode = TRUE; /* safer assumption? */ + fputc(c1, fout); + } + } + } + + CLOSEINOUTFILES(&fin,&fout,dest); +} + + + +void GBtoSGB(int hi, int lo, int *hi1, int *lo1) +{ +#ifdef DOS + *hi1 = 0x80 | hi; + *lo1 = 0x80 | lo; +#endif +#ifdef MAC + *hi1 = 0x81 + (hi - 0x21)/2; + if (hi%2 != 0) { + *lo1 = 0x40 + (lo - 0x21); + if (*lo1 >= 0x7F) + *lo1 += 1; + } else + *lo1 = 0x9F + (lo - 0x21); +#endif +} + + + +void EOFerror() +{ + errorCount++; + Syslog('m', "hz2gb: Unexpected EOF"); +} + + +void ESCerror(int c) +{ + errorCount++; + Syslog('m', "hz2gb: Invalid ASCII escape sequence:\"~%c\"", c); +} + + +void GBerror(int c1, int c2) +{ + errorCount++; + Syslog('m', "hz2gb: Invalid GB code:\"%c%c\"(0x%4x)", c1,c2, DB(c1,c2)); +} + + + +void GBerror1(int c) +{ + errorCount++; + Syslog('m', "hz2gb: Invalid GB code first byte:'%c'(0x%2x)", c, c); +} + + + +void gb2hz(char *src,char **dest) +{ +/* + Copyright (C) 1989 Fung F. Lee + + sgb2hz: convert a Macintosh/CCDOS SGB file into a HZ file. + + This program is free for general distribution. + +*/ + FILE *fin, *fout; + int c1, c2, c3, c4; +#ifdef MAC + int hi; +#endif + int GBmode = FALSE; + int len = 0; + + OPENINOUTFILES(&fin,&fout,src); + + while ((c1=fgetc(fin)) != EOF) { + if (notAscii(c1)) +#ifdef MAC + { + hi = c1 & 0xF0; + switch (hi) { + case 0x80: + case 0x90: + case 0xA0: + if (termStyle) { + if (GBmode && len>MAXLEN-5) { + fprintf(fout, "~}~\n"); + GBmode = FALSE; + len = 0; + } else if (!GBmode && len>MAXLEN-7) { + fprintf(fout, "~\n"); + GBmode = FALSE; len = 0; + } + } + if (!GBmode) { /* switch to GB mode */ + fprintf(fout, "~{"); + len += 2; + } + GBmode = TRUE; + c2 = fgetc(fin); + mac2gb(c1, c2, &c3, &c4); + fputc(c3, fout); + fputc(c4, fout); + len += 2; + break; + case 0xB0: + case 0xC0: + case 0xD0: + case 0xE0: + WriteError("gb2hz: ignored non-Ascii character: %2x\n", c1); + break; + case 0xF0: + switch (c1) { + case 0xFD: + case 0xFE: + case 0xFF: + WriteError("gb2hz: ignored non-Ascii character: %2x\n", c1); + break; + default: + c2 = fgetc(fin); + WriteError("gb2hz: ignored user defined SGB code: %2x%2x\n", c1, c2); + break; + } + } + } +#endif +#ifdef DOS + { + if (termStyle) { + if (GBmode && len>MAXLEN-5) { + fprintf(fout, "~}~\n"); + GBmode = FALSE; + len = 0; + } else if (!GBmode && len>MAXLEN-7) { + fprintf(fout, "~\n"); + GBmode = FALSE; len = 0; + } + } + if (!GBmode) { /* switch to GB mode */ + fprintf(fout, "~{"); + len += 2; + } + GBmode = TRUE; + c2 = fgetc(fin); + dos2gb(c1, c2, &c3, &c4); + fputc(c3, fout); + fputc(c4, fout); + len += 2; + } +#endif + /* c1 is ASCII */ + else { + if (GBmode) { + fprintf(fout, "~}"); + len += 2; + } + /* assert(len<=MAXLEN-1) */ + if (termStyle && (len>MAXLEN-2 || (len>MAXLEN-3 && c1=='~'))) { + fprintf(fout, "~\n"); + len = 0; + } + GBmode = FALSE; + if (CR2LF && c1=='\r') + c1 = '\n'; + fputc(c1, fout); + len++; + if (c1=='\n') + len=0; + else if (c1== '~') { + fputc('~', fout); + len++; + } + } + } + if (GBmode) + fprintf(fout, "~}"); + + CLOSEINOUTFILES(&fin,&fout,dest); +} + + + +#ifdef MAC +void mac2gb(int hi, int lo, int *hi1, int *lo1) +{ + if (lo >= 0x9F) { + *hi1 = 0x21 + (hi - 0x81) * 2 + 1; + *lo1 = 0x21 + (lo - 0x9F); + } else { + *hi1 = 0x21 + (hi - 0x81) * 2; + if (lo > 0x7F) + lo--; + *lo1 = 0x21 + (lo - 0x40); + } +} +#endif + + + +#ifdef DOS +void dos2gb(int hi, int lo, int *hi1, int *lo1) +{ + *hi1 = hi - 0x80; + *lo1 = lo - 0x80; +} +#endif + diff --git a/lib/charconv_jp.c b/lib/charconv_jp.c new file mode 100644 index 00000000..c191a5ad --- /dev/null +++ b/lib/charconv_jp.c @@ -0,0 +1,806 @@ +/***************************************************************************** + * + * File ..................: charconv_jp.c + * Purpose ...............: Common utilities + * Last modification date : 29-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + +/* ### Modified by P. Saratxaga on 26 Oct 95 ### + * This is the kcon.c taken from JE version (code from T. Tanaka) + * I've modified it to support 8bit -> 8bit transcoding in addition of + * japanese (16 bits) ones. + * Also the codings are not readen from a config file but taken from the + * charset values in Header lines. + */ + + + +void OPENINOUTFILES(FILE **in, FILE **out, char *src) +{ + *in=tmpfile(); + *out=tmpfile(); + fwrite(src, sizeof(char), strlen(src), *in); + rewind(*in); +} + + + +void CLOSEINOUTFILES(FILE **in, FILE **out,char **dest) +{ + int destlen, c; + char *p; + + rewind(*out); + for(destlen = 0; (c = fgetc(*out)) != EOF; destlen++); + rewind(*out); + if(*dest) + free(*dest); + *dest = (char *)malloc((destlen + 1) * sizeof(char)); + for(p = *dest; (c = fgetc(*out)) != EOF; p++) + *p = (char)(c & 0xff); + *p = '\0'; + fclose(*in); + fclose(*out); +} + + + +void sjis2jis(int *p1,int *p2) +{ + register unsigned char c1 = *p1; + register unsigned char c2 = *p2; + register int adjust = c2 < 159; + register int rowOffset = c1 < 160 ? 112 : 176; + register int cellOffset = adjust ? (31 + (c2 > 127)) : 126; + + *p1 = ((c1 - rowOffset) << 1) - adjust; + *p2 -= cellOffset; +} + + + +void jis2sjis(int *p1,int *p2) +{ + register unsigned char c1 = *p1; + register unsigned char c2 = *p2; + register int rowOffset = c1 < 95 ? 112 : 176; + register int cellOffset = c1 % 2 ? 31 + (c2 > 95) : 126; + + *p1 = ((c1 + 1) >> 1) + rowOffset; + *p2 = c2 + cellOffset; +} + + + +void shift2seven(char *src,char **dest,int incode,char ki[],char ko[]) +{ + int p1,p2,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case NUL : + case FF : + break; + case CR : + case NL : + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",NL); + break; + default : + if SJIS1(p1) { + p2 = fgetc(in); + if SJIS2(p2) { + sjis2jis(&p1,&p2); + if (!intwobyte) { + intwobyte = TRUE; + fprintf(out,"%c%s",ESC,ki); + } + } + fprintf(out,"%c%c",p1,p2); + } else if HANKATA(p1) { + han2zen(in,&p1,&p2,incode); + sjis2jis(&p1,&p2); + if (!intwobyte) { + intwobyte = TRUE; + fprintf(out,"%c%s",ESC,ki); + } + fprintf(out,"%c%c",p1,p2); + } else { + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",p1); + } + break; + } + } + if (intwobyte) + fprintf(out,"%c%s",ESC,ko); + CLOSEINOUTFILES(&in,&out,dest); +} + + + +void shift2euc(char *src, char **dest, int incode, int tofullsize) +{ + int p1,p2; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case CR : + case NL : + fprintf(out,"%c",NL); + break; + case NUL : + case FF : + break; + default : + if SJIS1(p1) { + p2 = fgetc(in); + if SJIS2(p2) { + sjis2jis(&p1,&p2); + p1 += 128; + p2 += 128; + } + fprintf(out,"%c%c",p1,p2); + } else if HANKATA(p1) { + if (tofullsize) { + han2zen(in,&p1,&p2,incode); + sjis2jis(&p1,&p2); + p1 += 128; + p2 += 128; + } else { + p2 = p1; + p1 = 142; + } + fprintf(out,"%c%c",p1,p2); + } else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + + + +void euc2seven(char *src,char **dest,int incode,char ki[],char ko[]) +{ + int p1,p2,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case NL : + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",p1); + break; + case FF : + break; + default : + if ISEUC(p1) { + p2 = fgetc(in); + if ISEUC(p2) { + p1 -= 128; + p2 -= 128; + if (!intwobyte) { + intwobyte = TRUE; + fprintf(out,"%c%s",ESC,ki); + } + } + fprintf(out,"%c%c",p1,p2); + } + else if (p1 == 142) { + p2 = fgetc(in); + if HANKATA(p2) { + p1 = p2; + han2zen(in,&p1,&p2,incode); + sjis2jis(&p1,&p2); + if (!intwobyte) { + intwobyte = TRUE; + fprintf(out,"%c%s",ESC,ki); + } + } + fprintf(out,"%c%c",p1,p2); + } + else { + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",p1); + } + break; + } + } + if (intwobyte) + fprintf(out,"%c%s",ESC,ko); + CLOSEINOUTFILES(&in,&out,dest); +} + + + +void euc2shift(char *src,char **dest,int incode,int tofullsize) +{ + int p1,p2; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case FF : + break; + default : + if ISEUC(p1) { + p2 = fgetc(in); + if ISEUC(p2) { + p1 -= 128; + p2 -= 128; + jis2sjis(&p1,&p2); + } + fprintf(out,"%c%c",p1,p2); + } + else if (p1 == 142) { + p2 = fgetc(in); + if HANKATA(p2) { + if (tofullsize) { + p1 = p2; + han2zen(in,&p1,&p2,incode); + fprintf(out,"%c%c",p1,p2); + } + else { + p1 = p2; + fprintf(out,"%c",p1); + } + } + else + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + + + +void euc2euc(char *src,char **dest,int incode,int tofullsize) +{ + int p1,p2; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case FF : + break; + default : + if ISEUC(p1) { + p2 = fgetc(in); + if ISEUC(p2) + fprintf(out,"%c%c",p1,p2); + } + else if (p1 == 142) { + p2 = fgetc(in); + if (HANKATA(p2) && tofullsize) { + p1 = p2; + han2zen(in,&p1,&p2,incode); + sjis2jis(&p1,&p2); + p1 += 128; + p2 += 128; + } + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + +void shift2shift(char *src,char **dest,int incode,int tofullsize) +{ + int p1,p2; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case CR : + case NL : + fprintf(out,"%c",NL); + break; + case NUL : + case FF : + break; + default : + if SJIS1(p1) { + p2 = fgetc(in); + if SJIS2(p2) + fprintf(out,"%c%c",p1,p2); + } + else if (HANKATA(p1) && tofullsize) { + han2zen(in,&p1,&p2,incode); + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + +void seven2shift(char *src,char **dest) +{ + int temp,p1,p2,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case ESC : + temp = fgetc(in); + SkipESCSeq(in,temp,&intwobyte); + break; + case NL : + if (intwobyte) + intwobyte = FALSE; + fprintf(out,"%c",p1); + break; + case FF : + break; + default : + if (intwobyte) { + p2 = fgetc(in); + jis2sjis(&p1,&p2); + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + +void seven2euc(char *src, char **dest) +{ + int temp,p1,p2,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case ESC : + temp = fgetc(in); + SkipESCSeq(in,temp,&intwobyte); + break; + case NL : + if (intwobyte) + intwobyte = FALSE; + fprintf(out,"%c",p1); + break; + case FF : + break; + default : + if (intwobyte) { + p2 = fgetc(in); + p1 += 128; + p2 += 128; + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + +void seven2seven(char *src,char **dest,char ki[],char ko[]) +{ + int temp,p1,p2,change,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case ESC : + temp = fgetc(in); + change = SkipESCSeq(in,temp,&intwobyte); + if ((intwobyte) && (change)) + fprintf(out,"%c%s",ESC,ki); + else if (change) + fprintf(out,"%c%s",ESC,ko); + break; + case NL : + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",p1); + break; + case FF : + break; + default : + if (intwobyte) { + p2 = fgetc(in); + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + if (intwobyte) + fprintf(out,"%c%s",ESC,ko); + CLOSEINOUTFILES(&in,&out,dest); +} + +void han2zen(FILE *in,int *p1,int *p2,int incode) +{ + int junk,maru,nigori; + + maru = nigori = FALSE; + if (incode == CHRS_SJIS) { + *p2 = fgetc(in); + if (*p2 == 222) { + if (ISNIGORI(*p1) || *p1 == 179) + nigori = TRUE; + else + ungetc(*p2,in); + } + else if (*p2 == 223) { + if ISMARU(*p1) + maru = TRUE; + else + ungetc(*p2,in); + } + else + ungetc(*p2,in); + } + else if (incode == CHRS_EUC_JP) { + junk = fgetc(in); + if (junk == 142) { + *p2 = fgetc(in); + if (*p2 == 222) { + if (ISNIGORI(*p1) || *p1 == 179) + nigori = TRUE; + else { + ungetc(*p2,in); + ungetc(junk,in); + } + } + else if (*p2 == 223) { + if ISMARU(*p1) + maru = TRUE; + else { + ungetc(*p2,in); + ungetc(junk,in); + } + } + else { + ungetc(*p2,in); + ungetc(junk,in); + } + } + else + ungetc(junk,in); + } + switch (*p1) { + case 161 : + *p1 = 129; + *p2 = 66; + break; + case 162 : + *p1 = 129; + *p2 = 117; + break; + case 163 : + *p1 = 129; + *p2 = 118; + break; + case 164 : + *p1 = 129; + *p2 = 65; + break; + case 165 : + *p1 = 129; + *p2 = 69; + break; + case 166 : + *p1 = 131; + *p2 = 146; + break; + case 167 : + *p1 = 131; + *p2 = 64; + break; + case 168 : + *p1 = 131; + *p2 = 66; + break; + case 169 : + *p1 = 131; + *p2 = 68; + break; + case 170 : + *p1 = 131; + *p2 = 70; + break; + case 171 : + *p1 = 131; + *p2 = 72; + break; + case 172 : + *p1 = 131; + *p2 = 131; + break; + case 173 : + *p1 = 131; + *p2 = 133; + break; + case 174 : + *p1 = 131; + *p2 = 135; + break; + case 175 : + *p1 = 131; + *p2 = 98; + break; + case 176 : + *p1 = 129; + *p2 = 91; + break; + case 177 : + *p1 = 131; + *p2 = 65; + break; + case 178 : + *p1 = 131; + *p2 = 67; + break; + case 179 : + *p1 = 131; + *p2 = 69; + break; + case 180 : + *p1 = 131; + *p2 = 71; + break; + case 181 : + *p1 = 131; + *p2 = 73; + break; + case 182 : + *p1 = 131; + *p2 = 74; + break; + case 183 : + *p1 = 131; + *p2 = 76; + break; + case 184 : + *p1 = 131; + *p2 = 78; + break; + case 185 : + *p1 = 131; + *p2 = 80; + break; + case 186 : + *p1 = 131; + *p2 = 82; + break; + case 187 : + *p1 = 131; + *p2 = 84; + break; + case 188 : + *p1 = 131; + *p2 = 86; + break; + case 189 : + *p1 = 131; + *p2 = 88; + break; + case 190 : + *p1 = 131; + *p2 = 90; + break; + case 191 : + *p1 = 131; + *p2 = 92; + break; + case 192 : + *p1 = 131; + *p2 = 94; + break; + case 193 : + *p1 = 131; + *p2 = 96; + break; + case 194 : + *p1 = 131; + *p2 = 99; + break; + case 195 : + *p1 = 131; + *p2 = 101; + break; + case 196 : + *p1 = 131; + *p2 = 103; + break; + case 197 : + *p1 = 131; + *p2 = 105; + break; + case 198 : + *p1 = 131; + *p2 = 106; + break; + case 199 : + *p1 = 131; + *p2 = 107; + break; + case 200 : + *p1 = 131; + *p2 = 108; + break; + case 201 : + *p1 = 131; + *p2 = 109; + break; + case 202 : + *p1 = 131; + *p2 = 110; + break; + case 203 : + *p1 = 131; + *p2 = 113; + break; + case 204 : + *p1 = 131; + *p2 = 116; + break; + case 205 : + *p1 = 131; + *p2 = 119; + break; + case 206 : + *p1 = 131; + *p2 = 122; + break; + case 207 : + *p1 = 131; + *p2 = 125; + break; + case 208 : + *p1 = 131; + *p2 = 126; + break; + case 209 : + *p1 = 131; + *p2 = 128; + break; + case 210 : + *p1 = 131; + *p2 = 129; + break; + case 211 : + *p1 = 131; + *p2 = 130; + break; + case 212 : + *p1 = 131; + *p2 = 132; + break; + case 213 : + *p1 = 131; + *p2 = 134; + break; + case 214 : + *p1 = 131; + *p2 = 136; + break; + case 215 : + *p1 = 131; + *p2 = 137; + break; + case 216 : + *p1 = 131; + *p2 = 138; + break; + case 217 : + *p1 = 131; + *p2 = 139; + break; + case 218 : + *p1 = 131; + *p2 = 140; + break; + case 219 : + *p1 = 131; + *p2 = 141; + break; + case 220 : + *p1 = 131; + *p2 = 143; + break; + case 221 : + *p1 = 131; + *p2 = 147; + break; + case 222 : + *p1 = 129; + *p2 = 74; + break; + case 223 : + *p1 = 129; + *p2 = 75; + break; + } + if (nigori) { + if ((*p2 >= 74 && *p2 <= 103) || (*p2 >= 110 && *p2 <= 122)) + (*p2)++; + else if (*p1 == 131 && *p2 == 69) + *p2 = 148; + } + else if (maru && *p2 >= 110 && *p2 <= 122) + *p2 += 2; +} diff --git a/lib/charconv_utf.c b/lib/charconv_utf.c new file mode 100644 index 00000000..896be839 --- /dev/null +++ b/lib/charconv_utf.c @@ -0,0 +1,267 @@ +/***************************************************************************** + * + * File ..................: charconv_utf.c + * Purpose ...............: Common utilities + * Last modification date : 29-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + +char Base_64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +/* returns numeric value from a Base64Code[] digit */ +static int index_hex2[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1,0x3e, -1, -1, -1,0x3f, + 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b, + 0x3c,0x3d, -1, -1, -1, -1, -1, -1, + -1,0x00,0x01,0x02,0x03,0x04,0x05,0x06, + 0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16, + 0x17,0x18,0x19, -1, -1, -1, -1, -1, + -1,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20, + 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30, + 0x31,0x32,0x33, -1, -1, -1, -1, -1 +}; + + + +void utf7_to_eight(char *in,char **out,int *code) +{ + int isb64,l_code=CHRS_AUTODETECT; + char *p, *q, *buf; + + buf=malloc(strlen(in)*sizeof(char)); + + isb64=0; + for (p = in, q = buf; *p != '\0';) { + + if (isb64) { /* we are in B64 encoding, that is in utf-7 */ + int bit_buffer=0; + int nbits=0; + int i,l,result,offset=0; + + /* find the lenght of the B64 string */ + l=strspn(p,Base_64Code); + for (i=0;i= 8) { + nbits -= 8; + result = ((bit_buffer >> nbits)&0xff); + /* if the charset code is unknown try to find it. + * it only works for latin1 (iso-8859-1), cyrillic, greek, + * arabic and hebrew (iso-8859-[5678]), as for other latin + * encodings it is harder, iso-8859-2 is assumed as it is + * the most common + */ + if ((l_code==CHRS_AUTODETECT) || (l_code==CHRS_ISO_8859_1)) { + if (result == 0x00) l_code=CHRS_ISO_8859_1; + else if (result == 0x01) l_code=CHRS_ISO_8859_2; + else if (result == 0x03) l_code=CHRS_ISO_8859_7; + else if (result == 0x04) l_code=CHRS_ISO_8859_5; + else if (result == 0x05) l_code=CHRS_ISO_8859_8; + else if (result == 0x06) l_code=CHRS_ISO_8859_6; + } + /* what to add to next byte to convert to iso-8859-* + * note that it doesn't work for iso-8859-{2,3,4,9,10} + * as the offset changes for almost each char + */ + if (result == 0x00) offset=0x00; + else if (result == 0x03) offset=0x30; + else if (result == 0x04) offset=0xa0; + else if (result == 0x05) offset=0x10; + else if (result == 0x06) offset=0xa0; + + /* convert to the right 8bit char by adding offset */ + if (result < 0x06) *q++ = (char)((bit_buffer & 0xff) + offset); + else *q++ = (char)(bit_buffer & 0xff); + } + } + /* end of B64 encoding */ + if (*p == '-') p++; + isb64=0; + } else if (*p == '+') { /* '+' is the beginning of a new B64 section */ + isb64=1; + p++; + } else { /* ascii encoding */ + *q++=*p++; + } + } + *q = '\0'; + + /* now we know the 8bit charset that was encoded whith utf-7, + * so ask again to see if a conversion to FTN charset is needed + */ + if (*code==CHRS_AUTODETECT || *code==CHRS_NOTSET) + *code=getoutcode(l_code); + switch (l_code) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: + switch (*code) { + case CHRS_CP437 : eight2eight(buf,out,(char *)ISO_8859_1__CP437); break; + case CHRS_CP850 : eight2eight(buf,out,(char *)ISO_8859_1__CP850); break; + case CHRS_MACINTOSH : eight2eight(buf,out,(char *)ISO_8859_1__MACINTOSH); break; + default : noconv(buf,out); break; + } + break; + case CHRS_ISO_8859_5 : + switch (*code) { + case CHRS_CP866 : eight2eight(buf,out,(char *)ISO_8859_5__CP866); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(buf,out,(char *)ISO_8859_5__KOI8); break; + case CHRS_MIK_CYR : eight2eight(buf,out,(char *)ISO_8859_5__MIK_CYR); break; + default : noconv(buf,out); break; + } + break; + case CHRS_ISO_8859_8 : + switch (*code) { + case CHRS_CP424 : eight2eight(buf,out,(char *)ISO_8859_8__CP424); break; + case CHRS_CP862 : eight2eight(buf,out,(char *)ISO_8859_8__CP862); break; + default : noconv(buf,out); break; + } + break; + default : noconv(in,out); break; + } +} + +/* + * UNICODE UTF-8 + * ------------- ------------------------------------ + * 0000 -> 007F = 7 bits = 0xxxxxxx + * 0080 -> 07FF = 11 bits = 110xxxxx 10xxxxxx + * 0800 -> FFFF = 16 bits = 1110xxxx 10xxxxxx 10xxxxxx + */ +void utf8_to_eight(char *in,char **out,int *code) +{ + int is8bit,l_code=CHRS_AUTODETECT; + char *p, *q, *buf; + + buf=malloc(strlen(in)*sizeof(char)); + + is8bit=0; + for (p = in, q = buf; *p != '\0';) { + int bit_buffer=0; + int nbits=0; + int result,offset=0; + + if ((*p & 0xff) >= 0xe0) { /* 16 bits = 1110xxxx 10xxxxxx 10xxxxxx */ + bit_buffer=((*p++ & 0xff) & 0x0f); + bit_buffer=(bit_buffer << 4); + bit_buffer+=((*p++ & 0xff) & 0xbf); + bit_buffer=(bit_buffer << 6); + bit_buffer+=((*p++ & 0xff) & 0x3f); + nbits=16; + } else if ((*p & 0xff) >= 0xc0) { /* 11 bits = 110xxxxx 10xxxxxx */ + bit_buffer=((*p++ & 0xff) & 0x2f); + bit_buffer=(bit_buffer << 6); + bit_buffer+=((*p++ & 0xff) & 0x3f); + nbits=11; + } else { /* 7 bits = 0xxxxxxx */ + bit_buffer=(*p++ & 0xff); + nbits=7; + } + + if (nbits >= 8) { + result = ((bit_buffer >> 8)&0xff); + /* if the charset code is unknown try to find it. + * it only works for latin1 (iso-8859-1), cyrillic, greek, + * arabic and hebrew (iso-8859-[5678]), as for other latin + * encodings it is harder, iso-8859-2 is assumed as it is + * the most common + */ + if ((l_code==CHRS_AUTODETECT) || (l_code==CHRS_ISO_8859_1)) { + if (result == 0x00) l_code=CHRS_ISO_8859_1; + else if (result == 0x01) l_code=CHRS_ISO_8859_2; + else if (result == 0x03) l_code=CHRS_ISO_8859_7; + else if (result == 0x04) l_code=CHRS_ISO_8859_5; + else if (result == 0x05) l_code=CHRS_ISO_8859_8; + else if (result == 0x06) l_code=CHRS_ISO_8859_6; + } + /* what to add to next byte to convert to iso-8859-* + * note that it doesn't work for iso-8859-{2,3,4,9,10} + * as the offset changes for almost each char + */ + if (result == 0x00) offset=0x00; + else if (result == 0x03) offset=0x30; + else if (result == 0x04) offset=0xa0; + else if (result == 0x05) offset=0x10; + else if (result == 0x06) offset=0xa0; + /* convert to the right 8bit char by adding offset */ + if (result < 0x06) *q++ = (char)((bit_buffer & 0xff) + offset); + else *q++ = (char)(bit_buffer & 0xff); + } else { /* ascii encoding */ + *q++ = (char)(bit_buffer & 0xff); + } + } + *q = '\0'; + /* now we know the 8bit charset that was encoded whith utf-7, + * so ask again to see if a conversion to FTN charset is needed + */ + if (*code==CHRS_AUTODETECT || *code==CHRS_NOTSET) + *code=getoutcode(l_code); + switch (l_code) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: + switch (*code) { + case CHRS_CP437 : eight2eight(buf,out,(char *)ISO_8859_1__CP437); break; + case CHRS_CP850 : eight2eight(buf,out,(char *)ISO_8859_1__CP850); break; + case CHRS_MACINTOSH : eight2eight(buf,out,(char *)ISO_8859_1__MACINTOSH); break; + default : noconv(buf,out); break; + } + break; + case CHRS_ISO_8859_5 : + switch (*code) { + case CHRS_CP866 : eight2eight(buf,out,(char *)ISO_8859_5__CP866); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(buf,out,(char *)ISO_8859_5__KOI8); break; + case CHRS_MIK_CYR : eight2eight(buf,out,(char *)ISO_8859_5__MIK_CYR); break; + default : noconv(buf,out); break; + } + break; + case CHRS_ISO_8859_8 : + switch (*code) { + case CHRS_CP424 : eight2eight(buf,out,(char *)ISO_8859_8__CP424); break; + case CHRS_CP862 : eight2eight(buf,out,(char *)ISO_8859_8__CP862); break; + default : noconv(buf,out); break; + } + break; + default : noconv(in,out); break; + } +} + + diff --git a/lib/charset.c b/lib/charset.c new file mode 100644 index 00000000..d60d5411 --- /dev/null +++ b/lib/charset.c @@ -0,0 +1,424 @@ +/***************************************************************************** + * + * File ..................: charset.c + * Purpose ...............: Common utilities + * Last modification date : 09-Sep-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" +#include "clcomm.h" + + +/* ### Created by P.Saratxaga on 7 Nov 1995 ### + * Functions for charset reading + * - bugfix for bad Content-Type lines lacking ";". By Marc Schaeffer. + */ + +int defaultrfcchar = CHRS_DEFAULT_RFC; +int defaultftnchar = CHRS_DEFAULT_FTN; +int toftnchar = CHRS_NOTSET; + + +//#ifndef HAVE_STRCASESTR +//char *strcasestr(char *, char *); +//#endif + + +/* tailor getoutcode() and getincode() to show your transcodage preferences */ + +int getoutcode(int code) /* rfc -> FTN */ +{ + if ((code==CHRS_MACINTOSH) && (toftnchar!=CHRS_NOTSET)) + return toftnchar; + else if (code==CHRS_MACINTOSH) return CHRS_ISO_8859_1; + else if ((toftnchar!=CHRS_NOTSET) && (code==defaultrfcchar)) + return toftnchar; + else if (code==CHRS_UTF_7||code==CHRS_UTF_8) return CHRS_AUTODETECT; + else if (code==CHRS_ZW) return CHRS_GB; + else return code; +} + + + +int getincode(int code) /* FTN -> rfc */ +{ + if (code==CHRS_CP437) return CHRS_ISO_8859_1; + else if (code==CHRS_CP850) return CHRS_ISO_8859_1; + else if (code==CHRS_CP852) return CHRS_ISO_8859_2; + else if (code==CHRS_CP862) return CHRS_ISO_8859_8; + else if (code==CHRS_CP866) return CHRS_KOI8_R; + else if (code==CHRS_CP895) return CHRS_ISO_8859_2; + else if (code==CHRS_EUC_JP) return CHRS_ISO_2022_JP; +/* else if (code==CHRS_EUC_KR) return CHRS_ISO_2022_KR; */ + else if (code==CHRS_FIDOMAZOVIA) return CHRS_ISO_8859_2; + else if (code==CHRS_ISO_11) return CHRS_ISO_8859_1; + else if (code==CHRS_ISO_4) return CHRS_ISO_8859_1; + else if (code==CHRS_ISO_60) return CHRS_ISO_8859_1; + else if (code==CHRS_ISO_8859_1_QP) return CHRS_ISO_8859_1_QP; + else if (code==CHRS_MACINTOSH) return CHRS_ISO_8859_1; + else if (code==CHRS_MIK_CYR) return CHRS_ISO_8859_5; + else if (code==CHRS_SJIS) return CHRS_ISO_2022_JP; + else if (code==defaultftnchar) return CHRS_AUTODETECT; + else return code; +} + + + +char *getcharset(int code) +{ + char *charset; + + if (code==CHRS_ASCII) charset=(char *)"us-ascii"; + else if (code==CHRS_BIG5) charset=(char *)"x-CN-Big5"; + else if (code==CHRS_CP424) charset=(char *)"x-cp424"; + else if (code==CHRS_CP437) charset=(char *)"x-cp437"; + else if (code==CHRS_CP850) charset=(char *)"x-cp850"; + else if (code==CHRS_CP852) charset=(char *)"x-cp852"; + else if (code==CHRS_CP862) charset=(char *)"x-cp862"; + else if (code==CHRS_CP866) charset=(char *)"x-cp866"; + else if (code==CHRS_CP895) charset=(char *)"x-cp895"; + else if (code==CHRS_EUC_JP) charset=(char *)"EUC-jp"; + else if (code==CHRS_EUC_KR) charset=(char *)"EUC-kr"; + else if (code==CHRS_FIDOMAZOVIA) charset=(char *)"x-FIDOMAZOVIA"; + else if (code==CHRS_GB) charset=(char *)"x-CN-GB"; + else if (code==CHRS_HZ) charset=(char *)"x-HZ"; + else if (code==CHRS_ISO_2022_CN) charset=(char *)"iso-2022-cn"; + else if (code==CHRS_ISO_2022_JP) charset=(char *)"iso-2022-jp"; + else if (code==CHRS_ISO_2022_KR) charset=(char *)"iso-2022-kr"; + else if (code==CHRS_ISO_2022_TW) charset=(char *)"iso-2022-tw"; + else if (code==CHRS_ISO_8859_1) charset=(char *)"iso-8859-1"; + else if (code==CHRS_ISO_8859_1_QP) charset=(char *)"iso-8859-1"; + else if (code==CHRS_ISO_8859_2) charset=(char *)"iso-8859-2"; + else if (code==CHRS_ISO_8859_3) charset=(char *)"iso-8859-3"; + else if (code==CHRS_ISO_8859_4) charset=(char *)"iso-8859-4"; + else if (code==CHRS_ISO_8859_5) charset=(char *)"iso-8859-5"; + else if (code==CHRS_ISO_8859_6) charset=(char *)"iso-8859-6"; + else if (code==CHRS_ISO_8859_7) charset=(char *)"iso-8859-7"; + else if (code==CHRS_ISO_8859_8) charset=(char *)"iso-8859-8"; + else if (code==CHRS_ISO_8859_9) charset=(char *)"iso-8859-5"; + else if (code==CHRS_ISO_8859_10) charset=(char *)"iso-8859-10"; + else if (code==CHRS_ISO_8859_11) charset=(char *)"iso-8859-11"; + else if (code==CHRS_ISO_8859_15) charset=(char *)"iso-8859-15"; + else if (code==CHRS_KOI8_R) charset=(char *)"koi8-r"; + else if (code==CHRS_KOI8_U) charset=(char *)"koi8-u"; + else if (code==CHRS_MACINTOSH) charset=(char *)"x-mac-roman"; + else if (code==CHRS_MIK_CYR) charset=(char *)"x-mik-cyr"; + else if (code==CHRS_NEC) charset=(char *)"x-NEC-JIS"; + else if (code==CHRS_SJIS) charset=(char *)"x-sjis"; + else if (code==CHRS_UTF_7) charset=(char *)"utf-7"; + else if (code==CHRS_UTF_8) charset=(char *)"utf-8"; + else if (code==CHRS_VISCII_11) charset=(char *)"viscii"; + else if (code==CHRS_ZW) charset=(char *)"x-zW"; + else charset=(char *)"us-ascii"; /* mime default */ + + return charset; +} + + + +int getcode(char *p) +{ + int code; + + while (*p && isspace(*p)) p++; + if (strncmp(p,"\"",1) == 0) p++; +/* if (strncasecmp(p,"us-ascii",8) == 0) code=CHRS_ASCII; */ +/* most newsreaders/mail user agents are misconfigured and put "us-ascii" when + in fact they use the local charset. */ + if (strncasecmp(p,"us-ascii",8) == 0) code=defaultrfcchar; + else if (strncasecmp(p,"CN-GB",5) == 0) code=CHRS_GB; + else if (strncasecmp(p,"CN-Big5",7) == 0) code=CHRS_BIG5; + else if (strncasecmp(p,"EUC-jp",6) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"EUC-kr",6) == 0) code=CHRS_EUC_KR; + else if (strncasecmp(p,"iso-2022-cn",11) == 0) code=CHRS_ISO_2022_CN; + else if (strncasecmp(p,"iso-2022-jp",11) == 0) code=CHRS_ISO_2022_JP; + else if (strncasecmp(p,"iso-2022-kr",11) == 0) code=CHRS_ISO_2022_KR; + else if (strncasecmp(p,"iso-2022-tw",11) == 0) code=CHRS_ISO_2022_TW; + else if (strncasecmp(p,"iso8859-1",9) == 0) code = CHRS_ISO_8859_1; /* erroneous iso8859-1 */ + else if (strncasecmp(p,"iso-8859-10",11) == 0) code=CHRS_ISO_8859_10; + else if (strncasecmp(p,"iso-8859-11",11) == 0) code=CHRS_ISO_8859_11; + else if (strncasecmp(p,"iso-8859-15",11) == 0) code=CHRS_ISO_8859_15; + else if (strncasecmp(p,"iso-8859-1",10) == 0) code = CHRS_ISO_8859_1; + else if (strncasecmp(p,"iso-8859-2",10) == 0) code=CHRS_ISO_8859_2; + else if (strncasecmp(p,"iso-8859-3",10) == 0) code=CHRS_ISO_8859_3; + else if (strncasecmp(p,"iso-8859-4",10) == 0) code=CHRS_ISO_8859_4; + else if (strncasecmp(p,"iso-8859-5",10) == 0) code=CHRS_ISO_8859_5; + else if (strncasecmp(p,"iso-8859-6",10) == 0) code=CHRS_ISO_8859_6; + else if (strncasecmp(p,"iso-8859-7",10) == 0) code=CHRS_ISO_8859_7; + else if (strncasecmp(p,"iso-8859-8",10) == 0) code=CHRS_ISO_8859_8; + else if (strncasecmp(p,"iso-8859-9",10) == 0) code=CHRS_ISO_8859_9; + else if (strncasecmp(p,"koi8-r",6) == 0) code=CHRS_KOI8_R; + else if (strncasecmp(p,"koi8-u",6) == 0) code=CHRS_KOI8_U; + else if (strncasecmp(p,"macintosh",9) == 0) code=CHRS_MACINTOSH; + else if (strncasecmp(p,"Shift_JIS",9) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"utf-7",5) == 0) code=CHRS_UTF_7; + else if (strncasecmp(p,"utf-8",5) == 0) code=CHRS_UTF_8; + else if (strncasecmp(p,"viscii",6) == 0) code=CHRS_VISCII_11; + else if (strncasecmp(p,"x-cp424",7) == 0) code=CHRS_CP424; + else if (strncasecmp(p,"x-cp437",7) == 0) code=CHRS_CP437; + else if (strncasecmp(p,"x-cp850",7) == 0) code=CHRS_CP850; + else if (strncasecmp(p,"x-cp852",7) == 0) code=CHRS_CP852; + else if (strncasecmp(p,"x-cp862",7) == 0) code=CHRS_CP862; + else if (strncasecmp(p,"x-cp866",7) == 0) code=CHRS_CP866; + else if (strncasecmp(p,"x-cp895",7) == 0) code=CHRS_CP895; + else if (strncasecmp(p,"x-CN-GB",7) == 0) code=CHRS_GB; + else if (strncasecmp(p,"x-CN-Big5",9) == 0) code=CHRS_BIG5; + else if (strncasecmp(p,"x-EUC-jp",8) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"x-FIDOMAZ",9) == 0) code=CHRS_FIDOMAZOVIA; + else if (strncasecmp(p,"x-gb2312",8) == 0) code=CHRS_GB; + else if (strncasecmp(p,"x-HZ",4) == 0) code=CHRS_HZ; + else if (strncasecmp(p,"x-mac-roman",11) == 0) code=CHRS_MACINTOSH; + else if (strncasecmp(p,"x-MAZOVIA",9) == 0) code=CHRS_FIDOMAZOVIA; + else if (strncasecmp(p,"x-mik",5) == 0) code=CHRS_MIK_CYR; + else if (strncasecmp(p,"x-NEC-JIS",9) == 0) code=CHRS_NEC; + else if (strncasecmp(p,"x-Shift-JIS",11) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"x-sjis",6) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"x-tis620",8) == 0) code=CHRS_ISO_8859_11; + else if (strncasecmp(p,"x-x-big5",8) == 0) code=CHRS_BIG5; + else if (strncasecmp(p,"x-zW",4) == 0) code=CHRS_ZW; + /* only intended to be in Areas file. So we can try to found the + * from the values of chars in message itself */ + else if (strncasecmp(p,"AUTODETECT",10) == 0) code=CHRS_AUTODETECT; + else if (strncasecmp(p,"default",7) == 0) code=CHRS_NOTSET; + else { code=CHRS_NOTSET; Syslog('+', "Unknown charset: %s",p); } + return code; +} + + + +int readcharset(char *p) +{ + int code; + + if (!strchr(p, ';')) /* foolproof MSC96 */ + return CHRS_NOTSET; + else if ((strcasestr(p,(char *)"text/plain")) && (strcasestr(p,(char *)"charset="))) + code=getcode(strcasestr(strchr(p,';'),(char *)"charset=")+8); + else if ((strcasestr(p,(char *)"text/html")) && (strcasestr(p,(char *)"charset="))) + code=getcode(strcasestr(strchr(p,';'),(char *)"charset=")+8); + else code=CHRS_NOTSET; + return code; +} + + + +/* readchrs() is also used to read outcode in Areas file (if JE defined) */ + +int readchrs(char *p) +{ + int code; + + while (*p && isspace(*p)) p++; + if (strncasecmp(p,"8859",4) == 0) code=CHRS_ISO_8859_1; + /* for X-FTN-CODEPAGE: */ + else if (strncasecmp(p,"437",3) == 0) code=CHRS_CP437; + else if (strncasecmp(p,"850",3) == 0) code=CHRS_CP850; + else if (strncasecmp(p,"Arabic",6) == 0) code=CHRS_ISO_8859_6; + else if (strncasecmp(p,"ASCII",5) == 0) code=CHRS_ASCII; + else if (strncasecmp(p,"BIG",3) == 0) code=CHRS_BIG5; + else if (strncasecmp(p,"CP 852",6) == 0) code=CHRS_CP852; + else if (strncasecmp(p,"CP424",5) == 0) code=CHRS_CP424; + else if (strncasecmp(p,"CP437",5) == 0) code=CHRS_CP437; + else if (strncasecmp(p,"CP850",5) == 0) code=CHRS_CP850; + else if (strncasecmp(p,"CP852",5) == 0) code=CHRS_CP852; + else if (strncasecmp(p,"CP862",5) == 0) code=CHRS_CP862; + else if (strncasecmp(p,"CP866",5) == 0) code=CHRS_CP866; /* ??? */ + else if (strncasecmp(p,"CP895",5) == 0) code=CHRS_CP895; + else if (strncasecmp(p,"CP932",5) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"CP942",5) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"Cyrillic",8) == 0) code=CHRS_ISO_8859_5; + else if (strncasecmp(p,"EUC-JP",6) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"EUC-KR",6) == 0) code=CHRS_EUC_KR; + else if (strncasecmp(p,"EUC",3) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"FIDOMAZ",7) == 0) code=CHRS_FIDOMAZOVIA; + else if (strncasecmp(p,"GB",2) == 0) code=CHRS_GB; + else if (strncasecmp(p,"Greek",5) == 0) code=CHRS_ISO_8859_7; + else if (strncasecmp(p,"Hebrew",6) == 0) code=CHRS_ISO_8859_8; + else if (strncasecmp(p,"HZ",2) == 0) code=CHRS_HZ; + /* Some FTN programs are misconfigured and use "IBMPC 2" kludge + * for the local DOS charset, even if it is DOS cyrillic or other + * so we will assume defaultftnchar here + */ + else if (strncasecmp(p,"IBMPC",5) == 0) code=defaultftnchar; + else if (strncasecmp(p,"IBM",3) == 0) code=CHRS_CP437; /* "IBMPC 1" "IBMPC 2" "IBM CMP" */ + else if (strncasecmp(p,"ISO-11",6) == 0) code=CHRS_ISO_11; + else if (strncasecmp(p,"ISO-2022-CN",11) == 0) code=CHRS_ISO_2022_CN; + else if (strncasecmp(p,"ISO-2022-KR",11) == 0) code=CHRS_ISO_2022_KR; + else if (strncasecmp(p,"ISO-2022-TW",11) == 0) code=CHRS_ISO_2022_TW; + else if (strncasecmp(p,"ISO-4",5) == 0) code=CHRS_ISO_4; + else if (strncasecmp(p,"ISO-60",6) == 0) code=CHRS_ISO_60; + else if (strncasecmp(p,"ISO-8859",8) == 0) code=CHRS_ISO_8859_1; + else if (strncasecmp(p,"JIS",3) == 0) code=CHRS_ISO_2022_JP; /* ??? - JE */ + else if (strncasecmp(p,"Kanji",5) == 0) code=CHRS_ISO_2022_JP; + else if (strncasecmp(p,"KOI8-R",6) == 0) code=CHRS_KOI8_R; + else if (strncasecmp(p,"KOI8-U",6) == 0) code=CHRS_KOI8_U; + else if (strncasecmp(p,"KOI8",4) == 0) code=CHRS_KOI8_R; + else if (strncasecmp(p,"LATIN-0",7) == 0) code=CHRS_ISO_8859_15; + else if (strncasecmp(p,"LATIN1QP",8) == 0) code=CHRS_ISO_8859_1_QP; + else if (strncasecmp(p,"LATIN-1",7) == 0) code=CHRS_ISO_8859_1; + else if (strncasecmp(p,"Latin-2",7) == 0) code=CHRS_ISO_8859_2; + else if (strncasecmp(p,"Latin-3",7) == 0) code=CHRS_ISO_8859_3; + else if (strncasecmp(p,"Latin-4",7) == 0) code=CHRS_ISO_8859_4; + else if (strncasecmp(p,"Latin-5",7) == 0) code=CHRS_ISO_8859_9; + else if (strncasecmp(p,"Latin-6",7) == 0) code=CHRS_ISO_8859_10; + else if (strncasecmp(p,"MAC",3) == 0) code=CHRS_MACINTOSH; + else if (strncasecmp(p,"MIK",3) == 0) code=CHRS_MIK_CYR; + else if (strncasecmp(p,"MAZOVIA",7) == 0) code=CHRS_FIDOMAZOVIA; + else if (strncasecmp(p,"NEC",3) == 0) code=CHRS_NEC; /* ??? - JE */ + else if (strncasecmp(p,"PC-8",4) == 0) code=CHRS_CP437; + else if (strncasecmp(p,"SJIS",4) == 0) code=CHRS_SJIS; /* ??? - JE */ + else if (strncasecmp(p,"Thai",4) == 0) code=CHRS_ISO_8859_11; + else if (strncasecmp(p,"UJIS",4) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"UTF-7",5) == 0) code=CHRS_UTF_7; + else if (strncasecmp(p,"UTF-8",5) == 0) code=CHRS_UTF_8; + else if (strncasecmp(p,"VISCII",6) == 0) code=CHRS_VISCII_11; + else if (strncasecmp(p,"ZW",2) == 0) code=CHRS_ZW; + /* only intended to be in Areas file. So we can try to found the + * from the values of chars in message itself */ + else if (strncasecmp(p,"AUTODETECT",10) == 0) code=CHRS_AUTODETECT; + else if (strncasecmp(p,"default",7) == 0) code=CHRS_NOTSET; + else { code=CHRS_NOTSET; Syslog('+', "Unknown CHRS: %s",p); } + return code; +/* if you know of other CHRS: values which are in use, let me know so I can + include them. Mail me to srtxg@chanae.alphanet.ch or srtxg (2:293/2219) */ +} + + + + +char *getchrs(int code) +{ + char *chrs=NULL; + + if (code == CHRS_ASCII) chrs=(char *)"ASCII 2"; + else if (code == CHRS_BIG5) chrs=(char *)"BIG5"; /* ??? */ + else if (code == CHRS_CP424) chrs=(char *)"CP424"; /* ??? */ + else if (code == CHRS_CP437) chrs=(char *)"IBMPC 2"; + else if (code == CHRS_CP850) chrs=(char *)"CP850 2"; + else if (code == CHRS_CP852) chrs=(char *)"CP852"; /* ??? */ + else if (code == CHRS_CP862) chrs=(char *)"CP862"; /* ??? */ + else if (code == CHRS_CP866) chrs=(char *)"CP866"; + else if (code == CHRS_CP895) chrs=(char *)"CP895 2"; + else if (code == CHRS_EUC_JP) chrs=(char *)"UJIS"; /* ??? */ + else if (code == CHRS_EUC_KR) chrs=(char *)"EUC-KR"; /* ??? */ + else if (code == CHRS_FIDOMAZOVIA) chrs=(char *)"FIDOMAZ 2"; + else if (code == CHRS_GB) chrs=(char *)"GB"; /* ??? */ + else if (code == CHRS_HZ) chrs=(char *)"HZ 2"; /* ??? */ + else if (code == CHRS_ISO_2022_CN) chrs=(char *)"ISO-2022-CN"; /* ??? */ + else if (code == CHRS_ISO_2022_JP) chrs=(char *)"JIS"; + else if (code == CHRS_ISO_2022_KR) chrs=(char *)"ISO-2022-KR"; /* ??? */ + else if (code == CHRS_ISO_2022_TW) chrs=(char *)"ISO-2022-TW"; /* ??? */ + else if (code == CHRS_ISO_8859_1) chrs=(char *)"LATIN-1 2"; + else if (code == CHRS_ISO_8859_1_QP) chrs=(char *)"LATIN-1 2"; + else if (code == CHRS_ISO_8859_2) chrs=(char *)"Latin-2 3"; + else if (code == CHRS_ISO_8859_3) chrs=(char *)"Latin-3 3"; + else if (code == CHRS_ISO_8859_4) chrs=(char *)"Latin-4 3"; + else if (code == CHRS_ISO_8859_5) chrs=(char *)"Cyrillic 3"; /* ??? */ + else if (code == CHRS_ISO_8859_6) chrs=(char *)"Arabic 3"; /* ??? */ + else if (code == CHRS_ISO_8859_7) chrs=(char *)"Greek 3"; /* ??? */ + else if (code == CHRS_ISO_8859_8) chrs=(char *)"Hebrew 3"; /* ??? */ + else if (code == CHRS_ISO_8859_9) chrs=(char *)"Latin-5 3"; + else if (code == CHRS_ISO_8859_10) chrs=(char *)"Latin-6 3"; + else if (code == CHRS_ISO_8859_11) chrs=(char *)"Thai 3"; + else if (code == CHRS_ISO_8859_15) chrs=(char *)"LATIN-0 2"; + else if (code == CHRS_KOI8_R) chrs=(char *)"KOI8-R"; /* ??? */ + else if (code == CHRS_KOI8_U) chrs=(char *)"KOI8-U"; /* ??? */ + else if (code == CHRS_MACINTOSH) chrs=(char *)"MAC 2"; + else if (code == CHRS_MIK_CYR) chrs=(char *)"MIK-CYR"; + else if (code == CHRS_NEC) chrs=(char *)"NEC-JIS"; /* ??? */ + else if (code == CHRS_SJIS) chrs=(char *)"SJIS"; /* ??? */ + else if (code == CHRS_UTF_7) chrs=(char *)"UTF-7"; + else if (code == CHRS_UTF_8) chrs=(char *)"UTF-8"; + else if (code == CHRS_VISCII_11) chrs=(char *)"VISCII 3"; + else if (code == CHRS_ZW) chrs=(char *)"ZW"; /* ??? */ + else chrs=NULL; + + return chrs; +} + + + +void writechrs(int code, FILE *pkt, int ispkt) +{ + char *akludge,*endline,*chrs=NULL; + + akludge = endline = NULL; + + if (ispkt==0) { + akludge=(char *)"X-FTN-"; endline=(char *)"\n"; + } else if (ispkt==1) { + akludge=(char *)"\1"; endline=(char *)"\r"; + } else if (ispkt==2) { + akludge=(char *)"X-FTN-ORIG"; endline=(char *)"\n"; + } else if (ispkt==3) { + akludge=(char *)"\1"; endline=(char *)"\n"; + } + chrs=getchrs(code); + if (chrs) fprintf(pkt,"%sCHRS: %s%s",akludge,chrs,endline); +} + + +// WORDT NIET GEBRUIKT ?? +void writecharset(int code, FILE *pip, rfcmsg *msg, rfcmsg *kmsg) +{ + char *p, *charset=NULL; + + charset=getcharset(code); + + if ((p=hdr((char *)"Mime-Version",msg))) fprintf(pip,(char *)"Mime-Version:%s",p); + else if ((p=hdr((char *)"RFC-Mime-Version",kmsg))) fprintf(pip,(char *)"Mime-Version: %s",p); + else if ((p=hdr((char *)"Mime-Version",kmsg))) fprintf(pip,(char *)"Mime-Version: %s",p); + else if ((charset) && (code != CHRS_NOTSET)) fprintf(pip,"Mime-Version: 1.0\n"); + + if ((p=hdr((char *)"Content-Type",msg))) fprintf(pip,"Content-Type:%s",p); + else if ((p=hdr((char *)"RFC-Content-Type",kmsg))) fprintf(pip,"Content-Type: %s",p); + else if ((p=hdr((char *)"Content-Type",kmsg))) fprintf(pip,"Content-Type: %s",p); + else if ((charset) && (code != CHRS_NOTSET)) + { + if ((p=hdr((char *)"FSCHTML",kmsg)) || (p=hdr((char *)"HTML",kmsg))) + fprintf(pip,"Content-Type: text/html; charset=%s\n",charset); + else + fprintf(pip,"Content-Type: text/plain; charset=%s\n",charset); + } + + if ((p=hdr((char *)"Content-Length",msg))) fprintf(pip,"Content-Length%s",p); + else if ((p=hdr((char *)"RFC-Content-Length",kmsg))) fprintf(pip,"Content-Length: %s",p); + else if ((p=hdr((char *)"Content-Length",kmsg))) fprintf(pip,"Content-Length: %s",p); + + if ((p=hdr((char *)"Content-Transfer-Encoding",msg))) fprintf(pip,"Content-Transfer-Encoding:%s",p); + else if ((p=hdr((char *)"RFC-Content-Transfer-Encoding",kmsg))) fprintf(pip,"Content-Transfer-Encoding: %s",p); + else if ((p=hdr((char *)"Content-Transfer-Encoding",kmsg))) fprintf(pip,"Content-Transfer-Encoding: %s",p); + else if ((charset) && (code == CHRS_ISO_8859_1_QP)) fprintf(pip,"Content-Transfer-Encoding: quoted-printable\n"); + else if ((charset) && (code != CHRS_NOTSET)) { fprintf(pip,"Content-Transfer-Encoding: "); + if ((code == CHRS_ASCII || code == CHRS_UTF_7)) fprintf(pip,"7bit\n"); + else if (strncasecmp(charset,"iso-2022-",9) == 0) fprintf(pip,"7bit\n"); + else fprintf(pip,"8bit\n"); /* all others are 8 bit */ + } +} + diff --git a/lib/clcomm.c b/lib/clcomm.c new file mode 100644 index 00000000..e5b9f9f3 --- /dev/null +++ b/lib/clcomm.c @@ -0,0 +1,462 @@ +/***************************************************************************** + * + * File ..................: clcomm.c + * Purpose ...............: Client/Server communications + * Last modification date : 23-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" + + +int do_quiet = FALSE; /* Quiet flag */ +int show_log = FALSE; /* Show loglines on screen */ +int most_debug = FALSE; /* Toggle normal/most debugging */ +char progname[21]; /* Program name */ +char logfile[PATH_MAX]; /* Normal logfile */ +char errfile[PATH_MAX]; /* Error logfile */ +long loggrade; /* Logging grade */ +pid_t mypid; /* Original parent pid if child */ +unsigned long lcrc = 0, tcrc = 1; /* CRC value of logstring */ +int lcnt = 0; /* Same message counter */ +static char *pbuff = NULL; +extern char cpath[108]; +extern char spath[108]; + + +char *xmalloc(size_t size) +{ + char *tmp; + + tmp = malloc(size); + if (!tmp) + abort(); + + return tmp; +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = xmalloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = xmalloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + + + + +void InitClient(char *user, char *myname, char *where, char *log, long loggr, char *err) +{ + if ((getenv("MBSE_ROOT")) == NULL) { + printf("Could not get the MBSE_ROOT environment variable\n"); + printf("Please set the environment variable ie:\n"); + printf("\"MBSE_ROOT=/opt/mbse; export MBSE_ROOT\"\n\n"); + exit(1); + } + + sprintf(progname, "%s", myname); + sprintf(logfile, "%s", log); + sprintf(errfile, "%s", err); + loggrade = loggr; + + sprintf(cpath, "%s/tmp/%s%d", getenv("MBSE_ROOT"), progname, getpid()); + sprintf(spath, "%s/tmp/mbtask", getenv("MBSE_ROOT")); + + /* + * Store my pid in case a child process is forked and wants to do + * some communications with the mbsed server. + */ + mypid = getpid(); + if (socket_connect(user, myname, where) == -1) { + printf("PANIC: cannot access socket\n"); + exit(1); + } +} + + + +void ExitClient(int errcode) +{ + if (socket_shutdown(mypid) == -1) + printf("PANIC: unable to shutdown socket\n"); + unlink(cpath); + fflush(stdout); + fflush(stdin); + + if (pbuff) + free(pbuff); + +#ifdef MEMWATCH + mwTerm(); +#endif + exit(errcode); +} + + + +void SockS(const char *format, ...) +{ + char *out; + va_list va_ptr; + + out = calloc(SS_BUFSIZE, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(out, format, va_ptr); + va_end(va_ptr); + + if (socket_send(out) == 0) + socket_receive(); + + free(out); +} + + + +char *SockR(const char *format, ...) +{ + static char buf[SS_BUFSIZE]; + char *out; + va_list va_ptr; + + memset(&buf, 0, SS_BUFSIZE); + out = calloc(SS_BUFSIZE, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(out, format, va_ptr); + va_end(va_ptr); + + if (socket_send(out) == 0) + sprintf(buf, "%s", socket_receive()); + + free(out); + return buf; +} + + + +void WriteError(const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + int i; + + outputstr = calloc(10240, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + for (i = 0; i < strlen(outputstr); i++) + if (outputstr[i] == '\r' || outputstr[i] == '\n') + outputstr[i] = ' '; + + if (*outputstr == '$') + sprintf(outputstr+strlen(outputstr), ": %s", strerror(errno)); + + if (strlen(outputstr) > (SS_BUFSIZE - 64)) { + outputstr[SS_BUFSIZE - 65] = ';'; + outputstr[SS_BUFSIZE - 64] = '\0'; + } + tcrc = StringCRC32(outputstr); + if (tcrc == lcrc) { + lcnt++; + free(outputstr); + return; + } else { + lcrc = tcrc; + if (lcnt) { + lcnt++; + SockS("ALOG:5,%s,%s,%d,?,Last message repeated %d times;", logfile, progname, mypid, lcnt); + SockS("ALOG:5,%s,%s,%d,?,Last message repeated %d times;", errfile, progname, mypid, lcnt); + } + lcnt = 0; + } + + SockS("ALOG:5,%s,%s,%d,?,%s;", logfile, progname, mypid, *outputstr == '$' ? outputstr+1 : outputstr); + SockS("ALOG:5,%s,%s,%d,?,%s;", errfile, progname, mypid, *outputstr == '$' ? outputstr+1 : outputstr); + free(outputstr); +} + + + +void Syslog(int level, const char *format, ...) +{ + char *outstr; + va_list va_ptr; + + outstr = calloc(10240, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + Syslogp(level, outstr); + free(outstr); +} + + + +void Syslogp(int level, char *outstr) +{ + long mask = 0; + int i, upper; + + upper = isupper(level); + switch(tolower(level)) { + case ' ' : mask = DLOG_ALLWAYS; break; + case '?' : mask = DLOG_ERROR; break; + case '!' : mask = DLOG_ATTENT; break; + case '+' : mask = DLOG_NORMAL; break; + case '-' : mask = DLOG_VERBOSE; break; + case 'a' : mask = DLOG_TCP; break; + case 'b' : mask = DLOG_BBS; break; + case 'c' : mask = DLOG_CHAT; break; + case 'd' : mask = DLOG_DEVIO; break; + case 'e' : mask = DLOG_EXEC; break; + case 'f' : mask = DLOG_FILEFWD; break; + case 'h' : mask = DLOG_HYDRA; break; + case 'i' : mask = DLOG_IEMSI; break; + case 'l' : mask = DLOG_LOCK; break; + case 'm' : mask = DLOG_MAIL; break; + case 'n' : mask = DLOG_NEWS; break; + case 'o' : mask = DLOG_OUTSCAN; break; + case 'p' : mask = DLOG_PACK; break; + case 'r' : mask = DLOG_ROUTE; break; + case 's' : mask = DLOG_SESSION; break; + case 't' : mask = DLOG_TTY; break; + case 'x' : mask = DLOG_XMODEM; break; + case 'z' : mask = DLOG_ZMODEM; break; + } + + if (((loggrade | DLOG_ALLWAYS | DLOG_ERROR) & mask) == 0) + return; + + /* + * Don't log uppercase debug levels when most_debug is FALSE + */ + if (upper && !most_debug) + return; + + for (i = 0; i < strlen(outstr); i++) + if (outstr[i] == '\r' || outstr[i] == '\n') + outstr[i] = ' '; + if (strlen(outstr) > (SS_BUFSIZE - 64)) + outstr[SS_BUFSIZE - 64] = '\0'; + + tcrc = StringCRC32(outstr); + if (tcrc == lcrc) { + lcnt++; + return; + } else { + lcrc = tcrc; + if (lcnt) { + lcnt++; + SockS("ALOG:5,%s,%s,%d,%c,Last message repeated %d times;", logfile, progname, mypid, level, lcnt); + } + lcnt = 0; + } + + if (show_log) + printf("%c %s\n", level, outstr); + + if (*outstr == '$') + SockS("ALOG:5,%s,%s,%d,%c,%s: %s;", logfile, progname, mypid, level, outstr+1, strerror(errno)); + else + SockS("ALOG:5,%s,%s,%d,%c,%s;", logfile, progname, mypid, level, outstr); +} + + + +void IsDoing(const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(SS_BUFSIZE, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + SockS("ADOI:2,%d,%s;", mypid, outputstr); + free(outputstr); +} + + + +void SetTTY(char *tty) +{ + SockS("ATTY:2,%d,%s;", mypid, tty); +} + + + +void UserCity(pid_t pid, char *user, char *city) +{ + SockS("AUSR:3,%d,%s,%s;", pid, user, city); +} + + + +void DoNop() +{ + SockS("GNOP:1,%d;", mypid); +} + + + +static time_t nop = 0; + +/* + * This function can be called very often but will only send once a minute + * a NOP to the server. This is a simple solution to keep server trafic low. + */ +void Nopper(void) +{ + time_t now; + + now = time(NULL); + if (((time_t)now - (time_t)nop) > 60) { + nop = now; + SockS("GNOP:1,%d;", mypid); + } +} + + + +/* + * Set new alarmtime for Client/Server connection, + * if zero set the default time. + */ +void Altime(int altime) +{ + if (altime) + SockS("ATIM:2,%d,%d;", mypid, altime); + else + SockS("ADEF:1,%d;", mypid); +} + + + +unsigned long sequencer() +{ + char *buf, *res; + unsigned long seq = 0; + + buf = calloc(SS_BUFSIZE, sizeof(char)); + sprintf(buf, "SSEQ:0;"); + + if (socket_send(buf) == 0) { + free(buf); + buf = socket_receive(); + res = strtok(buf, ","); + res = strtok(NULL, ";"); + seq = atol(res); + } + + return seq; +} + + + +char *printable(char *s, int l) +{ + int len; + char *p; + + if (pbuff) + free(pbuff); + pbuff=NULL; + + if (s == NULL) + return (char *)"(null)"; + + if (l > 0) + len=l; + else if (l == 0) + len=strlen(s); + else { + len=strlen(s); + if (len > -l) + len=-l; + } + + pbuff=(char*)xmalloc(len*4+1); + p=pbuff; + while (len--) { + if (*(unsigned char*)s >= ' ') + *p++=*s; + else switch (*s) { + case '\\': *p++='\\'; *p++='\\'; break; + case '\r': *p++='\\'; *p++='r'; break; + case '\n': *p++='\\'; *p++='n'; break; + case '\t': *p++='\\'; *p++='t'; break; + case '\b': *p++='\\'; *p++='b'; break; + default: sprintf(p,"\\%03o",*s); p+=4; break; + } + s++; + } + *p='\0'; + return pbuff; +} + + + +char *printablec(char c) +{ + return printable(&c,1); +} + + diff --git a/lib/clcomm.h b/lib/clcomm.h new file mode 100644 index 00000000..abeb62ca --- /dev/null +++ b/lib/clcomm.h @@ -0,0 +1,113 @@ +#ifndef _CLCOMM_H +#define _CLCOMM_H + + +#pragma pack(1) + +#define SS_BUFSIZE 1024 /* Socket buffersize */ +#define MBSE_SS(x) (x)?(x):"(null)" + +/* + * Logging flagbits, ' ' ? ! + - + */ +#define DLOG_ALLWAYS 0x00000001 +#define DLOG_ERROR 0x00000002 +#define DLOG_ATTENT 0x00000004 +#define DLOG_NORMAL 0x00000008 +#define DLOG_VERBOSE 0x00000010 + + + +/* + * Debug levels: A B C D E F H I L M N O P R S T X Z + */ +#define DLOG_TCP 0x00000020 +#define DLOG_BBS 0x00000040 +#define DLOG_CHAT 0x00000080 +#define DLOG_DEVIO 0x00000100 +#define DLOG_EXEC 0x00000200 +#define DLOG_FILEFWD 0x00000400 +#define DLOG_HYDRA 0x00001000 +#define DLOG_IEMSI 0x00002000 +#define DLOG_LOCK 0x00010000 +#define DLOG_MAIL 0x00020000 +#define DLOG_NEWS 0x00040000 +#define DLOG_OUTSCAN 0x00080000 +#define DLOG_PACK 0x00100000 +#define DLOG_ROUTE 0x00400000 +#define DLOG_SESSION 0x00800000 +#define DLOG_TTY 0x01000000 +#define DLOG_XMODEM 0x10000000 +#define DLOG_ZMODEM 0x40000000 + + + +typedef struct _srv_auth { + struct _srv_auth *next; + char *hostname; + char *authcode; +} srv_auth; + + +extern char SigName[32][16]; + + +/* + * From clcomm.c + */ +char *xmalloc(size_t); +char *xstrcpy(char *); +char *xstrcat(char *, char *); +void InitClient(char *, char *, char *, char *, long, char *); +void ExitClient(int); +void SockS(const char *, ...); +char *SockR(const char *, ...); +void WriteError(const char *, ...); +void Syslog(int, const char *, ...); +void Syslogp(int, char *); +void IsDoing(const char *, ...); +void SetTTY(char *); +void UserCity(pid_t, char *, char *); +void DoNop(void); +void Nopper(void); +void Altime(int); +unsigned long sequencer(void); +char *printable(char *, int); +char *printablec(char); + + + +/* + * From client.c + */ +int socket_connect(char *, char *, char *); +int socket_send(char *); +char *socket_receive(void); +int socket_shutdown(pid_t); + + + +/* + * From crc.c + */ +unsigned long crc32ccitt(char *, int); +unsigned short crc16ccitt(char *, int); +unsigned long str_crc32(char *str); +unsigned long StringCRC32(char *); +unsigned long upd_crc32(char *buf, unsigned long crc, int len); +unsigned long norm_crc32(unsigned long crc); +unsigned short crc16xmodem(char *, int); +unsigned char checksum(char *, int); + + + +/* + * from semafore.c + */ +void CreateSema(char *); +void RemoveSema(char *); +int IsSema(char *); + + +#endif + diff --git a/lib/client.c b/lib/client.c new file mode 100644 index 00000000..ed63d50a --- /dev/null +++ b/lib/client.c @@ -0,0 +1,211 @@ +/***************************************************************************** + * + * File ..................: client.c + * Purpose ...............: MBSE Deamon Client + * Last modification date : 27-May-2001 + * + ***************************************************************************** + * Copyright (C) 1993-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" + +static int sock = -1; /* Unix Datagram socket */ +struct sockaddr_un clntaddr; /* Client socket address */ +struct sockaddr_un servaddr; /* Server socket address */ +struct sockaddr_un from; /* From socket address */ +int fromlen; +static char *myname='\0'; /* my program name */ +char spath[108]; /* Server socket path */ +char cpath[108]; /* Client socket path */ + + +/************************************************************************ + * + * Connect to Unix Datagram socket, return -1 if error or socket no. + */ + +int socket_connect(char *user, char *prg, char *city) +{ + int s; + static char buf[SS_BUFSIZE]; + char tty[18]; + + myname = prg; + + /* + * Create Unix Datagram socket for the client. + */ + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s == -1) { + perror(myname); + printf("Unable to create Unix Datagram socket\n"); + return -1; + } + + /* + * Client will bind to an address so the server will get + * an address in its recvfrom call and use it to send + * data back to the client. + */ + memset(&clntaddr, 0, sizeof(clntaddr)); + clntaddr.sun_family = AF_UNIX; + strcpy(clntaddr.sun_path, cpath); + + if (bind(s, &clntaddr, sizeof(clntaddr)) < 0) { + close(s); + perror(myname); + printf("Can't bind socket %s\n", cpath); + return -1; + } + + /* + * If running seteuid as another user, chown to mbse.bbs + */ + if (getuid() != geteuid()) { + chown(cpath, getuid(), getgid()); + } + + /* + * Setup address structure for the server socket. + */ + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sun_family = AF_UNIX; + strcpy(servaddr.sun_path, spath); + + /* + * Now that we have an connection, we gather + * information to tell the server who we are. + */ + if (isatty(1) && (ttyname(1) != NULL)) { + strcpy(tty, ttyname(1)); + if (strchr(tty, 'p')) + strcpy(tty, index(tty, 'p')); + else if (strchr(tty, 't')) + strcpy(tty, index(tty, 't')); + else if (strchr(tty, 'c')) + strcpy(tty, index(tty, 'c')); + } else { + strcpy(tty, "-"); + } + sock = s; + + /* + * Send the information to the server. + */ + sprintf(buf, "AINI:5,%d,%s,%s,%s,%s;", getpid(), tty, user, prg, city); + if (socket_send(buf) != 0) { + sock = -1; + return -1; + } + + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:0;", 6) != 0) { + printf("AINI not acknowledged by the server\n"); + sock = -1; + return -1; + } + + return s; +} + + + +/* + * Send data via internet domain socket + */ +int socket_send(char *buf) +{ + if (sock == -1) + return -1; + + if (sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)) != strlen(buf)) { + printf("Socket send failed error %d\n", errno); + return -1; + } + return 0; +} + + + +/* + * Return an empty buffer if somthing went wrong, else the complete + * dataline is returned. + */ +char *socket_receive(void) +{ + static char buf[SS_BUFSIZE]; + int rlen; + + memset((char *)&buf, 0, SS_BUFSIZE); + fromlen = sizeof(from); + rlen = recvfrom(sock, buf, SS_BUFSIZE, 0, &from, &fromlen); + if (rlen == -1) { + perror("recv"); + printf("Error reading socket\n"); + memset((char *)&buf, 0, SS_BUFSIZE); + return buf; + } + return buf; +} + + + +/*************************************************************************** + * + * Shutdown the socket, first send the server the close command so this + * application will be removed from the servers active clients list. + * There must be a parameter with the pid so that client applications + * where the shutdown will be done by a child process is able to give + * the parent pid as an identifier. + */ + +int socket_shutdown(pid_t pid) +{ + static char buf[SS_BUFSIZE]; + + if (sock == -1) + return 0; + + sprintf(buf, "ACLO:1,%d;", pid); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "107:0;", 6) != 0) { + printf("Shutdown not acknowledged by the server\n"); + printf("Got \"%s\"\n", buf); + } + } + + if (shutdown(sock, 1) == -1) { + perror(myname); + printf("Cannot shutdown socket\n"); + return -1; + } + + sock = -1; + return 0; +} + + diff --git a/lib/common.h b/lib/common.h new file mode 100644 index 00000000..818f442b --- /dev/null +++ b/lib/common.h @@ -0,0 +1,914 @@ +#ifndef _COMMON_H +#define _COMMON_H + +#include "../config.h" + +#pragma pack(1) + +#define LEAVE 0 +#define KFS 1 +#define TFS 2 +#define DSF 3 + + +#define MAXNAME 35 +#define MAXUFLAGS 16 + + +#define METRIC_EQUAL 0 +#define METRIC_POINT 1 +#define METRIC_NODE 2 +#define METRIC_NET 3 +#define METRIC_ZONE 4 +#define METRIC_DOMAIN 5 +#define METRIC_MAX METRIC_DOMAIN + + + +/* + * Fidonet message status bits + */ +#define M_PVT 0x0001 +#define M_CRASH 0x0002 +#define M_RCVD 0x0004 +#define M_SENT 0x0008 +#define M_FILE 0x0010 +#define M_TRANSIT 0x0020 +#define M_ORPHAN 0x0040 +#define M_KILLSENT 0x0080 +#define M_LOCAL 0x0100 +#define M_HOLD 0x0200 +#define M_REQ 0x0800 +#define M_RRQ 0x1000 +#define M_IRR 0x2000 +#define M_AUDIT 0x4000 +#define M_FILUPD 0x8000 + + + +/* + * Analogue Modem flag values, order is important, first the + * compresion capabilities, then the linespeeds. This is late + * tested by portsel to find the fastest common connection + * speed for a given line if you have multiple dialout modems. + */ +#define NL_MNP 0x00000001L +#define NL_V42 0x00000002L +#define NL_V42B 0x00000004L +#define NL_V22 0x00000008L +#define NL_V29 0x00000010L +#define NL_V32 0x00000020L +#define NL_H96 0x00000040L +#define NL_HST 0x00000080L +#define NL_MAX 0x00000100L +#define NL_PEP 0x00000200L +#define NL_CSP 0x00000400L +#define NL_V32B 0x00000800L +#define NL_H14 0x00001000L +#define NL_V32T 0x00002000L +#define NL_H16 0x00004000L +#define NL_ZYX 0x00008000L +#define NL_Z19 0x00010000L +#define NL_VFC 0x00020000L +#define NL_V34 0x00040000L +#define NL_X2C 0x00080000L +#define NL_X2S 0x00100000L +#define NL_V90C 0x00200000L +#define NL_V90S 0x00400000L + + + +/* + * ISDN Flags + */ +#define ND_V110L 0x00000001L +#define ND_V110H 0x00000002L +#define ND_V120L 0x00000004L +#define ND_V120H 0x00000008L +#define ND_X75 0x00000010L + + + +/* + * TCP/IP flags + */ +#define IP_IBN 0x00000001L +#define IP_IFC 0x00000002L +#define IP_ITN 0x00000004L +#define IP_IVM 0x00000008L +#define IP_IP 0x00000010L +#define IP_IFT 0x00000020L + + + +/* + * Online special flags + */ +#define OL_CM 0x00000001L +#define OL_MO 0x00000002L +#define OL_LO 0x00000004L +#define OL_MN 0x00000008L + + + +/* + * Request flags + */ +#define RQ_RQMODE 0x0000000fL +#define RQ_RQ_BR 0x00000001L +#define RQ_RQ_BU 0x00000002L +#define RQ_RQ_WR 0x00000004L +#define RQ_RQ_WU 0x00000008L +#define RQ_XA (RQ_RQ_BR | RQ_RQ_BU | RQ_RQ_WR | RQ_RQ_WU) +#define RQ_XB (RQ_RQ_BR | RQ_RQ_BU | RQ_RQ_WR ) +#define RQ_XC (RQ_RQ_BR | RQ_RQ_WR | RQ_RQ_WU) +#define RQ_XP (RQ_RQ_BR | RQ_RQ_BU ) +#define RQ_XR (RQ_RQ_BR | RQ_RQ_WR ) +#define RQ_XW ( RQ_RQ_WR ) +#define RQ_XX ( RQ_RQ_WR | RQ_RQ_WU) + + + +/* + * Returned function keys + */ +#define KEY_BACKSPACE 8 +#define KEY_LINEFEED 10 +#define KEY_ENTER 13 +#define KEY_ESCAPE 27 +#define KEY_RUBOUT 127 +#define KEY_UP 200 +#define KEY_DOWN 201 +#define KEY_LEFT 202 +#define KEY_RIGHT 203 +#define KEY_HOME 204 +#define KEY_END 205 +#define KEY_INS 206 +#define KEY_DEL 207 +#define KEY_PGUP 208 +#define KEY_PGDN 209 + + +#define LINES 24 +#define COLS 80 + + +/* + * ANSI colors + */ +#define BLACK 0 +#define BLUE 1 +#define GREEN 2 +#define CYAN 3 +#define RED 4 +#define MAGENTA 5 +#define BROWN 6 +#define LIGHTGRAY 7 +#define DARKGRAY 8 +#define LIGHTBLUE 9 +#define LIGHTGREEN 10 +#define LIGHTCYAN 11 +#define LIGHTRED 12 +#define LIGHTMAGENTA 13 +#define YELLOW 14 +#define WHITE 15 + + +#define MAXSUBJ 71 +#define MSGTYPE 2 + + +/* +#define FLG_PVT 0x0001 +#define FLG_CRS 0x0002 +#define FLG_RCV 0x0004 +#define FLG_SNT 0x0008 +#define FLG_ATT 0x0010 +#define FLG_TRN 0x0020 +#define FLG_ORP 0x0040 +#define FLG_K_S 0x0080 +#define FLG_LOC 0x0100 +#define FLG_HLD 0x0200 +#define FLG_RSV 0x0400 +#define FLG_FRQ 0x0800 +#define FLG_RRQ 0x1000 +#define FLG_RRC 0x2000 +#define FLG_ARQ 0x4000 +#define FLG_FUP 0x8000 +*/ + + +typedef struct _parsedaddr { + char *target; + char *remainder; + char *comment; +} parsedaddr; + + +#define ADDR_NESTED 1 +#define ADDR_MULTIPLE 2 +#define ADDR_UNMATCHED 4 +#define ADDR_BADTOKEN 8 +#define ADDR_BADSTRUCT 16 +#define ADDR_ERRMAX 5 + +/* + * From rfcaddr.c + */ +char *addrerrstr(int); +void tidyrfcaddr(parsedaddr); +parsedaddr parserfcaddr(char *); + + +typedef struct _faddr { + char *name; + unsigned int point; + unsigned int node; + unsigned int net; + unsigned int zone; + char *domain; +} faddr; + + + +typedef struct _fa_list { + struct _fa_list *next; + faddr *addr; + int force; +} fa_list; + + + +typedef struct _ftnmsg { + int flags; + int ftnorigin; + faddr *to; + faddr *from; + time_t date; + char *subj; + char *msgid_s; + char *msgid_a; + unsigned long msgid_n; + char *reply_s; + char *reply_a; + unsigned long reply_n; + char *origin; + char *area; +} ftnmsg; + + + +extern struct _ftscprod { + unsigned short code; + char *name; +} ftscprod[]; + + + +/* + * Nodelist entry + */ +typedef struct _node { + faddr addr; /* Node address */ + unsigned short upnet; /* Uplink netnumber */ + unsigned short upnode; /* Uplink nodenumber */ + unsigned short region; /* Region belongin to */ + unsigned char type; + unsigned char pflag; + char *name; /* System name */ + char *location; /* System location */ + char *sysop; /* Sysop name */ + char *phone; /* Phone number */ + unsigned speed; /* Baudrate */ + unsigned long mflags; /* Modem flags */ + unsigned long dflags; /* ISDN flags */ + unsigned long iflags; /* TCP-IP flags */ + unsigned long oflags; /* Online flags */ + unsigned long xflags; /* Request flags */ + char *uflags[MAXUFLAGS]; /* User flags */ +} node; + + + +extern struct _fkey { + char *key; + unsigned long flag; +} fkey[]; + + + +extern struct _dkey { + char *key; + unsigned long flag; +} dkey[]; + + + +extern struct _ikey { + char *key; + unsigned long flag; +} ikey[]; + + + +extern struct _okey { + char *key; + unsigned long flag; +} okey[]; + + + +extern struct _xkey { + char *key; + unsigned long flag; +} xkey[]; + + + +extern struct _nodelist { + char *domain; + FILE *fp; +} *nodevector; + + + +struct _ixentry { + unsigned short zone; + unsigned short net; + unsigned short node; + unsigned short point; +}; + + + +extern struct _pkey { + char *key; + unsigned char type; + unsigned char pflag; +} pkey[]; + + +extern char SigName[32][16]; + + +int ttyfd; /* Filedescriptor for raw mode */ +struct termio tbuf, tbufsav; /* Structure for raw mode */ + + + +/* + * From attach.c + */ +int attach(faddr, char *, int, char); + + + +/* + * From dostran.c + */ +char *Dos2Unix(char *); +char *Unix2Dos(char *); + + + +/* + * From execute.c + */ +int execute(char *, char *, char *, char *, char *, char *); +int execsh(char *, char *, char *, char *); + + + +/* + * From expipe.c + */ +FILE *expipe(char *, char *, char *); +int exclose(FILE *); + + + +/* + * From faddr.c + */ +char *aka2str(fidoaddr aka); +fidoaddr str2aka(char *addr); + + + +/* + * From falists.c + */ +void tidy_falist(fa_list **); +void fill_list(fa_list **,char *,fa_list **, int); +void fill_path(fa_list **,char *); +void sort_list(fa_list **); +void uniq_list(fa_list **); +int in_list(faddr *,fa_list **, int); + + + + +/* + * From ftn.c + */ +faddr *parsefnode(char *); +faddr *parsefaddr(char *); +char *ascinode(faddr *,int); +char *ascfnode(faddr *,int); +void tidy_faddr(faddr *); +int metric(faddr *, faddr *); +faddr *fido2faddr(fidoaddr); +fidoaddr *faddr2fido(faddr *); +faddr *bestaka_s(faddr *); +int is_local(faddr *); +int chkftnmsgid(char *); + + + +/* + * From getheader.c + */ +int getheader(faddr *, faddr *, FILE *, char *); + + + +/* + * From gmtoffset.c + */ +long gmt_offset(time_t); +char *gmtoffset(time_t); +char *str_time(time_t); +char *t_elapsed(time_t, time_t); + + +/* + * From mbfile.c + */ +int file_cp(char *from, char *to); +int file_rm(char *path); +int file_mv(char *oldpath, char *newpath); +int file_exist(char *path, int mode); +long file_size(char *path); +long file_crc(char *path, int); +time_t file_time(char *path); +int mkdirs(char *name); +int diskfree(int); + + +/* + * From nodelist.c + */ +int initnl(void); +node *getnlent(faddr *); +void olflags(unsigned long); +void rqflags(unsigned long); +void moflags(unsigned long); +void diflags(unsigned long); +void ipflags(unsigned long); + + + +/* + * From nodelock.c + */ +int nodelock(faddr *); +int nodeulock(faddr *); + + +/* + * From noderecord.c + */ +int noderecord(faddr *); + + + +/* + * From pktname.c + */ +char *prepbuf(faddr *); +char *pktname(faddr *, char); +char *reqname(faddr *); +char *floname(faddr *, char); +char *splname(faddr *); +char *bsyname(faddr *); +char *stsname(faddr *); +char *polname(faddr *); +char *dayname(void); +char *arcname(faddr *, unsigned short, int); + + + +/* + * From rawio.c + */ +void Setraw(void); /* Set raw mode */ +void Unsetraw(void); /* Unset raw mode */ +unsigned char Getone(void); /* Get one raw character */ +int Speed(void); /* Get (locked) tty speed */ +int Waitchar(unsigned char *, int); /* Wait n * 10mSec for char */ +int Escapechar(unsigned char *); /* Escape sequence test */ +unsigned char Readkey(void); /* Read a translated key */ + + + +/* + * From strutil.c + */ +char *padleft(char *str, int size, char pad); +char *tl(char *str); +void Striplf(char *String); +void tlf(char *str); +char *tu(char *str); +char *tlcap(char *); +char *Hilite(char *, char *); +void Addunderscore(char *); +void strreplace(char *, char *, char*); +char *GetLocalHM(void); +char *StrTimeHM(time_t); +char *StrTimeHMS(time_t); +char *GetLocalHMS(void); +char *StrDateMDY(time_t *); +char *StrDateDMY(time_t); +char *GetDateDMY(void); + + + +/* + * From term.c + */ +void TermInit(int); +void Enter(int); +void pout(int, int, char *); +void poutCR(int, int, char *); +void poutCenter(int,int,char *); +void colour(int, int); +void Center(char *); +void clear(void); +void locate(int, int); +void fLine(int); +void sLine(void); +void mvprintw(int, int, const char *, ...); + + + +/* + * From unpacker.c + */ +char *unpacker(char *); +int getarchiver(char *); + + + +/* + * From packet.c + */ +FILE *openpkt(FILE *, faddr *, char); +void closepkt(void); + + + +/* + * From ftnmsg.c + */ +char *ftndate(time_t); +FILE *ftnmsghdr(ftnmsg *,FILE *,faddr *,char, char *); +void tidy_ftnmsg(ftnmsg *); + + + +/* + * From rfcdate.c + */ +time_t parsefdate(char *, void *); +char *rfcdate(time_t); + + +/* + * Frome mime.c + */ +char *qp_decode(char *); +/* int=0 for text (normal mode), int=1 for headers and gatebau MSGID */ +char *qp_encode(char *,int); +char *b64_decode(char *); +char *b64_encode(char *); + + + +/* + * From rfcmsg.c + */ + +typedef struct _rfcmsg { + struct _rfcmsg *next; + char *key; + char *val; +} rfcmsg; + +rfcmsg *parsrfc(FILE *); +void tidyrfc(rfcmsg *); +void dumpmsg(rfcmsg *,FILE *); + + +/* + * From hdr.c + */ +char *hdr(char *, rfcmsg *); + + + +/* + * From batchrd.c + */ +char *bgets(char *, int, FILE *); + + + +/* + * recognized charsets + */ +#define CHRS_AUTODETECT -1 +#define CHRS_NOTSET 0 +#define CHRS_ASCII 1 /* us-ascii */ +#define CHRS_BIG5 2 /* Chinese Big5 charset */ +#define CHRS_CP424 3 /* hebrew EBCDIC */ +#define CHRS_CP437 4 /* Latin-1 MS codage (cp437) */ +#define CHRS_CP850 5 /* Latin-1 MS codage (cp850) */ +#define CHRS_CP852 6 /* Polish MS-DOS codage */ +#define CHRS_CP862 7 /* Hebrew PC */ +#define CHRS_CP866 8 /* Cyrillic Alt-PC (cp866) */ +#define CHRS_CP895 9 /* Kamenicky (DOS charset in CZ & SK) */ +#define CHRS_EUC_JP 10 /* Japanese EUC */ +#define CHRS_EUC_KR 11 /* Korean EUC */ +#define CHRS_FIDOMAZOVIA 12 /* Polish "FIDOMAZOVIA" charset */ +#define CHRS_GB 13 /* Chinese GB 2312 8 bits */ +#define CHRS_HZ 14 /* Chinese HZ coding */ +#define CHRS_ISO_2022_CN 15 /* Chinese GB 2312 7 bits */ +#define CHRS_ISO_2022_JP 16 /* Japanese iso-2022-jp */ +#define CHRS_ISO_2022_KR 17 /* Korean iso-2022-kr */ +#define CHRS_ISO_2022_TW 18 /* Taiwanese iso-2022-tw */ +#define CHRS_ISO_8859_1 19 /* Latin-1, Western Europe, America */ +#define CHRS_ISO_8859_1_QP 20 +#define CHRS_ISO_8859_2 21 /* Latin-2, Eastern Europe */ +#define CHRS_ISO_8859_3 22 /* Latin-3, Balkanics languages */ +#define CHRS_ISO_8859_4 23 /* Latin-4, Scandinavian, Baltic */ +#define CHRS_ISO_8859_5 24 /* Cyrillic (iso-8859-5) */ +#define CHRS_ISO_8859_6 25 /* Arabic (iso-8859-6) */ +#define CHRS_ISO_8859_7 26 /* Greek (iso-8859-7) */ +#define CHRS_ISO_8859_8 27 /* Hebrew (iso-8859-8) */ +#define CHRS_ISO_8859_9 28 /* Latin-5, Turkish */ +#define CHRS_ISO_8859_10 29 /* Latin-6, Lappish/Nordic/Eskimo */ +#define CHRS_ISO_8859_11 30 /* Thai (iso-8859-11, aka TIS620) */ +#define CHRS_ISO_8859_15 31 /* Latin-0 (Latin-1 + a few letters) */ +#define CHRS_KOI8_R 32 /* Cyrillic Koi8 (Russian) */ +#define CHRS_KOI8_U 33 /* Cyrillic Koi8 (Ukranian) */ +#define CHRS_MACINTOSH 34 /* Macintosh */ +#define CHRS_MIK_CYR 35 /* Bulgarian "Mik" cyrillic charset */ +#define CHRS_NEC 36 /* Japanese NEC-JIS charset */ +#define CHRS_SJIS 37 /* Japanese Shift-JIS (MS codage) */ +#define CHRS_UTF_7 38 /* Unicode in UTF-7 encoding */ +#define CHRS_UTF_8 39 /* Unicode in UTF-8 encoding */ +#define CHRS_VISCII_10 40 /* VISCII 1.0 */ +#define CHRS_VISCII_11 41 /* VISCII 1.1 */ +#define CHRS_ZW 42 /* Chinese Zw encoding */ + +#define CHRS_ISO_11 91 +#define CHRS_ISO_4 92 +#define CHRS_ISO_60 93 + + + +/* + * languages (used for LANG_DEFAULT definition) + */ +#define LANG_WEST 1 /* West-European languages */ +#define LANG_EAST 2 /* East-Eurpean languages */ +#define LANG_JAPAN 3 /* japanese */ +#define LANG_KOREA 4 /* korean */ +#define LANG_CHINA 5 /* chinese */ +#define LANG_CYRILLIC 6 /* Cyrillic based languages */ + + + +/* + * Define these according to the values used in your country + */ +#define CHRS_DEFAULT_FTN CHRS_CP437 +#define CHRS_DEFAULT_RFC CHRS_ISO_8859_1 +#define LANG_DEFAULT LANG_WEST + +#if (LANG_DEFAULT==LANG_JAPAN || LANG_DEFAULT==LANG_KOREA || LANG_DEFAULT==LANG_CHINA) +#define LANG_BITS 16 +#else +#define LANG_BITS 8 +#endif + + + +/* + * used to recognize pgpsigned messages + */ +#define PGP_SIGNED_BEGIN "-----BEGIN PGP SIGNED MESSAGE-----" +#define PGP_SIG_BEGIN "-----BEGIN PGP SIGNATURE-----" +#define PGP_SIG_END "-----END PGP SIGNATURE-----" + + + +/* + * charset reading functions + */ +int getoutcode(int); +int getincode(int); +char *getcharset(int); +char *getchrs(int); +int getcode(char *); +int readchrs(char *); +int readcharset(char *); +void writechrs(int,FILE *,int); + + + +/* + * some special chars values + */ +#define NUL 0 +#define NL 10 +#define FF 12 +#define CR 13 +#define ESC 27 + + +/* ************ general functions ************* */ +char *hdrconv(char *, int, int); +char *hdrnconv(char *, int, int, int); +char *strnkconv(const char *, int, int, int); +char *strkconv(const char *, int, int); +void kconv(char *, char **, int, int); + + +/* ************ 8 bit charsets **************** */ +void noconv(char *, char **); +void eight2eight(char *, char **, char *); + + + +/* + * maptabs names + */ +#define CP424__CP862 "cp424__cp862" +#define CP424__ISO_8859_8 "cp424__iso-8859-8" +#define CP437__ISO_8859_1 "cp437__iso-8859-1" +#define CP437__MACINTOSH "cp437__mac" +#define CP850__ISO_8859_1 "cp437__iso-8859-1" +#define CP850__MACINTOSH "cp437__mac" +#define CP852__FIDOMAZOVIA "cp852__fidomazovia" +#define CP852__ISO_8859_2 "cp852__iso-8859-2" +#define CP862__CP424 "cp862__cp424" +#define CP862__ISO_8859_8 "cp862__iso-8859-8" +#define CP866__ISO_8859_5 "mik__iso-8859-5" +#define CP866__KOI8 "cp866__koi8" +#define CP895__CP437 "cp895__cp437" +#define CP895__ISO_8859_2 "cp895__iso-8859-2" +#define FIDOMAZOVIA__CP852 "fidomazovia__cp852" +#define FIDOMAZOVIA__ISO_8859_2 "fidomazovia__iso-8859-2" +#define ISO_11__ISO_8859_1 "iso-11__iso-8859-1" +#define ISO_4__ISO_8859_1 "iso-4__iso-8859-1" +#define ISO_60__ISO_8859_1 "iso-60__iso-8859-1" +#define ISO_8859_1__CP437 "iso-8859-1__cp437" +#define ISO_8859_1__MACINTOSH "iso-8859-1__mac" +#define ISO_8859_1__CP850 "iso-8859-1__cp437" +#define ISO_8859_2__CP852 "iso-8859-2__cp852" +#define ISO_8859_2__CP895 "iso-8859-2__cp895" +#define ISO_8859_2__FIDOMAZOVIA "iso-8859-2__fidomazovia" +#define ISO_8859_5__CP866 "iso-8859-5__mik" +#define ISO_8859_5__KOI8 "iso-8859-5__koi8" +#define ISO_8859_5__MIK_CYR "iso-8859-5__mik" +#define ISO_8859_8__CP424 "iso-8859-8__cp424" +#define ISO_8859_8__CP862 "iso-8859-8__cp862" +#define KOI8__CP866 "koi8__cp866" +#define KOI8__ISO_8859_5 "koi8__iso-8859-5" +#define KOI8__MIK_CYR "koi8__mik" +#define MACINTOSH__CP437 "mac__cp437" +#define MACINTOSH__CP850 "mac__cp437" +#define MACINTOSH__ISO_8859_1 "mac__iso-8859-1" +#define MIK_CYR__ISO_8859_5 "mik__iso-8859-5" +#define MIK_CYR__KOI8 "mik__koi8" + + +/* ??? */ +int SkipESCSeq(FILE *, int, int *); +int getkcode(int, char [],char []); +int iso2022_detectcode(char *, int); + + +#define DOS +#define SPACE 0xA1A1 /* GB "space" symbol */ +#define BOX 0xA1F5 /* GB "blank box" symbol */ +#define isGB1(c) ((c)>=0x21 && (c)<=0x77) /* GB 1st byte */ +#define isGB1U(c) ((c)>=0x78 && (c)<=0x7D) /* GB 1st byte unused*/ +#define isGB2(c) ((c)>=0x21 && (c)<=0x7E) /* GB 2nd byte */ +#define HI(code) (((code) & 0xFF00)>>8) +#define LO(code) ((code) & 0x00FF) +#define DB(hi,lo) ((((hi)&0xFF) << 8) | ((lo)&0xFF)) +#define CLEAN7(c) ((c) & 0x7F) /* strip MSB */ +#define notAscii(c) ((c)&0x80) + + +/* Chinese charsets */ +void gb2hz(char *in, char **out); +void hz2gb(char *in, char **out); +void zw2hz(char *in, char **out); +void zw2gb(char *in, char **out); + + + +#define SJIS1(A) ((A >= 129 && A <= 159) || (A >= 224 && A <= 239)) +#define SJIS2(A) (A >= 64 && A <= 252) +#define HANKATA(A) (A >= 161 && A <= 223) +#define ISEUC(A) (A >= 161 && A <= 254) +#define ISMARU(A) (A >= 202 && A <= 206) +#define ISNIGORI(A) ((A >= 182 && A <= 196) || (A >= 202 && A <= 206)) + +void OPENINOUTFILES(FILE **, FILE **, char *); +void CLOSEINOUTFILES(FILE **, FILE **, char **); +void han2zen(FILE *, int *, int *, int); +void sjis2jis(int *, int *); +void jis2sjis(int *, int *); + +/* ************ 16 bits charsets ************* */ +/* japanese charsets */ +void shift2seven(char *, char **, int, char [], char []); +void shift2euc(char *, char **, int, int); +void euc2seven(char *, char **, int, char [], char []); +void euc2euc(char *, char **, int, int); +void shift2shift(char *, char **, int, int); +void euc2shift(char *, char **, int, int); +void seven2shift(char *, char **); +void seven2euc(char *, char **); +void seven2seven(char *, char **, char [], char []); + + + +void utf7_to_eight(char *, char **, int *); +void utf8_to_eight(char *, char **, int *); + + + +/* + * parsedate.c + */ +typedef struct _TIMEINFO { + time_t time; + long usec; + long tzone; +} TIMEINFO; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +typedef union { + time_t Number; + enum _MERIDIAN Meridian; +} CYYSTYPE; + +#define tDAY 257 +#define tDAYZONE 258 +#define tMERIDIAN 259 +#define tMONTH 260 +#define tMONTH_UNIT 261 +#define tSEC_UNIT 262 +#define tSNUMBER 263 +#define tUNUMBER 264 +#define tZONE 265 + + +extern CYYSTYPE cyylval; + + +time_t parsedate(char *, TIMEINFO *); + + +/* + * msgflags.c + */ +int flag_on(char *,char *); +int flagset(char *); +char *compose_flags(int,char *); +char *strip_flags(char *); +int flag_on(char *,char *); + + + +/* + * strcasestr.c + */ +#ifndef HAVE_STRCASESTR +char *strcasestr(char *, char *); +#endif + +#endif + diff --git a/lib/crc.c b/lib/crc.c new file mode 100644 index 00000000..cf04918c --- /dev/null +++ b/lib/crc.c @@ -0,0 +1,303 @@ +/***************************************************************************** + * + * File ..................: crc.c + * Purpose ...............: Crc32 and Crc16 calculations + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1993-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" + + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* 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. */ + + +unsigned long crc32tab[] = { /* 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 +}; + + + +unsigned short crc16xmodemtab[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 +}; + + +unsigned short crc16ccitttab[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 +}; + + + +unsigned long crc32ccitt(char *str, int l) +{ + unsigned long crc; + + for (crc = 0xffffffffL; l--; str++) + crc = crc32tab[((int) crc ^ (*str)) & 0xff] ^ ((crc >> 8) & 0x00ffffff); + + return crc; +} + + + +unsigned short crc16ccitt(char *str, int l) +{ + unsigned short crc; + + for (crc = 0xffff; l--; str++) + crc = crc16ccitttab[(crc ^ (*str)) & 0xff] ^ ((crc >> 8) & 0x00ff); + + return crc; +} + + + + +/* + * Calculate the CRC of a string. + */ +unsigned long str_crc32(char *str) +{ + unsigned long crc; + + for (crc=0L; *str; str++) + crc = crc32tab[((int)crc^(*str)) & 0xff] ^ ((crc>>8) & 0x00ffffff); + return crc; +} + + + +unsigned long StringCRC32(char *str) +{ + unsigned long crc; + + for (crc = 0xffffffff; *str; str++) + crc = crc32tab[((int)crc^(*str)) & 0xff] ^ ((crc>>8) & 0x00ffffff); + return crc; +} + + + +/* + * Update CRC32, first initialize CRC with 0xffffffff. + */ +unsigned long crc32(int octet, unsigned long crc) +{ + return (crc32tab[((int)crc ^ ((long)octet)) & 0xff] ^ ((((unsigned long)crc) >> 8) & 0x00ffffff)); +} + + + +/* + * Update CRC32, first initialize crc with 0xffffffff + */ +unsigned long upd_crc32(char *buf, unsigned long crc, int len) +{ + int i; + unsigned long cr; + + cr = crc; + for (i = 0; i < len; i++) { + cr = (crc32tab[((int)cr ^ ((long)buf[i])) & 0xff] ^ ((((unsigned long)cr) >> 8) & 0x00ffffff)); + } + return cr; +} + + + +/* + * return normalized CRC32 value, which means put al bytes in the + * normal (not for comms) order. + */ +unsigned long norm_crc32(unsigned long crc) +{ + unsigned long L; + + L = crc & 0x000000ff; + L <<= 8; + L |= ((crc >> 8) & 0x000000ff); + L <<= 8; + L |= ((crc >> 16) & 0x000000ff); + L <<= 8; + L |= ((crc >> 24) & 0x000000ff); + return L; +} + + + +unsigned short crc16xmodem(char *str, int l) +{ + unsigned short crc; + + for (crc = 0; l--; str++) + crc = crc16xmodemtab[(((crc>>8)&0xff)^(*str)) & 0xff] ^ (crc<<8); + return crc; +} + + + +unsigned char checksum(char *str, int l) +{ + unsigned char cs; + + for (cs=0;l--;str++) + cs += (unsigned char)(*str); + return cs; +} + + + diff --git a/lib/dbcfg.c b/lib/dbcfg.c new file mode 100644 index 00000000..eb6f3040 --- /dev/null +++ b/lib/dbcfg.c @@ -0,0 +1,96 @@ +/***************************************************************************** + * + * File ..................: dbcfg.c + * Purpose ...............: Config Database. + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "mbse.h" +#include "structs.h" +#include "records.h" +#include "dbcfg.h" + + + + +void InitConfig(void) +{ + if ((getenv("MBSE_ROOT")) == NULL) { + printf("Could not get MBSE_ROOT environment variable\n"); + printf("Please set the environment variable ie:\n"); + printf("\"MBSE_ROOT=/opt/mbse;export MBSE_ROOT\"\n\n"); + exit(1); + } + LoadConfig(); +} + + + +void LoadConfig(void) +{ + FILE *pDataFile; + char *FileName; + + FileName = calloc(PATH_MAX, sizeof(char)); + sprintf(FileName, "%s/etc/config.data", getenv("MBSE_ROOT")); + if ((pDataFile = fopen(FileName, "r")) == NULL) { + perror("\n\nFATAL ERROR:"); + printf(" Can't open %s\n", FileName); + printf("Please run mbsetup to create configuration file.\n"); + printf("Or check that your MBSE_ROOT variable is set to the BBS path!\n\n"); + free(FileName); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + free(FileName); + fread(&CFG, sizeof(CFG), 1, pDataFile); + fclose(pDataFile); +} + + + +int IsOurAka(fidoaddr taka) +{ + int i; + + for (i = 0; i < 40; i++) { + if ((taka.zone == CFG.aka[i].zone) && + (taka.net == CFG.aka[i].net) && + (taka.node == CFG.aka[i].node) && + (taka.point == CFG.aka[i].point) && + (CFG.akavalid[i])) + return TRUE; + } + return FALSE; +} + + + diff --git a/lib/dbcfg.h b/lib/dbcfg.h new file mode 100644 index 00000000..4137fe01 --- /dev/null +++ b/lib/dbcfg.h @@ -0,0 +1,11 @@ +#ifndef _DBCFG_H +#define _DBCFG_H + + +void InitConfig(void); /* Initialize and load config */ +void LoadConfig(void); /* Only load config file */ +int IsOurAka(fidoaddr); /* Check if our aka */ + + +#endif + diff --git a/lib/dbdupe.c b/lib/dbdupe.c new file mode 100644 index 00000000..2b842e55 --- /dev/null +++ b/lib/dbdupe.c @@ -0,0 +1,183 @@ +/***************************************************************************** + * + * File ..................: dbdupe.c + * Purpose ...............: Dupe checking. + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "dbdupe.h" + + +typedef struct _dupesrec { + unsigned long *crcs; + int loaded; + int changed; + int count; + int max; + int peak; +} dupesrec; + + +dupesrec dupes[3]; +static char *files[] = {(char *)"echomail", (char *)"fileecho", (char *)"news"}; +void CloseDdb(int); + + + +void InitDupes() +{ + int i; + + for (i = 0; i < 3; i++) { + dupes[i].crcs= NULL; + dupes[i].loaded = FALSE; + dupes[i].changed = FALSE; + dupes[i].count = 0; + dupes[i].max = 0; + } +} + + + +int CheckDupe(unsigned long crc, int idx, int max) +{ + char *dfile; + FILE *fil; + unsigned long test; + int i, size = 0; + + if (!dupes[idx].loaded) { + dfile = calloc(PATH_MAX, sizeof(char)); + sprintf(dfile, "%s/etc/%s.dupe", getenv("MBSE_ROOT"), files[idx]); + if ((fil = fopen(dfile, "r+")) == NULL) { + /* + * Dupe database doesn't exist yet. + */ + if ((fil = fopen(dfile, "w")) == NULL) { + WriteError("$PANIC: dbdupe.c, can't create %s", dfile); + free(dfile); + exit(1); + } + fclose(fil); + fil = fopen(dfile, "r+"); + } else { + fseek(fil, 0L, SEEK_END); + size = ftell(fil) / sizeof(unsigned long); + fseek(fil, 0L, SEEK_SET); + } + + /* + * Reserve some extra memeory and record howmuch. + */ + if (size > max) + dupes[idx].peak = size + 5000; + else + dupes[idx].peak = max + 5000; + dupes[idx].crcs = (unsigned long *)malloc(dupes[idx].peak * sizeof(unsigned long)); + + /* + * Load dupe records + */ + while (fread(&test, sizeof(test), 1, fil) == 1) { + dupes[idx].crcs[dupes[idx].count] = test; + dupes[idx].count++; + } + fclose(fil); + free(dfile); + dupes[idx].loaded = TRUE; + dupes[idx].max = max; + } + + for (i = 0; i < dupes[idx].count; i++) { + if (dupes[idx].crcs[i] == crc) { + return TRUE; + } + } + /* + * Not a dupe, append new crc value + */ + dupes[idx].crcs[dupes[idx].count] = crc; + dupes[idx].count++; + dupes[idx].changed = TRUE; + + /* + * If we reach the high limit, flush the current dupelist. + */ + if (dupes[idx].count >= dupes[idx].peak) + CloseDdb(idx); + return FALSE; +} + + + +void CloseDdb(int idx) +{ + int j, start; + char *dfile; + FILE *fil; + + dfile = calloc(PATH_MAX, sizeof(char)); + if (dupes[idx].loaded) { + if (dupes[idx].changed) { + if (dupes[idx].count > dupes[idx].max) + start = dupes[idx].count - dupes[idx].max; + else + start = 0; + sprintf(dfile, "%s/etc/%s.dupe", getenv("MBSE_ROOT"), files[idx]); + if ((fil = fopen(dfile, "w"))) { + for (j = start; j < dupes[idx].count; j++) + fwrite(&dupes[idx].crcs[j], sizeof(unsigned long), 1, fil); + fclose(fil); + } else { + WriteError("$Can't write %s", dfile); + } + } + + dupes[idx].changed = FALSE; + dupes[idx].loaded = FALSE; + dupes[idx].count = 0; + dupes[idx].max = 0; + dupes[idx].peak = 0; + free(dupes[idx].crcs); + dupes[idx].crcs = NULL; + } + free(dfile); +} + + + +void CloseDupes() +{ + int i; + + for (i = 0; i < 3; i++) + CloseDdb(i); +} + diff --git a/lib/dbdupe.h b/lib/dbdupe.h new file mode 100644 index 00000000..5c73e460 --- /dev/null +++ b/lib/dbdupe.h @@ -0,0 +1,12 @@ +#ifndef _DBDUPE_H +#define _DBDUPE_H + +typedef enum {D_ECHOMAIL, D_FILEECHO, D_NEWS} DUPETYPE; + +void InitDupes(void); +int CheckDupe(unsigned long, int, int); +void CloseDupes(void); + +#endif + + diff --git a/lib/dbftn.c b/lib/dbftn.c new file mode 100644 index 00000000..8e61384c --- /dev/null +++ b/lib/dbftn.c @@ -0,0 +1,101 @@ +/***************************************************************************** + * + * File ..................: dbftn.c + * Purpose ...............: Fidonetrecord Access + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "dbcfg.h" +#include "dbftn.h" + + + + +int InitFidonet(void) +{ + FILE *fil; + + memset(&fidonet, 0, sizeof(fidonet)); + LoadConfig(); + + sprintf(fidonet_fil, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fil = fopen(fidonet_fil, "r")) == NULL) + return FALSE; + + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + fseek(fil, 0, SEEK_END); + fidonet_cnt = (ftell(fil) - fidonethdr.hdrsize) / fidonethdr.recsize; + fclose(fil); + + return TRUE; +} + + + +int TestFidonet(unsigned short zone) +{ + int i, ftnok = FALSE; + + for (i = 0; i < 6; i++) { + if (zone == fidonet.zone[i]) + ftnok = TRUE; + } + return(ftnok); +} + + + +int SearchFidonet(unsigned short zone) +{ + FILE *fil; + + /* + * If current record is ok, return immediatly. + */ + if (TestFidonet(zone)) + return TRUE; + + if ((fil = fopen(fidonet_fil, "r")) == NULL) { + return FALSE; + } + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + + while (fread(&fidonet, fidonethdr.recsize, 1, fil) == 1) { + if (TestFidonet(zone)) { + fclose(fil); + return TRUE; + } + } + fclose(fil); + return FALSE; +} + + + diff --git a/lib/dbftn.h b/lib/dbftn.h new file mode 100644 index 00000000..f9fce5bc --- /dev/null +++ b/lib/dbftn.h @@ -0,0 +1,16 @@ +#ifndef _DBFTN_H +#define _DBFTN_H + + +struct _fidonethdr fidonethdr; /* Header record */ +struct _fidonet fidonet; /* Fidonet datarecord */ +int fidonet_cnt; /* Fidonet records in database */ +char fidonet_fil[81];/* Fidonet database filename */ + +int InitFidonet(void); /* Initialize fidonet database */ +int TestFidonet(unsigned short); /* Test if zone is in memory */ +int SearchFidonet(unsigned short); /* Search specified zone and load */ + + +#endif + diff --git a/lib/dbmsgs.c b/lib/dbmsgs.c new file mode 100644 index 00000000..87678a8d --- /dev/null +++ b/lib/dbmsgs.c @@ -0,0 +1,357 @@ +/***************************************************************************** + * + * File ..................: dbmsgs.c + * Purpose ...............: Message areas record Access + * Last modification date : 14-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "dbcfg.h" +#include "dbmsgs.h" + + +char msgs_fil[PATH_MAX]; /* Database filename */ +char mgrp_fil[PATH_MAX]; /* Group database filename */ +long msgs_pos = -1; /* Current record position */ +long mgrp_pos = -1; /* Current group position */ +unsigned long msgs_crc = -1; /* CRC value of current record */ +unsigned long mgrp_crc = -1; /* CRC value of group record */ +static long sysstart, sysrecord; + + + +int InitMsgs(void) +{ + FILE *fil; + + memset(&msgs, 0, sizeof(msgs)); + memset(&mgroup, 0, sizeof(mgroup)); + LoadConfig(); + sysstart = -1; + + sprintf(msgs_fil, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(msgs_fil, "r")) == NULL) + return FALSE; + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + fseek(fil, 0, SEEK_END); + msgs_cnt = (ftell(fil) - msgshdr.hdrsize) / (msgshdr.recsize + msgshdr.syssize); + fclose(fil); + + sprintf(mgrp_fil, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + return TRUE; +} + + +int smsgarea(char *w, int); +int smsgarea(char *what, int newsgroup) +{ + FILE *fil; + + if ((fil = fopen(msgs_fil, "r")) == NULL) { + return FALSE; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + + while (fread(&msgs, msgshdr.recsize, 1, fil) == 1) { + /* + * Mark the start of the connected systems records + * for later use and skip the system records. + */ + msgs_pos = ftell(fil) - msgshdr.recsize; + sysstart = ftell(fil); + fseek(fil, msgshdr.syssize, SEEK_CUR); + if (((!strcmp(what, msgs.Tag) && !newsgroup) || (!strcmp(what, msgs.Newsgroup) && newsgroup)) && msgs.Active) { + sysrecord = 0; + fclose(fil); + msgs_crc = 0xffffffff; + msgs_crc = upd_crc32((char *)&msgs, msgs_crc, msgshdr.recsize); + mgrp_pos = -1; + mgrp_crc = -1; + + if (strlen(msgs.Group)) { + if ((fil = fopen(mgrp_fil, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + while ((fread(&mgroup, mgrouphdr.recsize, 1, fil)) == 1) { + if (!strcmp(msgs.Group, mgroup.Name)) { + mgrp_pos = ftell(fil) - mgrouphdr.recsize; + mgrp_crc = 0xffffffff; + mgrp_crc = upd_crc32((char *)&mgroup, mgrp_crc, mgrouphdr.recsize); + break; + } + } + fclose(fil); + } + } else + memset(&mgroup, 0, sizeof(mgroup)); + + return TRUE; + } + } + sysstart = -1; + msgs_crc = -1; + msgs_pos = -1; + fclose(fil); + return FALSE; +} + + + +int SearchMsgs(char *Area) +{ + return smsgarea(Area, FALSE); +} + + + +int SearchMsgsNews(char *Group) +{ + return smsgarea(Group, TRUE); +} + + + +/* + * Check if system is connected + */ +int MsgSystemConnected(sysconnect Sys) +{ + FILE *fil; + sysconnect T; + + if (sysstart == -1) + return FALSE; + + if ((fil = fopen(msgs_fil, "r")) == NULL) + return FALSE; + + if (fseek(fil, sysstart, SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + while (ftell(fil) != (sysstart + msgshdr.syssize)) { + fread(&T, sizeof(sysconnect), 1, fil); + if ((T.aka.zone == Sys.aka.zone) && + (T.aka.net == Sys.aka.net) && + (T.aka.node == Sys.aka.node) && + (T.aka.point == Sys.aka.point)) { + fclose(fil); + return TRUE; + } + } + + fclose(fil); + return FALSE; +} + + + +/* + * Change system's status, if the Read or Write flags are clear, + * the connection will be erased, else updated or connected. + */ +int MsgSystemConnect(sysconnect *Sys, int New) +{ + FILE *fil; + sysconnect T; + + if (sysstart == -1) + return FALSE; + + if ((fil = fopen(msgs_fil, "r+")) == NULL) + return FALSE; + + if (fseek(fil, sysstart, SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + while (ftell(fil) != (sysstart + msgshdr.syssize)) { + fread(&T, sizeof(sysconnect), 1, fil); + + /* + * For a new connection, search an empty slot. + */ + if (New && (!T.aka.zone)) { + fseek(fil, - sizeof(sysconnect), SEEK_CUR); + fwrite(Sys, sizeof(sysconnect), 1, fil); + fclose(fil); + return TRUE; + } + + /* + * If not new it is an update + */ + if ((!New) && (T.aka.zone == Sys->aka.zone) && + (T.aka.net == Sys->aka.net) && (T.aka.node == Sys->aka.node) && + (T.aka.point == Sys->aka.point)) { + fseek(fil, - sizeof(sysconnect), SEEK_CUR); + if ((!Sys->sendto) && (!Sys->receivefrom)) { + /* + * It's a deletion, if the area is mandatory or + * the node is cutoff, refuse the deletion. + */ + if (msgs.Mandatory || T.cutoff) { + fclose(fil); + return FALSE; + } + memset(&T, 0, sizeof(sysconnect)); + fwrite(&T, sizeof(sysconnect), 1, fil); + } else { + /* + * It's a update, refuse it if the node is cutoff. + */ + if (T.cutoff) { + fclose(fil); + return FALSE; + } + fwrite(Sys, sizeof(sysconnect), 1, fil); + } + fclose(fil); + return TRUE; + } + } + + fclose(fil); + return FALSE; +} + + + +int GetMsgSystem(sysconnect * Sys, int First) +{ + FILE *fil; + + memset(Sys, 0, sizeof(sysconnect)); + if (sysstart == -1) + return FALSE; + + if (First) + sysrecord = 0; + else + sysrecord++; + + if (sysrecord >= CFG.toss_systems) + return FALSE; + + if ((fil = fopen(msgs_fil, "r")) == NULL) + return FALSE; + + if (fseek(fil, sysstart + (sysrecord * sizeof(sysconnect)), SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + if (fread(Sys, sizeof(sysconnect), 1, fil) == 1) { + fclose(fil); + return TRUE; + } + + fclose(fil); + return FALSE; +} + + + +int SearchNetBoard(unsigned short zone, unsigned short net) +{ + FILE *fil; + + mgrp_pos = -1; + mgrp_crc = -1; + + if ((fil = fopen(msgs_fil, "r")) == NULL) { + return FALSE; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + + while (fread(&msgs, msgshdr.recsize, 1, fil) == 1) { + fseek(fil, msgshdr.syssize, SEEK_CUR); + if ((msgs.Type == NETMAIL) && (msgs.Active) && + (zone == msgs.Aka.zone) && (net == msgs.Aka.net)) { + msgs_pos = ftell(fil) - (msgshdr.recsize + msgshdr.syssize); + msgs_crc = 0xffffffff; + msgs_crc = upd_crc32((char *)&msgs, msgs_crc, msgshdr.recsize); + fclose(fil); + return TRUE; + } + } + fclose(fil); + msgs_pos = -1; + msgs_crc = -1; + sysstart = -1; + return FALSE; +} + + + +void UpdateMsgs() +{ + unsigned long crc = 0xffffffff; + FILE *fil; + + if (msgs_pos == -1) + return; + + crc = upd_crc32((char *)&msgs, crc, msgshdr.recsize); + if (crc != msgs_crc) { + if ((fil = fopen(msgs_fil, "r+")) == NULL) { + msgs_pos = -1; + return; + } + fseek(fil, msgs_pos, SEEK_SET); + fwrite(&msgs, msgshdr.recsize, 1, fil); + fclose(fil); + } + msgs_pos = -1; + msgs_crc = -1; + + if (mgrp_pos == -1) + return; + + crc = 0xffffffff; + crc = upd_crc32((char *)&mgroup, crc, mgrouphdr.recsize); + if (crc != mgrp_crc) { + if ((fil = fopen(mgrp_fil, "r+")) == NULL) { + mgrp_pos = -1; + return; + } + fseek(fil, mgrp_pos, SEEK_SET); + fwrite(&mgroup, mgrouphdr.recsize, 1, fil); + fclose(fil); + } + mgrp_pos = -1; + mgrp_crc = -1; +} + + diff --git a/lib/dbmsgs.h b/lib/dbmsgs.h new file mode 100644 index 00000000..90130e75 --- /dev/null +++ b/lib/dbmsgs.h @@ -0,0 +1,21 @@ +#ifndef _DBMSGS_H +#define _DBMSGS_H + + +struct msgareashdr msgshdr; /* Header record */ +struct msgareas msgs; /* Msgss datarecord */ +struct _mgrouphdr mgrouphdr; /* Group header record */ +struct _mgroup mgroup; /* Group record */ +int msgs_cnt; /* Msgs records in database */ + +int InitMsgs(void); /* Initialize msgs database */ +int SearchMsgs(char *); /* Search specified msg area */ +int SearchMsgsNews(char *); /* Search specified msg area */ +int MsgSystemConnected(sysconnect); /* Is system connected */ +int MsgSystemConnect(sysconnect *, int); /* Connect/change/delete system*/ +int GetMsgSystem(sysconnect *, int);/* Get connected system */ +int SearchNetBoard(unsigned short, unsigned short); /* Search netmail */ +void UpdateMsgs(void); /* Update current messages record */ + +#endif + diff --git a/lib/dbnode.c b/lib/dbnode.c new file mode 100644 index 00000000..d100b22a --- /dev/null +++ b/lib/dbnode.c @@ -0,0 +1,205 @@ +/***************************************************************************** + * + * File ..................: dbnode.c + * Purpose ...............: Noderecord Access + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "dbcfg.h" +#include "dbnode.h" + + +char nodes_fil[PATH_MAX]; /* Nodes database filename */ +long nodes_pos = -1; /* Noderecord position */ +long nodes_fgp = -1; /* Nodes files group position */ +long nodes_mgp = -1; /* Nodes message group position */ +unsigned long nodes_crc = -1; /* Noderecord crc value */ + + + +int InitNode(void) +{ + FILE *fil; + + memset(&nodes, 0, sizeof(nodes)); + LoadConfig(); + + sprintf(nodes_fil, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((fil = fopen(nodes_fil, "r")) == NULL) + return FALSE; + + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + fseek(fil, 0, SEEK_END); + nodes_cnt = (ftell(fil) - nodeshdr.hdrsize) / (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp); + fclose(fil); + + return TRUE; +} + + + +int TestNode(fidoaddr aka) +{ + int i, nodeok = FALSE; + + for (i = 0; i < 20; i++) { + if (((aka.zone == 0) || (aka.zone = nodes.Aka[i].zone)) && + (aka.net == nodes.Aka[i].net) && + (aka.node == nodes.Aka[i].node) && + (aka.point == nodes.Aka[i].point)) + nodeok = TRUE; + } + return(nodeok); +} + + + +int SearchNode(fidoaddr aka) +{ + FILE *fil; + + nodes_pos = -1; + nodes_crc = -1; + + if ((fil = fopen(nodes_fil, "r")) == NULL) + return FALSE; + + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + while (fread(&nodes, nodeshdr.recsize, 1, fil) == 1) { + fseek(fil, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + if (TestNode(aka)) { + nodes_pos = ftell(fil) - (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp); + fclose(fil); + nodes_crc = 0xffffffff; + nodes_crc = upd_crc32((char *)&nodes, nodes_crc, nodeshdr.recsize); + return TRUE; + } + } + + memset(&nodes, 0, sizeof(nodes)); + fclose(fil); + return FALSE; +} + + + +/* + * Update current noderecord if changed. + */ +int UpdateNode() +{ + unsigned long crc; + FILE *fil; + + if (nodes_pos == -1) + return FALSE; + + crc = 0xffffffff; + crc = upd_crc32((char *)&nodes, crc, nodeshdr.recsize); + if (crc != nodes_crc) { + if ((fil = fopen(nodes_fil, "r+")) == NULL) + return FALSE; + fseek(fil, nodes_pos, SEEK_SET); + fwrite(&nodes, nodeshdr.recsize, 1, fil); + fclose(fil); + } + + nodes_crc = -1; + nodes_pos = -1; + memset(&nodes, 0, sizeof(nodes)); + return TRUE; +} + + + +char *GetNodeMailGrp(int First) +{ + FILE *fil; + char group[13], *gr; + + if (nodes_pos == -1) + return NULL; + + if (First) + nodes_mgp = nodes_pos + nodeshdr.recsize + nodeshdr.filegrp; + + if (nodes_mgp > (nodes_pos + nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)) + return NULL; + + if ((fil = fopen(nodes_fil, "r")) == NULL) + return NULL; + + fseek(fil, nodes_mgp, SEEK_SET); + fread(&group, sizeof(group), 1, fil); + fclose(fil); + + nodes_mgp += sizeof(group); + + if (group[0] == '\0') + return NULL; + + gr = xstrcpy(group); + return gr; +} + + + +char *GetNodeFileGrp(int First) +{ + FILE *fil; + char group[13], *gr; + + if (nodes_pos == -1) + return NULL; + + if (First) + nodes_fgp = nodes_pos + nodeshdr.recsize; + + if (nodes_fgp > (nodes_pos + nodeshdr.recsize + nodeshdr.filegrp)) + return NULL; + + if ((fil = fopen(nodes_fil, "r")) == NULL) + return NULL; + + fseek(fil, nodes_fgp, SEEK_SET); + fread(&group, sizeof(group), 1, fil); + fclose(fil); + + nodes_fgp += sizeof(group); + + if (group[0] == '\0') + return NULL; + + gr = xstrcpy(group); + return gr; +} + + diff --git a/lib/dbnode.h b/lib/dbnode.h new file mode 100644 index 00000000..f49810fb --- /dev/null +++ b/lib/dbnode.h @@ -0,0 +1,18 @@ +#ifndef _DBNODE_H +#define _DBNODE_H + + +struct _nodeshdr nodeshdr; /* Header record */ +struct _nodes nodes; /* Nodes datarecord */ +int nodes_cnt; /* Node records in database */ + +int InitNode(void); /* Initialize nodes database */ +int TestNode(fidoaddr); /* Check if noderecord is loaded */ +int SearchNode(fidoaddr); /* Search specified node and load */ +int UpdateNode(void); /* Update record if changed. */ +char *GetNodeMailGrp(int); /* Get nodes mailgroup record */ +char *GetNodeFileGrp(int); /* Get nodes filegroup record */ + + +#endif + diff --git a/lib/dbtic.c b/lib/dbtic.c new file mode 100644 index 00000000..a020d795 --- /dev/null +++ b/lib/dbtic.c @@ -0,0 +1,305 @@ +/***************************************************************************** + * + * File ..................: dbtic.c + * Purpose ...............: Tic areas record Access + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "dbcfg.h" +#include "dbtic.h" + + +char tic_fil[PATH_MAX]; /* Database filename */ +char tgrp_fil[PATH_MAX]; /* Group database filename */ +long tic_pos = -1; /* Current record position */ +long tgrp_pos = -1; /* Current group position */ +unsigned long tic_crc = -1; /* CRC value of current record */ +unsigned long tgrp_crc = -1; /* CRC value of group record */ +static long sysstart, sysrecord; + + + +int InitTic(void) +{ + FILE *fil; + + memset(&tic, 0, sizeof(tic)); + memset(&fgroup, 0, sizeof(fgroup)); + LoadConfig(); + sysstart = -1; + + sprintf(tic_fil, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((fil = fopen(tic_fil, "r")) == NULL) + return FALSE; + + fread(&tichdr, sizeof(tichdr), 1, fil); + fseek(fil, 0, SEEK_END); + tic_cnt = (ftell(fil) - tichdr.hdrsize) / (tichdr.recsize + tichdr.syssize); + fclose(fil); + + sprintf(tgrp_fil, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + return TRUE; +} + + + +int SearchTic(char *Area) +{ + FILE *fil; + + if ((fil = fopen(tic_fil, "r")) == NULL) { + return FALSE; + } + + fread(&tichdr, sizeof(tichdr), 1, fil); + + while (fread(&tic, tichdr.recsize, 1, fil) == 1) { + /* + * Mark the start of the connected systems records + * for later use and skip the system records. + */ + tic_pos = ftell(fil) - tichdr.recsize; + sysstart = ftell(fil); + fseek(fil, tichdr.syssize, SEEK_CUR); + if (!strcmp(Area, tic.Name) && tic.Active) { + sysrecord = 0; + fclose(fil); + tic_crc = 0xffffffff; + tic_crc = upd_crc32((char *)&tic, tic_crc, tichdr.recsize); + tgrp_pos = -1; + tgrp_crc = -1; + + if (strlen(tic.Group)) { + if ((fil = fopen(tgrp_fil, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + while ((fread(&fgroup, fgrouphdr.recsize, 1, fil)) == 1) { + if (!strcmp(tic.Group, fgroup.Name)) { + tgrp_pos = ftell(fil) - fgrouphdr.recsize; + tgrp_crc = 0xffffffff; + tgrp_crc = upd_crc32((char *)&fgroup, tgrp_crc, fgrouphdr.recsize); + break; + } + } + fclose(fil); + } + } else + memset(&fgroup, 0, sizeof(fgroup)); + + return TRUE; + } + } + sysstart = -1; + tic_crc = -1; + tic_pos = -1; + fclose(fil); + return FALSE; +} + + + +/* + * Check if system is connected + */ +int TicSystemConnected(sysconnect Sys) +{ + FILE *fil; + sysconnect T; + + if (sysstart == -1) + return FALSE; + + if ((fil = fopen(tic_fil, "r")) == NULL) + return FALSE; + + if (fseek(fil, sysstart, SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + while (ftell(fil) != (sysstart + tichdr.syssize)) { + fread(&T, sizeof(sysconnect), 1, fil); + if ((T.aka.zone == Sys.aka.zone) && + (T.aka.net == Sys.aka.net) && + (T.aka.node == Sys.aka.node) && + (T.aka.point == Sys.aka.point)) { + fclose(fil); + return TRUE; + } + } + + fclose(fil); + return FALSE; +} + + + +/* + * Change the system's status, if the Read and Write flags are clear, + * the connection will be erased, else updated or connected. + */ +int TicSystemConnect(sysconnect *Sys, int New) +{ + FILE *fil; + sysconnect T; + + if (sysstart == -1) + return FALSE; + + if ((fil = fopen(tic_fil, "r+")) == NULL) + return FALSE; + + if (fseek(fil, sysstart, SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + while (ftell(fil) != (sysstart + tichdr.syssize)) { + fread(&T, sizeof(sysconnect), 1, fil); + + /* + * For a new connection, search an empty slot. + */ + if (New && (!T.aka.zone)) { + fseek(fil, - sizeof(sysconnect), SEEK_CUR); + fwrite(Sys, sizeof(sysconnect), 1, fil); + fclose(fil); + return TRUE; + } + + /* + * If not new it is an update + */ + if ((!New) && (T.aka.zone == Sys->aka.zone) && + (T.aka.node == Sys->aka.node) && + (T.aka.net == Sys->aka.net) && + (T.aka.point == Sys->aka.point)) { + fseek(fil, - sizeof(sysconnect), SEEK_CUR); + if ((!Sys->sendto) && (!Sys->receivefrom)) { + /* + * It's a deletion + */ + if (tic.Mandat) { + fclose(fil); + return FALSE; + } + memset(&T, 0, sizeof(sysconnect)); + fwrite(&T, sizeof(sysconnect), 1, fil); + } else { + /* + * It's a update + */ + fwrite(Sys, sizeof(sysconnect), 1, fil); + } + fclose(fil); + return TRUE; + } + } + + fclose(fil); + return FALSE; +} + + + +int GetTicSystem(sysconnect * Sys, int First) +{ + FILE *fil; + + memset(Sys, 0, sizeof(sysconnect)); + if (sysstart == -1) + return FALSE; + + if (First) + sysrecord = 0; + else + sysrecord++; + + if (sysrecord >= CFG.tic_systems) + return FALSE; + + if ((fil = fopen(tic_fil, "r")) == NULL) + return FALSE; + + if (fseek(fil, sysstart + (sysrecord * sizeof(sysconnect)), SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + if (fread(Sys, sizeof(sysconnect), 1, fil) == 1) { + fclose(fil); + return TRUE; + } + fclose(fil); + return FALSE; +} + + + +void UpdateTic() +{ + unsigned long crc = 0xffffffff; + FILE *fil; + + if (tic_pos == -1) + return; + + crc = upd_crc32((char *)&tic, crc, tichdr.recsize); + if (crc != tic_crc) { + if ((fil = fopen(tic_fil, "r+")) == NULL) { + tic_pos = -1; + return; + } + fseek(fil, tic_pos, SEEK_SET); + fwrite(&tic, tichdr.recsize, 1, fil); + fclose(fil); + } + tic_pos = -1; + tic_crc = -1; + + if (tgrp_pos == -1) + return; + + crc = 0xffffffff; + crc = upd_crc32((char *)&fgroup, crc, fgrouphdr.recsize); + if (crc != tgrp_crc) { + if ((fil = fopen(tgrp_fil, "r+")) == NULL) { + tgrp_pos = -1; + return; + } + fseek(fil, tgrp_pos, SEEK_SET); + fwrite(&fgroup, fgrouphdr.recsize, 1, fil); + fclose(fil); + } + tgrp_pos = -1; + tgrp_crc = -1; +} + + diff --git a/lib/dbtic.h b/lib/dbtic.h new file mode 100644 index 00000000..590ce464 --- /dev/null +++ b/lib/dbtic.h @@ -0,0 +1,19 @@ +#ifndef _DBTIC_H +#define _DBTIC_H + + +struct _tichdr tichdr; /* Header record */ +struct _tic tic; /* Tics datarecord */ +struct _fgrouphdr fgrouphdr; /* Group header record */ +struct _fgroup fgroup; /* Group record */ +int tic_cnt; /* Tic records in database */ + +int InitTic(void); /* Initialize tic database */ +int SearchTic(char *); /* Search specified msg are */ +int TicSystemConnected(sysconnect); /* Is system connected */ +int TicSystemConnect(sysconnect *, int); /* Connect/change/delete system*/ +int GetTicSystem(sysconnect *, int);/* Get connected system */ +void UpdateTic(void); /* Update current messages record */ + +#endif + diff --git a/lib/dbuser.c b/lib/dbuser.c new file mode 100644 index 00000000..b286c7de --- /dev/null +++ b/lib/dbuser.c @@ -0,0 +1,101 @@ +/***************************************************************************** + * + * File ..................: dbuser.c + * Purpose ...............: Userrecord Access + * Last modification date : 29-Jul-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "dbcfg.h" +#include "dbuser.h" + + + + +int InitUser(void) +{ + FILE *fil; + + memset(&usr, 0, sizeof(usr)); + LoadConfig(); + + sprintf(usr_fil, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((fil = fopen(usr_fil, "r")) == NULL) + return FALSE; + + fread(&usrhdr, sizeof(usrhdr), 1, fil); + fseek(fil, 0, SEEK_END); + usr_cnt = (ftell(fil) - usrhdr.hdrsize) / usrhdr.recsize; + fclose(fil); + + return TRUE; +} + + + +int TestUser(char *Name) +{ + int userok = FALSE; + + if ((strcasecmp(usr.sUserName, Name) == 0) || + ((strlen(usr.sHandle) > 0) && (strcasecmp(usr.sHandle, Name) == 0)) || + (strcmp(usr.Name, Name) == 0)) { + if (!usr.Deleted) + userok = TRUE; + } + return(userok); +} + + + +int SearchUser(char *Name) +{ + FILE *fil; + + /* + * Allways reread the users file. + */ + if ((fil = fopen(usr_fil, "r")) == NULL) { + memset(&usr, 0, sizeof(usr)); + return FALSE; + } + fread(&usrhdr, sizeof(usrhdr), 1, fil); + + while (fread(&usr, usrhdr.recsize, 1, fil) == 1) { + if (TestUser(Name)) { + fclose(fil); + return TRUE; + } + } + fclose(fil); + return FALSE; +} + + + diff --git a/lib/dbuser.h b/lib/dbuser.h new file mode 100644 index 00000000..3c2207fd --- /dev/null +++ b/lib/dbuser.h @@ -0,0 +1,16 @@ +#ifndef _DBUSER_H +#define _DBUSER_H + + +struct userhdr usrhdr; /* Header record */ +struct userrec usr; /* User datarecord */ +int usr_cnt; /* User records in database */ +char usr_fil[81]; /* User database filename */ + +int InitUser(void); /* Initialize user database */ +int TestUser(char *); /* Test if user is in memory */ +int SearchUser(char *); /* Search specified user and load */ + + +#endif + diff --git a/lib/dostran.c b/lib/dostran.c new file mode 100644 index 00000000..0a511df6 --- /dev/null +++ b/lib/dostran.c @@ -0,0 +1,96 @@ +/***************************************************************************** + * + * File ..................: dostran.c + * Purpose ...............: DOS to Unix filename translation + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "common.h" + + +char *Dos2Unix(char *dosname) +{ + char buf[PATH_MAX]; + static char buf2[PATH_MAX]; + char *p, *q; + + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + sprintf(buf, "%s", dosname); + p = buf; + + if (strlen(CFG.dospath)) { + if (strncasecmp(p, CFG.dospath, strlen(CFG.dospath)) == 0) { + strcpy((char *)buf2, CFG.uxpath); + for (p+=strlen(CFG.dospath), q = buf2 + strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } else { + if (strncasecmp(p, CFG.uxpath, strlen(CFG.uxpath)) == 0) { + for (p+=strlen(CFG.uxpath), q = buf2 + strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } + } + } + return buf2; +} + + + +char *Unix2Dos(char *uxname) +{ + char *q; + static char buf[PATH_MAX]; + + memset(&buf, 0, sizeof(buf)); + + if (strlen(CFG.dospath)) { + sprintf(buf, "%s", CFG.dospath); + + if (*(CFG.dospath+strlen(CFG.dospath)-1) != '\\') + buf[strlen(buf)] = '\\'; + + if (*(q=uxname+strlen(CFG.uxpath)) == '/') + q++; + + for (; *q; q++) + buf[strlen(buf)] = (*q == '/')?'\\':*q; + + } else { + sprintf(buf, "%s", uxname); + } + + return buf; +} + + diff --git a/lib/execute.c b/lib/execute.c new file mode 100644 index 00000000..7df4a8aa --- /dev/null +++ b/lib/execute.c @@ -0,0 +1,190 @@ +/***************************************************************************** + * + * File ..................: execute.c + * Purpose ...............: Execute subprogram + * Last modification date : 16-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +int e_pid = 0; /* Execute child pid */ + + + +int execute(char *cmd, char *file, char *pkt, char *in, char *out, char *err) +{ + char buf[512]; + char *vector[16]; + int i; + int pid, status, rc; + + if (pkt == NULL) + sprintf(buf, "%s %s", cmd, file); + else + sprintf(buf, "%s %s %s", cmd, file, pkt); + Syslog('+', "Execute: %s",buf); + + i = 0; + vector[i++] = strtok(buf," \t\n"); + while ((vector[i++] = strtok(NULL," \t\n")) && (i<16)); + vector[15] = NULL; + fflush(stdout); + fflush(stderr); + + if ((pid = fork()) == 0) { + if (in) { + close(0); + if (open(in,O_RDONLY) != 0) { + WriteError("$Reopen of stdin to %s failed", MBSE_SS(in)); + exit(-1); + } + } + if (out) { + close(1); + if (open(out,O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { + WriteError("$Reopen of stdout to %s failed", MBSE_SS(out)); + exit(-1); + } + } + if (err) { + close(2); + if (open(err,O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { + WriteError("$Reopen of stderr to %s failed", MBSE_SS(err)); + exit(-1); + } + } + errno = 0; + rc = getpriority(PRIO_PROCESS, 0); + if (errno == 0) { + rc = setpriority(PRIO_PROCESS, 0, 15); + if (rc) + WriteError("$execv can't set priority to 15"); + } + rc = execv(vector[0],vector); + WriteError("$execv \"%s\" returned %d", MBSE_SS(vector[0]), rc); + setpriority(PRIO_PROCESS, 0, 0); + exit(-1); + } + + e_pid = pid; + + do { + rc = wait(&status); + e_pid = 0; + } while (((rc > 0) && (rc != pid)) || ((rc == -1) && (errno == EINTR))); + + setpriority(PRIO_PROCESS, 0, 0); + switch (rc) { + case -1: + WriteError("$Wait returned %d, status %d,%d", rc,status>>8,status&0xff); + return -1; + case 0: + return 0; + default: + if (WIFEXITED(status)) { + rc = WEXITSTATUS(status); + if (rc) { + WriteError("Execute: returned error %d", rc); + return rc; + } + } + if (WIFSIGNALED(status)) { + rc = WTERMSIG(status); + WriteError("Wait stopped on signal %d", rc); + return rc; + } + if (rc) + WriteError("Wait stopped unknown, rc=%d", rc); + return rc; + } + return 0; +} + + +#define SHELL "/bin/sh" + + +int execsh(char *cmd, char *in, char *out, char *err) +{ + int pid, status, rc, sverr; + + Syslog('+', "Execute shell: %s", MBSE_SS(cmd)); + fflush(stdout); + fflush(stderr); + + if ((pid = fork()) == 0) { + if (in) { + close(0); + if (open(in, O_RDONLY) != 0) { + WriteError("$Reopen of stdin to %s failed",MBSE_SS(in)); + exit(-1); + } + } + if (out) { + close(1); + if (open(out, O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { + WriteError("$Reopen of stdout to %s failed",MBSE_SS(out)); + exit(-1); + } + } + if (err) { + close(2); + if (open(err, O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { + WriteError("$Reopen of stderr to %s failed",MBSE_SS(err)); + exit(-1); + } + } + + rc = execl(SHELL, "sh", "-c", cmd, NULL); + WriteError("$execl \"%s\" returned %d", MBSE_SS(cmd), rc); + exit(-1); + } + + e_pid = pid; + + do { + rc = wait(&status); + e_pid = 0; + sverr = errno; + if (status) + WriteError("$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); + } + + while (((rc > 0) && (rc != pid)) || ((rc == -1) && (sverr == EINTR))); + if (rc == -1) { + WriteError("$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); + return -1; + } + + return status; +} + + diff --git a/lib/expipe.c b/lib/expipe.c new file mode 100644 index 00000000..75b28f6b --- /dev/null +++ b/lib/expipe.c @@ -0,0 +1,196 @@ +/***************************************************************************** + * + * File ..................: expipe.c + * Purpose ...............: MBSE BBS Execute pipe + * Last modification date : 22-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + + +static struct _fppid { + FILE *fp; + int pid; +} fppid[] = { + {NULL, 0}, {NULL, 0}, {NULL, 0} +}; + +#define maxfppid 2 + + + +FILE *expipe(char *cmd, char *from, char *to) +{ + char buf[256], *buflimit; + char *vector[16]; + int i, rc; + char *p, *q, *f=from, *t=to; + int pipedes[2]; + FILE *fp; + int pid, slot; + + buflimit = buf + sizeof(buf) -1 - (f&&t&&(strlen(f)>strlen(t))?strlen(f):t?strlen(t):0); + + for (slot = 0; slot <= maxfppid; slot++) { + if (fppid[slot].fp == NULL) + break; + } + if (slot > maxfppid) { + WriteError("Attempt to pipe more than %d processes", maxfppid + 1); + return NULL; + } + + for (p = cmd, q = buf; (*p); p++) { + if (q > buflimit) { + WriteError("Attempt to pipe too long command"); + return NULL; + } + switch (*p) { + case '$': switch (*(++p)) { + case 'f': + case 'F': if ((f)) + while (*f) + *(q++) = *(f++); + f=from; + break; + case 't': + case 'T': if ((t)) + while (*t) + *(q++) = *(t++); + t=to; + break; + default: *(q++)='$'; + *(q++)=*p; + break; + } + break; + case '\\': *(q++) = *(++p); + break; + default: *(q++) = *p; + break; + } + } + + *q = '\0'; + Syslog('+', "Expipe: %s",buf); + i = 0; + vector[i++] = strtok(buf," \t\n"); + while ((vector[i++] = strtok(NULL," \t\n")) && (i<16)); + vector[15] = NULL; + fflush(stdout); + fflush(stderr); + if (pipe(pipedes) != 0) { + WriteError("$Pipe failed for command \"%s\"", MBSE_SS(vector[0])); + return NULL; + } + + Syslog('e', "pipe() returned read=%d, write=%d", pipedes[0], pipedes[1]); + if ((pid = fork()) == 0) { + close(pipedes[1]); + close(0); + if (dup(pipedes[0]) != 0) { + WriteError("$Reopen of stdin for command %s failed", MBSE_SS(vector[0])); + exit(-1); + } + rc = execv(vector[0],vector); + WriteError("$Exec \"%s\" returned %d", MBSE_SS(vector[0]), rc); + exit(-1); + } + + close(pipedes[0]); + + if ((fp = fdopen(pipedes[1],"w")) == NULL) { + WriteError("$fdopen failed for pipe to command \"%s\"", MBSE_SS(vector[0])); + } + + fppid[slot].fp = fp; + fppid[slot].pid = pid; + return fp; +} + + + +int exclose(FILE *fp) +{ + int status, rc; + int pid, slot, sverr; + + for (slot = 0; slot <= maxfppid; slot++) { + if (fppid[slot].fp == fp) + break; + } + if (slot > maxfppid) { + WriteError("Attempt to close unopened pipe"); + return -1; + } + pid = fppid[slot].pid; + fppid[slot].fp = NULL; + fppid[slot].pid = 0; + + Syslog('e', "Closing pipe to the child process %d",pid); + if ((rc = fclose(fp)) != 0) { + WriteError("$Error closing pipe to transport (rc=%d)", rc); + if ((rc = kill(pid,SIGKILL)) != 0) + WriteError("$kill for pid %d returned %d",pid,rc); + } + Syslog('e', "Waiting for process %d to finish",pid); + do { + rc = wait(&status); + sverr = errno; + if (status) + Syslog('e', "$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); + } while (((rc > 0) && (rc != pid)) || ((rc == -1) && (sverr == EINTR))); + + switch (rc) { + case -1:WriteError("$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); + return -1; + case 0: return 0; + default: + if (WIFEXITED(status)) { + rc = WEXITSTATUS(status); + if (rc) { + WriteError("Expipe: returned error %d", rc); + return rc; + } + } + if (WIFSIGNALED(status)) { + rc = WTERMSIG(status); + WriteError("Wait stopped on signal %d", rc); + return rc; + } + if (rc) + WriteError("Wait stopped unknown, rc=%d", rc); + return rc; + } + return 0; +} + diff --git a/lib/faddr.c b/lib/faddr.c new file mode 100644 index 00000000..ec12727f --- /dev/null +++ b/lib/faddr.c @@ -0,0 +1,100 @@ +/***************************************************************************** + * + * File ..................: faddr.c + * Purpose ...............: Fidonet Address conversions. + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1993-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MB BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + +/************************************************************************ + * + * String functions + */ + + +/* + * Fidonet aka to string, returns Z:N/N@domain or Z:N/N.P@domain + */ +char *aka2str(fidoaddr aka) +{ + static char result[43]; + + result[0] = '\0'; + if (aka.point == 0) + sprintf(result, "%d:%d/%d@%s", aka.zone, aka.net, aka.node, aka.domain); + else + sprintf(result, "%d:%d/%d.%d@%s", aka.zone, aka.net, aka.node, aka.point, aka.domain); + + return result; +} + + + +fidoaddr str2aka(char *addr) +{ + char a[256]; + static char b[43]; + char *temp; + fidoaddr n; + + sprintf(b, "%s~", addr); + n.zone = 0; + n.net = 0; + n.node = 0; + n.point = 0; + n.domain[0] = '\0'; + + if ((strchr(b, ':') == NULL) || (strchr(b, '@') == NULL)) + return n; + + /* First split the f:n/n.p and domain part + */ + temp = strtok(b, "@"); + strcpy(n.domain, strtok(NULL, "~")); + + /* Handle f:n/n.p part + */ + strcpy(a, strcat(temp, "~")); + if (strchr(a, '.') == NULL) { + n.zone = atoi(strtok(a, ":")); + n.net = atoi(strtok(NULL, "/")); + n.node = atoi(strtok(NULL, "~")); + } else { + n.zone = atoi(strtok(a, ":")); + n.net = atoi(strtok(NULL, "/")); + n.node = atoi(strtok(NULL, ".")); + n.point = atoi(strtok(NULL, "~")); + } + return n; +} + + + + diff --git a/lib/falists.c b/lib/falists.c new file mode 100644 index 00000000..d461754b --- /dev/null +++ b/lib/falists.c @@ -0,0 +1,228 @@ +/***************************************************************************** + * + * File ..................: falists.c + * Purpose ...............: SEEN-BY and PATH lists + * Last modification date : 25-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + + +void tidy_falist(fa_list **fap) +{ + fa_list *tmp,*old; + + for (tmp = *fap; tmp; tmp = old) { + old = tmp->next; + tidy_faddr(tmp->addr); + free(tmp); + } + *fap = NULL; +} + + + +int in_list(faddr *addr, fa_list **fap, int fourd) +{ + fa_list *tmp; + + Syslog('M', "in_list: Seeking seen-by match for %s", ascinode(addr,0x06)); + + if (addr->point) { + Syslog('M', "in_list: No seen-by check for point address"); + return 0; + } + + for (tmp = *fap; tmp; tmp = tmp->next) + if ((tmp->addr->net == addr->net) && + ((!fourd) || (fourd && (tmp->addr->zone == addr->zone))) && + ((!fourd) || (fourd && (tmp->addr->point == addr->point))) && + (tmp->addr->node == addr->node)) { + Syslog('M', "in_list: Match found"); + return 1; + } + + Syslog('M', "in_list: Match not found"); + return 0; +} + + + +void fill_list(fa_list **fap, char *str, fa_list **omit, int force) +{ + fa_list *tmp; + faddr *ta; + static unsigned int oldnet; + char *buf, *p, *q, *r; + int allowskip = 1; + + if ((str == NULL) || (*str == '\0')) + return; + + buf = xstrcpy(str); + r = buf + strlen(buf); + + for (p = strtok(buf," \t\n"), q = p + strlen(p) + 1; + p; + p = (q < r) ? strtok(q, " \t\n"):NULL, q = p ? p + strlen(p) + 1:r) + if ((ta = parsefnode(p))) { + if (ta->net == 0) + ta->net = oldnet; + else + oldnet = ta->net; + if (allowskip && omit && *omit && (metric(ta,(*omit)->addr) == 0)) { + Syslog('m', "fill_list: omit %s", ascfnode(ta,0x1f)); + tmp = *omit; + *omit = (*omit)->next; + tmp->next = NULL; + tidy_falist(&tmp); + } else { + allowskip = 0; + tmp = (fa_list *)malloc(sizeof(fa_list)); + tmp->next = *fap; + tmp->addr = ta; + tmp->force = force; + *fap = tmp; + } + } + + free(buf); + return; +} + + + +void fill_path(fa_list **fap, char *str) +{ + fa_list **tmp; + faddr *ta; + static unsigned int oldnet; + char *buf, *p, *q, *r; + + if ((str == NULL) || (*str == '\0')) + return; + buf = xstrcpy(str); + for (tmp = fap; *tmp; tmp = &((*tmp)->next)); /*nothing*/ + r = buf + strlen(buf); + + for (p = strtok(buf, " \t\n"), q = p + strlen(p) + 1; + p; + p = (q < r) ? strtok(q, " \t\n") : NULL, q = p ? p + strlen(p) + 1 : r) + if ((ta = parsefnode(p))) { + if (ta->net == 0) + ta->net=oldnet; + else + oldnet=ta->net; + *tmp = (fa_list *)malloc(sizeof(fa_list)); + (*tmp)->next = NULL; + (*tmp)->addr = ta; + tmp = &((*tmp)->next); + } + free(buf); + return; +} + + + + +int compaddr(fa_list **,fa_list **); + + + +void uniq_list(fa_list **fap) +{ + fa_list *ta, *tan; + + if (*fap == NULL) + return; + for (ta = *fap; ta; ta = ta->next) { + while ((tan = ta->next) && (compaddr(&ta, &tan) == 0)) { + ta->next = tan->next; + tidy_faddr(tan->addr); + free(tan); + } + ta->next = tan; + } +} + + + +void sort_list(fa_list **fap) +{ + fa_list *ta, **vector; + size_t n = 0, i; + + if (*fap == NULL) + return; + + for (ta = *fap; ta; ta = ta->next) + n++; + vector = (fa_list **)malloc(n * sizeof(fa_list *)); + i = 0; + + for (ta = *fap; ta; ta = ta->next) { + vector[i++] = ta; + } + qsort(vector,n,sizeof(faddr*), + (int(*)(const void*,const void*))compaddr); + + (*fap) = vector[0]; + i = 1; + + for (ta = *fap; ta; ta = ta->next) { + while ((i < n) && (compaddr(&ta,&(vector[i])) == 0)) + { + tidy_faddr((vector[i])->addr); + free(vector[i]); + i++; + } + if (i < n) + ta->next=vector[i++]; + else + ta->next=NULL; + } + + free(vector); + return; +} + + + +int compaddr(fa_list **fap1, fa_list **fap2) +{ + if ((*fap1)->addr->net != (*fap2)->addr->net) + return ((*fap1)->addr->net - (*fap2)->addr->net); + else + return ((*fap1)->addr->node - (*fap2)->addr->node); +} + + + diff --git a/lib/ftn.c b/lib/ftn.c new file mode 100644 index 00000000..1819ec5f --- /dev/null +++ b/lib/ftn.c @@ -0,0 +1,683 @@ +/***************************************************************************** + * + * File ..................: ftn.c + * Purpose ...............: Fidonet Technology Network functions + * Last modification date : 25-Mar-2001 + * Remark ................: From ifmail with patches from P.Saratxaga + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#define DB_FIDONET + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "dbftn.h" +#include "common.h" + + +#ifndef MAXUSHORT +#define MAXUSHORT 65535 +#endif +#ifndef BLANK_SUBS +#define BLANK_SUBS '.' +#endif + + +int addrerror = 0; + +void tidy_faddr(faddr *addr) +{ + if (addr == NULL) + return; + if (addr->name) + free(addr->name); + if (addr->domain) + free(addr->domain); + free(addr); +} + + + +faddr *parsefnode(char *s) +{ + faddr addr, *tmp; + char *buf, *str, *p, *q, *n; + int good = 1; + + if (s == NULL) + return NULL; + + str = buf = xstrcpy(s); + + while (isspace(*str)) + str++; + if (*(p=str+strlen(str)-1) == '\n') + *(p--) ='\0'; + while (isspace(*p)) + *(p--) = '\0'; + + p=str + strlen(str) - 1; + if (((*str == '(') && (*p == ')')) || ((*str == '\"') && (*p == '\"')) || + ((*str == '\'') && (*p == '\'')) || ((*str == '<') && (*p == '>')) || + ((*str == '[') && (*p == ']')) || ((*str == '{') && (*p == '}'))) { + str++; + *p = '\0'; + } + + memset(&addr, 0, sizeof(faddr)); + if ((p = strrchr(str,' '))) { + n = str; + str = p + 1; + while (isspace(*p)) + *(p--) = '\0'; + if (!strcasecmp(p - 2," of")) + *(p-2) = '\0'; + else if (!strcasecmp(p - 1," @")) + *(p-1) = '\0'; + p -= 3; + while (isspace(*p) || (*p == ',')) + *(p--) = '\0'; + if (strlen(n) > MAXNAME) + n[MAXNAME] = '\0'; + if (*n != '\0') + addr.name = xstrcpy(n); + } + + if ((p = strrchr(str, '@'))) + *(p++) = '\0'; + else if ((p = strrchr(str,'%'))) + *(p++) = '\0'; + else if ((q = strrchr(str,'#'))) { + *(q++) = '\0'; + p = str; + str = q; + } else if (addr.name && (strrchr(addr.name,'@'))) { + str = xstrcpy(addr.name); + if ((p=strrchr(str,'@'))) + *(p++) = '\0'; + else if ((p=strrchr(str,'%'))) + *(p++) = '\0'; + } else + p = NULL; + + if (p && ((q = strchr(p,'.')))) + *q = '\0'; + + addr.point = 0; + addr.node = 0; + addr.net = 0; + addr.zone = 0; + addr.domain = xstrcpy(p); + + if ((p = strchr(str, ':'))) { + *(p++) = '\0'; + if (strspn(str, "0123456789") == strlen(str)) + addr.zone = atoi(str); + else + if (strcmp(str,"*") == 0) + addr.zone = -1; + else + good = 0; + str = p; + } + + if ((p = strchr(str, '/'))) { + *(p++) = '\0'; + if (strspn(str, "0123456789") == strlen(str)) + addr.net = atoi(str); + else + if (strcmp(str, "*") == 0) + addr.net = -1; + else + good = 0; + str = p; + } + + if ((p=strchr(str, '.'))) { + *(p++) = '\0'; + if (strspn(str, "0123456789") == strlen(str)) + addr.node = atoi(str); + else + if (strcmp(str, "*") == 0) + addr.node = -1; + else + good = 0; + str = p; + } else { + if (strspn(str, "0123456789") == strlen(str)) + addr.node = atoi(str); + else + if (strcmp(str, "*") == 0) + addr.node = -1; + else + good = 0; + str = NULL; + } + + if (str) { + if (strspn(str, "0123456789") == strlen(str)) + addr.point = atoi(str); + else + if (strcmp(str, "*") == 0) + addr.point = -1; + else + good = 0; + } + + if (buf) + free(buf); + + if (good) { + tmp = (faddr *)malloc(sizeof(addr)); + tmp->name = NULL; + tmp->domain = addr.domain; + tmp->point = addr.point; + tmp->node = addr.node; + tmp->net = addr.net; + tmp->zone = addr.zone; + return tmp; + } else { + if (addr.name) + free(addr.name); + if (addr.domain) + free(addr.domain); + return NULL; + } +} + + + +faddr *parsefaddr(char *s) +{ + faddr *tmpaddr = NULL; + parsedaddr rfcaddr; + int gotzone = 0, gotnet = 0, gotnode = 0, gotpoint = 0; + int zone = 0, net = 0, noden = 0, point = 0; + char *domain = NULL, *freename = NULL; + long num; + char *p = NULL,*q = NULL,*t = NULL; + int l, quoted; + FILE *fp; + + rfcaddr.target = NULL; + rfcaddr.remainder = NULL; + rfcaddr.comment = NULL; + + t = xstrcpy(s); + if (*(q=t+strlen(t)-1) == '\n') + *q='\0'; + if (((*(p=t) == '(') && (*(q=p+strlen(p)-1) == ')')) || ((*p == '\"') && (*q == '\"'))) { + p++; + *q='\0'; + } + + if (strchr(s,'@') || strchr(s,'%') || strchr(s,'!')) + rfcaddr = parserfcaddr(p); + else { + addrerror = 0; + rfcaddr.target = xstrcpy(p); + } + free(t); + if ((addrerror) || (rfcaddr.target == NULL)) + goto leave; + + p = calloc(PATH_MAX, sizeof(char)); + sprintf(p, "%s/etc/domain.data", getenv("MBSE_ROOT")); + if ((fp = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + free(p); + } else { + free(p); + fread(&domainhdr, sizeof(domainhdr), 1, fp); + p = rfcaddr.target; + + while (fread(&domtrans, domainhdr.recsize, 1, fp) == 1) { + q = p + strlen(p) - strlen(domtrans.intdom); + if ((q >= p) && (strcasecmp(domtrans.intdom, q) == 0)) { + *q = '\0'; + q = malloc(strlen(p) + strlen(domtrans.ftndom) +1); + strcpy(q, p); + strcat(q, domtrans.ftndom); + p = q; + free(rfcaddr.target); + rfcaddr.target = p; + break; + } + } + fclose(fp); + } + + if (((l = strlen(rfcaddr.target)) > 4) && (strcasecmp(rfcaddr.target + l - 4,".ftn") == 0)) { + rfcaddr.target[l-4] = '\0'; + } + + for (p = strtok(rfcaddr.target, "."); p; p = strtok(NULL,".")) { + if (((l = strlen(p + 1)) > 0) && (l <= 5) && + (strspn(p + 1, "0123456789") == l)) { + num = atol(p + 1); + switch (*p) { + case 'z': + case 'Z': + gotzone++; + if (num > MAXUSHORT) + addrerror |= ADDR_BADTOKEN; + zone = num; + break; + case 'n': + case 'N': + gotnet++; + if (num > MAXUSHORT) + addrerror |= ADDR_BADTOKEN; + net = num; + break; + case 'f': + case 'F': + gotnode++; + if (num > MAXUSHORT) + addrerror |= ADDR_BADTOKEN; + noden = num; + break; + case 'p': + case 'P': + gotpoint++; + if (num > MAXUSHORT) + addrerror |= ADDR_BADTOKEN; + point = num; + break; + default: + if (gotnet && gotnode) { + if (domain == NULL) + domain = xstrcpy(p); + } else + addrerror |= ADDR_BADTOKEN; + break; + } + } else { /* not "cNNNN" token */ + if (gotnet && gotnode) { + if (domain == NULL) + domain = xstrcpy(p); + } else + addrerror |= ADDR_BADTOKEN; + } + } + + if ((gotzone > 1) || (gotnet != 1) || (gotnode != 1) || (gotpoint > 1)) { + addrerror |= ADDR_BADSTRUCT; + } + + if (addrerror) + goto leave; + + if (rfcaddr.remainder) { + quoted = 0; + if ((*(p = rfcaddr.remainder) == '\"') && (*(q = p + strlen(p) -1) == '\"')) { + p++; + *q='\0'; + quoted = 1; + } + if (strchr(p,'@') || strchr(p,'%') || strchr(p,'!')) { + if (((q=strrchr(p,'%'))) && !strchr(p,'@')) + *q = '@'; + } else if ((!quoted) && (!strchr(p, ' '))) { + for (q = p; *q; q++) { + if (*q == BLANK_SUBS) + *q = ' '; + else if (*q == '.') + *q = ' '; + else if (*q == '_') + *q = ' '; + } + } + for (q = p; *q; q++) { + if ((*q == '\\') && ((*(q+1) == '"') || ((*(q+1) == '\\') && (!quoted)))) { + *q='\0'; + strcat(p, q+1); + } + } + if (strspn(p," ") != strlen(p)) + freename = xstrcpy(qp_decode(p)); + } + + tmpaddr=(faddr*)malloc(sizeof(faddr)); + + tmpaddr->zone=zone; + tmpaddr->net=net; + tmpaddr->node=noden; + tmpaddr->point=point; + tmpaddr->domain=domain; + domain=NULL; + tmpaddr->name=freename; + freename=NULL; + +leave: + if (domain) + free(domain); + if (freename) + free(freename); + + tidyrfcaddr(rfcaddr); + return tmpaddr; +} + + + +char *ascinode(faddr *a, int fl) +{ + static char buf[128], *f, *t, *p; + static char *q; + int skip, found = FALSE; + FILE *fp; + + if (a == NULL) { + strcpy(buf,""); + return buf; + } + + buf[0]='\0'; + if ((fl & 0x80) && (a->name)) { + if ((strchr(a->name,'.')) || (strchr(a->name,'@')) || + (strchr(a->name,'\'')) || (strchr(a->name,',')) || + (strchr(a->name,'<')) || (strchr(a->name,'>'))) + sprintf(buf+strlen(buf),"\"%s\" <",a->name); + else + sprintf(buf+strlen(buf),"%s <",a->name); + } + + if ((fl & 0x40) && (a->name)) { + f = qp_encode(a->name, 0); + t = buf + strlen(buf); + skip = 0; + if ((!strchr(f,'@')) && ((strchr(f,BLANK_SUBS)) || (strchr(f,'.')) || (strchr(f,'_')))) { + skip = 1; + *t++='"'; + } + while (*f) { + switch (*f) { + case '_': + case '.': *t++=*f; + break; + case ' ': if (!skip) + *t++=BLANK_SUBS; + else { + *t++='='; *t++='2'; *t++='0'; + } + break; + case ',': { /* "," is a problem on mail addr */ + if (!skip) + *t++='\\'; + *t++='='; + *t++='2'; + *t++='c'; + } + case '@': if (skip) { + *t++='"'; + skip=0; + } + *t++='%'; + break; + case '"': *t++='\\'; + *t++=*f; + break; + case '>': + case '<': + case '\'': if (!skip) + *t++='\\'; + *t++=*f; + break; + default: if ((((*f & 0xff) > 0x29) && ((*f & 0xff) < 0x3a)) || + (((*f & 0xff) > 0x40) && ((*f & 0xff) < 0x5b)) || + (((*f & 0xff) > 0x60) && ((*f & 0xff) < 0x7b))) + *t++=*f; + else { + if (!skip) + *t++='\\'; + *t++=*f; + } + break; + } + f++; + } + if (skip) + *t++='"'; + skip = 0; + *t++ = '@'; + *t++ = '\0'; + } + + if ((fl & 0x01) && (a->point)) + sprintf(buf+strlen(buf),"p%u.",a->point); + if (fl & 0x02) + sprintf(buf+strlen(buf),"f%u.",a->node); + if (fl & 0x04) + sprintf(buf+strlen(buf),"n%u.",a->net); + if ((fl & 0x08) && (a->zone)) + sprintf(buf+strlen(buf),"z%u.",a->zone); + buf[strlen(buf)-1]='\0'; + + if (fl & 0x10) { + if (a->domain) + sprintf(buf+strlen(buf),".%s",a->domain); + } + + if (fl & 0x20) { + if (a->domain) { + if ((fl & 0x10) == 0) + sprintf(buf+strlen(buf),".%s",a->domain); + } else { + if (SearchFidonet(a->zone)) + sprintf(buf+strlen(buf), ".%s", fidonet.domain); + else + sprintf(buf+strlen(buf),".fidonet"); + } + + p = calloc(128, sizeof(char)); + sprintf(p, "%s/etc/domain.data", getenv("MBSE_ROOT")); + if ((fp = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + } else { + fread(&domainhdr, sizeof(domainhdr), 1, fp); + while (fread(&domtrans, domainhdr.recsize, 1, fp) == 1) { + q = buf + strlen(buf) - strlen(domtrans.ftndom); + if ((q >= buf) && (strcasecmp(domtrans.ftndom, q) == 0)) { + strcpy(q, domtrans.intdom); + found = TRUE; + break; + } + } + fclose(fp); + } + free(p); + if (!found) + sprintf(buf + strlen(buf), ".ftn"); + } + + if ((fl & 0x80) && (a->name)) + sprintf(buf+strlen(buf),">"); + + return buf; +} + + + +/* + * Return ASCII string for node, the bits in 'fl' set the + * output format. + */ +char *ascfnode(faddr *a, int fl) +{ + static char buf[128]; + + if (a == NULL) { + strcpy(buf, ""); + return buf; + } + + buf[0] = '\0'; + if ((fl & 0x40) && (a->name)) + sprintf(buf+strlen(buf),"%s of ",a->name); + if ((fl & 0x08) && (a->zone)) + sprintf(buf+strlen(buf),"%u:",a->zone); + if (fl & 0x04) + sprintf(buf+strlen(buf),"%u/",a->net); + if (fl & 0x02) + sprintf(buf+strlen(buf),"%u",a->node); + if ((fl & 0x01) && (a->point)) + sprintf(buf+strlen(buf),".%u",a->point); + if ((fl & 0x10) && (a->domain)) + sprintf(buf+strlen(buf),"@%s",a->domain); + return buf; +} + + + +int metric(faddr *a1, faddr *a2) +{ + if ((a1->domain != NULL) && (a2->domain != NULL) && + (strcasecmp(a1->domain,a2->domain) != 0)) + return METRIC_DOMAIN; + if ((a1->zone != 0) && (a2->zone != 0) && + (a1->zone != a2->zone)) return METRIC_ZONE; + if (a1->net != a2->net) return METRIC_NET; + if (a1->node != a2->node) return METRIC_NODE; + if (a1->point != a2->point) return METRIC_POINT; + return METRIC_EQUAL; +} + + + +/* + * Convert mbse style to ifcico style. + */ +faddr *fido2faddr(fidoaddr aka) +{ + faddr *fa; + + fa = (faddr *)malloc(sizeof(faddr)); + fa->name = NULL; + fa->domain = xstrcpy(aka.domain);; + fa->zone = aka.zone; + fa->net = aka.net; + fa->node = aka.node; + fa->point = aka.point; + + return fa; +} + + + +/* + * Convert ifcico style to mbse style + */ +fidoaddr *faddr2fido(faddr *aka) +{ + fidoaddr *Sys; + + Sys = (fidoaddr *)malloc(sizeof(fidoaddr)); + memset(Sys, 0, sizeof(Sys)); + Sys->zone = aka->zone; + Sys->net = aka->net; + Sys->node = aka->node; + Sys->point = aka->point; + if (aka->domain != NULL) + sprintf(Sys->domain, "%s", aka->domain); + + return Sys; +} + + + +faddr *bestaka_s(faddr *addr) +{ + faddr *best = NULL, *tmp; + int i, minmetric, wt; + + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i]) { + best = fido2faddr(CFG.aka[i]); + break; + } + } + if (addr == NULL) + return best; + minmetric = metric(addr, best); + + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i]) { + tmp = fido2faddr(CFG.aka[i]); + wt = metric(addr, tmp); + tidy_faddr(tmp); + + if ((wt < minmetric) && ((best->point != 0) || (minmetric > METRIC_NODE))) { + /* + * In the same network, use node address even when + * routing to the node where we have a point address + */ + minmetric = wt; + tidy_faddr(best); + best = fido2faddr(CFG.aka[i]); + } + } + } + return best; +} + + + +int is_local(faddr *addr) +{ + int i; + + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && (metric(fido2faddr(CFG.aka[i]), addr) == METRIC_EQUAL)) + return TRUE; + } + return FALSE; +} + + + +int chkftnmsgid(char *msgid) +{ + faddr *p; + + if (msgid == NULL) + return 0; + + while (isspace(*msgid)) + msgid++; + if ((p=parsefaddr(msgid))) { + if (p->name && (strspn(p->name,"0123456789") == strlen(p->name))) + return 1; + } else if ((!strncmp(msgid,"tm_sec > 59) + ptm->tm_sec = 59; + + sprintf(buf,"%02d %s %02d %02d:%02d:%02d",ptm->tm_mday, + months[ptm->tm_mon], ptm->tm_year%100, + ptm->tm_hour, ptm->tm_min, ptm->tm_sec); + return buf; +} + + + +FILE *ftnmsghdr(ftnmsg *fmsg, FILE *pkt, faddr *route, char flavor, char *Pid) +{ + unsigned char buffer[0x0e]; + time_t Now; + faddr *from; + + if ((strlen(fmsg->to->name) > 36) || + (strlen(fmsg->from->name) > 36) || + (strlen(fmsg->subj) > 72)) + return NULL; + + if (route == NULL) + route = fmsg->to; + pkt = openpkt(pkt, route, flavor); + if (pkt == NULL) + return NULL; + + if (fmsg->area) + from = bestaka_s(fmsg->to); + else + from = fmsg->from; + + memset(&buffer, 0, sizeof(buffer)); + buffer[0x00] = 2; + buffer[0x02] = (from->node & 0x00ff); + buffer[0x03] = (from->node & 0xff00) >> 8; + buffer[0x04] = (fmsg->to->node & 0x00ff); + buffer[0x05] = (fmsg->to->node & 0xff00) >> 8; + buffer[0x06] = (from->net & 0x00ff); + buffer[0x07] = (from->net & 0xff00) >> 8; + buffer[0x08] = (fmsg->to->net & 0x00ff); + buffer[0x09] = (fmsg->to->net & 0xff00) >> 8; + buffer[0x0a] = (fmsg->flags & 0x00ff); + buffer[0x0b] = (fmsg->flags & 0xff00) >> 8; + fwrite(buffer, 1, sizeof(buffer), pkt); + + fprintf(pkt, "%s%c", ftndate(fmsg->date), '\0'); + fprintf(pkt, "%s%c", fmsg->to->name?fmsg->to->name:(char *)"Sysop", '\0'); + fprintf(pkt, "%s%c", fmsg->from->name?fmsg->from->name:(char *)"Sysop", '\0'); + fprintf(pkt, "%s%c", fmsg->subj?fmsg->subj:(char *)"", '\0'); + + if (fmsg->area) { + fprintf(pkt, "AREA:%s\r", fmsg->area); + } else { + if (fmsg->to->point) + fprintf(pkt, "\1TOPT %u\r", fmsg->to->point); + if (fmsg->from->point) + fprintf(pkt, "\1FMPT %u\r", fmsg->from->point); + fprintf(pkt, "\1INTL %u:%u/%u %u:%u/%u\r", + fmsg->to->zone, + fmsg->to->net, + fmsg->to->node, + fmsg->from->zone, + fmsg->from->net, + fmsg->from->node + ); + } + + if (fmsg->msgid_s) + fprintf(pkt, "\1MSGID: %s\r", fmsg->msgid_s); + else if (fmsg->msgid_a) + fprintf(pkt, "\1MSGID: %s %08lx\r", + fmsg->msgid_a, + fmsg->msgid_n); + + if (fmsg->reply_s) + fprintf(pkt, "\1REPLY: %s\r", fmsg->reply_s); + else if (fmsg->reply_a) + fprintf(pkt, "\1REPLY: %s %08lx\r", + fmsg->reply_a, + fmsg->reply_n); + + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + fprintf(pkt, "\001PID: %s %s\r", Pid, VERSION); + fprintf(pkt, "\001TZUTC: %s\r", gmtoffset(Now)); + if (ferror(pkt)) + return NULL; + else + return pkt; +} + + + +void tidy_ftnmsg(ftnmsg *tmsg) +{ + if (tmsg == NULL) + return; + + tmsg->flags = 0; + if (tmsg->to) + tidy_faddr(tmsg->to); + tmsg->to=NULL; + if (tmsg->from) + tidy_faddr(tmsg->from); + tmsg->from=NULL; + if (tmsg->subj) + free(tmsg->subj); + tmsg->subj=NULL; + if (tmsg->msgid_s) + free(tmsg->msgid_s); + tmsg->msgid_s=NULL; + if (tmsg->msgid_a) + free(tmsg->msgid_a); + tmsg->msgid_a=NULL; + if (tmsg->reply_s) + free(tmsg->reply_s); + tmsg->reply_s=NULL; + if (tmsg->reply_a) + free(tmsg->reply_a); + tmsg->reply_a=NULL; + if (tmsg->origin) + free(tmsg->origin); + tmsg->origin=NULL; + if (tmsg->area) + free(tmsg->area); + tmsg->area=NULL; + free(tmsg); +} + + diff --git a/lib/ftscprod.006 b/lib/ftscprod.006 new file mode 100644 index 00000000..03483616 --- /dev/null +++ b/lib/ftscprod.006 @@ -0,0 +1,289 @@ +0000,Fido,MS-DOS,Packer/mailer,Tom_Jennings,1:125/111 +0001,Rover,MS-DOS,Packer/mailer,Bob_Hartman,1:104/501 +0002,SEAdog,MS-DOS,Packer/mailer,Thom_Henderson,1:107/542.1 +0003,WinDog,MS-DOS,Mailer,Solar_Wind_Computing,1:115/333 +0004,Slick-150,HP-150,Packer/mailer,Jerry_Bain,???? +0005,Opus,MS-DOS,Packer/mailer,Doug_Boone,1:124/4227 +0006,Dutchie,MS-DOS,Packer/mailer,Henk_Wevers,2:500/1 +0007,WPL_Library,Amiga,Mailer,Russell_McOrmand,1:163/109 +0008,Tabby,Macintosh,Packer/mailer,Michael_Connick,1:107/412 +0009,SWMail,OS/2,Mailer,Solar_Wind_Computing,1:115/333 +000A,Wolf-68k,CPM-68k,Packer/mailer,Robert_Heller,1:321/153 +000B,QMM,QNX,Packer/mailer,Rick_Duff,1:167/201 +000C,FrontDoor,MS-DOS,Packer/mailer,Joaquim_Homrighausen,2:270/17 +000D,GOmail,MS-DOS,Packer,Scott_Green,???? +000E,FFGate,MS-DOS,Packer,Ruedi_Kneubuehler,2:301/580 +000F,FileMgr,MS-DOS,Packer,Erik_van_Emmerik,2:281/611 +0010,FIDZERCP,MS-DOS,Packer,Thorsten_Seidel,2:242/55 +0011,MailMan,MS-DOS,Packer,Ron_Bemis,1:124/1113 +0012,OOPS,MS-DOS,Packer,Tom_Kashuba,1:322/379 +0013,GS-Point,Atari_ST,Packer/mailer,Harry_Lee,1:124/4230 +0014,BGMail,????,????,Ray_Gwinn,1:265/104 +0015,ComMotion/2,OS/2,Packer/mailer,Michael_Buenter,2:301/602 +0016,OurBBS_Fidomailer,MS-DOS/Unix/Coherent,Packer/mailer,Brian_Keahl,1:133/524 +0017,FidoPcb,MS-DOS,Packer,Matjaz_Koce,2:380/100 +0018,WimpLink,Archimedes,Packer/mailer,Remco_de_Vreugd,2:283/307 +0019,BinkScan,MS-DOS,Packer,Shawn_Stoddard,1:362/101 +001A,D'Bridge,MS-DOS,Packer/mailer,Chris_Irwin,1:18/68 +001B,BinkleyTerm,MS-DOS,Mailer,Vince_Perriello,1:343/491 +001C,Yankee,MS-DOS,Packer,Randy_Edwards,???? +001D,uuGate,MS-DOS,Packer,Geoff_Watts,3:690/710 +001E,Daisy,Apple_][,Packer/mailer,Raymond_&_Ken_Lo,3:700/1 +001F,Polar_Bear,????,Packer/mailer,Kenneth_McLeod,1:101/190 +0020,The-Box,MS-DOS/Atari_ST,Packer/mailer,Jac_Kersing/Arjen_Lentz,2:283/333 +0021,STARgate/2,OS/2,Packer/mailer,Shawn_Stoddard,1:362/101 +0022,TMail,MS-DOS,Packer,Larry_Lewis,3:713/600.1701 +0023,TCOMMail,MS-DOS,Packer/mailer,Mike_Ratledge,1:372/888 +0024,GIGO,MS-DOS,Packer,Jason_Fesler,1:203/7707,,940228 +0025,RBBSMail,MS-DOS,Packer,Jan_Terpstra,2:512/10 +0026,Apple-Netmail,Apple_][,Packer/mailer,Bill_Fenner,1:129/87 +0027,Chameleon,Amiga,Mailer,Juergen_Hermann,2:241/2.12 +0028,Majik_Board,MS-DOS,Packer/mailer,Dale_Barnes,1:3601/14.20 +0029,QM,MS-DOS,Packer,George_Peace,1:270/101 +002A,Point_And_Click,Amiga,Packer,Rob_Tillotson,1:201/40.302 +002B,Aurora_Three_Bundler,MS-DOS,Packer,Oliver_McDonald,???? +002C,FourDog,MS-DOS,Packer,Shay_Walters,1:376/12 +002D,MSG-PACK,MS-DOS,Packer,Tom_Hendricks,1:261/662 +002E,AMAX,MS-DOS,Packer,Alan_Applegate,1:104/36 +002F,Domain_Communication_System,????,????,Hal_Duprie,1:101/106 +0030,LesRobot,????,Packer,Lennart_Svensonn,2:501/2 +0031,Rose,MS-DOS,Packer/mailer,Glen_Jackson,1:100/617 +0032,Paragon,Amiga,Packer/mailer,Jon_Radoff,1:322/545 +0033,BinkleyTerm/oMMM/ST,Atari_ST,Packer/mailer,Bill_Scull,1:363/112,,19951209 +0034,StarNet,Atari_ST,Mailer,Eric_Drewry,1:322/566 +0035,ZzyZx,MS-DOS,Packer,Jason_Steck,1:124/424 +0036,QEcho,MS-DOS,Packer,The_QuickBBS_Group,1:363/1701 +0037,BOOM,MS-DOS,Packer,Andrew_Farmer,1:243/1 +0038,PBBS,Amiga,Packer/mailer,Todd_Kover,1:261/1028 +0039,TrapDoor,Amiga,Mailer,Maximilian_Hantsch,2:310/6 +003A,Welmat,Amiga,Mailer,Russell_McOrmand,1:163/109 +003B,NetGate,Unix-386,Packer,David_Nugent,3:632/348 +003C,Odie,MS-DOS,Mailer,Matt_Farrenkopf,1:105/376 +003D,Quick_Gimme,CPM-80/MS-DOS,Packer/mailer,Laeeth_Isaacs,2:254/18 +003E,dbLink,MS-DOS,Packer/mailer,Chris_Irwin,1:18/68 +003F,TosScan,MS-DOS,Packer,Joaquim_Homrighausen,2:270/17 +0040,Beagle,MS-DOS,Mailer,Alexander_Holy,2:310/90 +0041,Igor,MS-DOS,Mailer,Harry_Lee,1:124/4230 +0042,TIMS,MS-DOS,Packer/mailer,Bit_Bucket_Software,1:104/501 +0043,Phoenix,MS-DOS,Packer/mailer,International_Telecommunications,1:296/5,,19930624 +0044,FrontDoor_APX,MS-DOS,Packer/mailer,Joaquim_Homrighausen,2:270/17 +0045,XRS,MS-DOS,Packer,Mike_Ratledge,1:372/888 +0046,Juliet_Mail_System,Amiga,Packer,Gregory_Kritsch,1:163/109.30 +0047,Jabberwocky,Macintosh,Packer,Eric_Larson,1:2605/620 +0048,XST,MS-DOS,Packer,Wayne_Michaels,1:380/100 +0049,MailStorm,Amiga,Packer,Russel_Miranda,1:268/106 +004A,BIX-Mail,????,Mailer,Bob_Hartman,1:104/501 +004B,IMAIL,MS-DOS,Packer,IMAIL_INC.,2:246/47 +004C,FTNGate,MS-DOS,Packer,Jason_Steck,1:104/424 +004D,RealMail,MS-DOS,Packer,Taine_Gilliam,1:372/42 +004E,Lora-CBIS,MS-DOS,Mailer,Marco_Maccaferri,2:332/402 +004F,TDCS,PDP-11,Packer/mailer,Terry_Ebdon,2:254/6 +0050,InterMail,MS-DOS,Packer/mailer,Peter_Stewart,1:369/35 +0051,RFD,MS-DOS,Packer,Doug_Belkofer,1:234/10 +0052,Yuppie!,MS-DOS,Packer,Leo_Moll,2:242/2 +0053,EMMA,MS-DOS,Packer,Johan_Zwiekhorst,2:292/100 +0054,QBoxMail,QDOS,Packer/mailer,Jan_Bredenbeek,2:283/500 +0055,Number_4,MS-DOS,Packer/mailer,Ola_Garstad,2:502/15 +0056,Number_5,MS-DOS,Packer/mailer,Ola_Garstad,2:502/15 +0057,GSBBS,MS-DOS,Packer,Michelangelo_Jones,1:260/244 +0058,Merlin,MS-DOS,Packer/mailer,Mark_Lewis,2:258/25 +0059,TPCS,MS-DOS,Packer,Mikael_Kjellstrom,2:201/211 +005A,Raid,MS-DOS,Packer,George_Peace,1:270/101 +005B,Outpost,MS-DOS,Packer/mailer,Mike_Dailor,???? +005C,Nizze,MS-DOS,Packer,Tomas_Nielsen,2:205/202 +005D,Armadillo,Macintosh,Packer,Erik_Sea,1:221/109 +005E,rfmail,Unix,Packer/mailer,Per_Lindqvist,2:201/332 +005F,Msgtoss,MS-DOS,Packer,Mike_Zakharoff,1:343/36 +0060,InfoTex,MS-DOS,Packer/mailer,Jan_Spooren,2:292/852 +0061,GEcho,MS-DOS,Packer,Gerard_van_der_Land,2:283/555,951209 +0062,CDEhost,MS-DOS,Packer,Dennis_D'Annunzio,1:379/28 +0063,Pktize,MS-DOS,Packer,Joaquim_Homrighausen,2:270/17 +0064,PC-RAIN,MS-DOS,Packer/mailer,Ray_Hyder,1:272/40 +0065,Truffle,MS-DOS/OS2,Mailer,Mike_Rissa,2:504/59 +0066,Foozle,Amiga,Packer,Peer_Hasselmeyer,2:247/4 +0067,White_Pointer,Macintosh,Packer/mailer,Alastair_Rakine,3:680/820 +0068,GateWorks,MS-DOS,Packer,Jamie_Penner,1:153/1025 +0069,Portal_of_Power,MS-DOS,Mailer,Soren_Ager,2:230/12 +006A,MacWoof,Macintosh,Packer/mailer,Craig_Vaughan,1:109/342 +006B,Mosaic,MS-DOS,Packer,Christopher_King,1:103/315 +006C,TPBEcho,MS-DOS,Packer,Gerd_Qualmann,2:242/1 +006D,HandyMail,MS-DOS,Packer/mailer,jim_nutt,1:114/30 +006E,EchoSmith,MS-DOS,Packer,Noel_Crow,1:170/409 +006F,FileHost,MS-DOS,Packer,Mark_Cole,2:252/186 +0070,SFTS,MS-DOS,Packer,Bruce_Anderson,1:3402/6 +0071,Benjamin,MS-DOS,Packer/mailer,Stefan_Graf,2:245/4.5436 +0072,RiBBS,OS9_(COCO),Packer/mailer,Ron_Bihler,1:104/54 +0073,MP,MS-DOS,Packer,Ivan_Leong,6:600/28 +0074,Ping,MS-DOS,Packer,David_Nugent,3:632/348 +0075,Door2Europe,MS-DOS,Packer/mailer,Michaela_Schoebel,2:247/14 +0076,SWIFT,MS-DOS,Packer/mailer,Hanno_van_der_Maas,2:500/2 +0077,WMAIL,MS-DOS,Packer,Silvan_Calarco,2:334/100.2 +0078,RATS,MS-DOS,Packer,Jason_DeCaro,1:260/205 +0079,Harry_the_Dirty_Dog,OS2,Mailer/packer,George_Edwards,3:632/340.7 +007A,Maximus-CBCS,MS-DOS/OS2,Packer,Scott_Dudley,1:249/106 +007B,SwifEcho,MS-DOS,Packer,Dana_Bell,1:3801/8 +007C,GCChost,Amiga,Packer,Davide_Massarenti,2:332/505.3 +007D,RPX-Mail,MS-DOS,Packer,Joerg_Wirtgen,2:241/4034 +007E,Tosser,MS-DOS,Packer,Albert_Ng,6:700/185 +007F,TCL,MS-DOS,Packer,Ulf_Hedlund,2:201/602 +0080,MsgTrack,MS-DOS,Packer,Andrew_Farmer,1:243/1 +0081,FMail,MS-DOS/DOS_DPMI/OS2/WIN32,Packer,Folkert_Wijnstra,2:283/619 +0082,Scantoss,MS-DOS,Packer,Michael_Matter,2:243/44.3443 +0083,Point_Manager,Amiga,Packer,Pino_Aliberti,2:335/602.2,,19931012 +0084,IMBINK,MS-DOS,Packer,Mike_Hartmann,2:246/48 +0085,Simplex,MS-DOS/OS2,Packer,Chris_Laforet,1:152/401 +0086,UMTP,MS-DOS,Packer,Byron_Copeland,1:272/26 +0087,Indaba,MS-DOS,Packer,Pieter_Muller,5:7102/11 +0088,Echomail_Engine,MS-DOS,Packer,Joe_Jared,1:103/200 +0089,DragonMail,OS2,Packer,Patrick_O'Riva,1:143/37 +008A,Prox,MS-DOS,Packer,Gerhard_Hoogterp,2:283/1.2 +008B,Tick,MS-DOS/OS2,Packer,Barry_Geller,1:266/12 +008C,RA-Echo,MS-DOS,Packer,Roger_Kirchhoff,2:245/4 +008D,TrapToss,Amiga,Packer,Maximilian_Hantsch,2:310/6 +008E,Babel,MS-DOS/OS2,Packer,Jorgen_Abrahamsen,2:230/100.9 +008F,UMS,Amiga,Packer,Martin_Horneffer,2:242/7.9 +0090,RWMail,MS-DOS,Packer,Remko_Westrik,2:285/309.5 +0091,WildMail,MS-DOS,Packer,Derek_Koopowitz,1:161/502 +0092,AlMAIL,MS-DOS,Packer,Alan_Leung,1:348/207 +0093,XCS,MS-DOS,Packer,Rudi_Kusters,2:512/34.4 +0094,Fone-Link,MS-DOS,Packer/mailer,Chris_Sloyan,1:269/602 +0095,Dogfight,MS-DOS,Packer,Chris_Tyson,2:256/36 +0096,Ascan,MS-DOS,Packer,Arjen_van_Loon,2:281/1.397 +0097,FastMail,MS-DOS,Packer,Jan_Berends,2:282/5 +0098,DoorMan,MS-DOS,Mailer,Christopher_Dean,1:105/70 +0099,PhaedoZap,Atari_ST,Packer,Jeff_Mitchell,1:229/422 +009A,SCREAM,MS-DOS,Packer/mailer,Jem_Miller,1:147/33 +009B,MoonMail,MS-DOS,Packer/mailer,Hasse_Wigdahl,2:206/101 +009C,Backdoor,Sinclair_QL,Packer,Erik_Slagter,2:283/500.3 +009D,MailLink,Archimedes,Packer/mailer,Jan-Jaap_v._d._Geer,2:500/133.1138 +009E,Mail_Manager,MS-DOS,Packer,Andreas_Brodowski,2:241/4006 +009F,Black_Star,Xenix_386,Packer/mailer,Jac_Kersing,2:283/333 +00A0,Bermuda,Atari_ST/MS-DOS,Packer,Jac_Kersing,2:283/333 +00A1,PT,MS-DOS,Packer/mailer,Jerry_Andrew,1:109/426 +00A2,UltiMail,MS-DOS,Mailer,Brett_Floren,1:363/1000 +00A3,GMD,MS-DOS,Packer,John_Souvestre,1:396/1 +00A4,FreeMail,MS-DOS,Packer,Chad_Nelson,1:109/536 +00A5,Meliora,MS-DOS,Packer,Erik_van_Riper,1:107/230 +00A6,Foodo,CPM-80,Packer/mailer,Ron_Murray,3:690/640.7 +00A7,MSBBS,CPM-80,Packer,Marc_Newman,1:106/601 +00A8,Boston_BBS,MS-DOS,Packer/mailer,Tom_Bradford,1:101/625 +00A9,XenoMail,MS-DOS,Packer/mailer,Noah_Wood,1:284/14 +00AA,XenoLink,Amiga,Packer/mailer,Jonathan_Forbes,1:250/642 +00AB,ObjectMatrix,MS-DOS,Packer,Roberto_Ceccarelli,2:332/305.1 +00AC,Milquetoast,Win3/MS-DOS,Mailer,Vince_Perriello,1:343/491 +00AD,PipBase,MS-DOS,Packer,Roberto_Piola,2:334/306 +00AE,EzyMail,MS-DOS,Packer,Peter_Davies,3:636/204 +00AF,FastEcho,MS-DOS,Packer,Tobias_Burchhardt,2:245/39 +00B0,IOS,Atari_ST/TT,Packer,Rinaldo_Visscher,2:280/3.1 +00B1,Communique,MS-DOS,Packer,Ian_Harris,3:620/251 +00B2,PointMail,MS-DOS,Packer,Michele_Clinco,2:331/302.11 +00B3,Harvey's_Robot,MS-DOS,Packer,Harvey_Parisien,1:249/114 +00B4,2daPoint,MS-DOS,Packer,Ron_Pritchett,1:376/74 +00B5,CommLink,MS-DOS,Mailer,Steve_Shapiro,1:382/35 +00B6,fronttoss,MS-DOS,Packer,Dirk_Astrath,2:241/5603 +00B7,SysopPoint,MS-DOS,Packer,Rudolf_Heeb,2:243/44 +00B8,PTMAIL,MS-DOS,Packer,Arturo_Krogulski,2:341/27.7 +00B9,MHS,MS-DOS/OS2/WINNT,Packer/mailer,Matthias_Hertzog,2:301/402,,19940310 +00BA,DLGMail,Amiga,Packer,Steve_Lewis,1:114/52 +00BB,GatePrep,MS-DOS,Packer,Andrew_Allen,1:382/92 +00BC,Spoint,MS-DOS,Packer,Conrad_Thompson,1:130/29.106 +00BD,TurboMail,MS-DOS,Packer,B._J._Weschke,1:2606/403 +00BE,FXMAIL,MS-DOS,Packer,Kenneth_Roach,1:208/401 +00BF,NextBBS,MS-DOS,Packer/mailer,Tomas_Hood,1:352/777 +00C0,EchoToss,MS-DOS,Packer,Mikel_Beck,1:107/218 +00C1,SilverBox,Amiga,Packer,David_Lebel,1:240/516 +00C2,MBMail,MS-DOS,Packer,Ruud_Uphoff,2:500/116.1928 +00C3,SkyFreq,Amiga,Packer,Luca_Spada,2:331/106 +00C4,ProMailer,Amiga,Mailer,Ivan_Pintori,2:335/311.21 +00C5,Mega_Mail,MS-DOS,Packer/mailer,Mirko_Mucko,2:242/94 +00C6,YaBom,MS-DOS,Packer,Berin_Lautenbach,3:620/248 +00C7,TachEcho,MS-DOS,Packer,Tom_Zacios,1:107/376 +00C8,XAP,MS-DOS,Packer,Jeroen_Smulders,2:512/1.8 +00C9,EZMAIL,MS-DOS,Packer,Torben_Paving,2:234/41 +00CA,Arc-Binkley,Archimedes,Mailer,Geoff_Riley,2:250/208 +00CB,Roser,MS-DOS,Packer,Chan_Kafai,6:700/158 +00CC,UU2,MS-DOS,Packer,Dmitri_Zavalishin,2:5020/32 +00CD,NMS,MS-DOS,Packer/mailer,Michiel_de.Bruijn,2:285/505.2 +00CE,BBCSCAN,Archimedes,Packer/mailer,E._G._Snel,2:512/222.17 +00CF,XBBS,MS-DOS,Packer,Mark_Kimes,1:380/16 +00D0,LoTek_Vzrul,,Packer/mailer,Kevin_Gates,gates@sasknet.sk.ca,19951229,20000122 +00D1,Private_Point_Project,MS-DOS,Packer,Oliver_von_Bueren,2:301/701 +00D2,NoSnail,MS-DOS,Packer,Eddie_Rowe,1:19/124 +00D3,SmlNet,MS-DOS,Packer,Steve_T._Gove,1:106/6 +00D4,STIR,MS-DOS,Packer,Paul_Martin,2:250/107.3 +00D5,RiscBBS,Archimedes,Packer,Carl_Declerck,2:292/500.10 +00D6,Hercules,Amiga,Packer/mailer,Andrew_Gray,1:231/590 +00D7,AMPRGATE,MS-DOS,Packer/mailer,Mike_Bilow,1:323/120.1 +00D8,BinkEMSI,MS-DOS,Mailer,Tobias_Burchhardt,2:245/39 +00D9,EditMsg,MS-DOS,Packer,G._K._Pace,1:374/26 +00DA,Roof,Amiga,Packer,Robert_Williamson,1:167/104 +00DB,QwkPkt,MS-DOS,Packer,Ross_West,1:250/412 +00DC,MARISCAN,MS-DOS,Packer,Mario_Elkati,2:341/14.9 +00DD,NewsFlash,MS-DOS,Packer,Chris_Lueders,2:241/5306 +00DE,Paradise,MS-DOS,Packer/mailer,Kenneth_Wall,1:300/5 +00DF,DogMatic-ACB,N/A,Packer/mailer,Martin_Allard,2:245/48 +00E0,T-Mail,MS-DOS,Packer/mailer,Andy_Elkin,2:5030/15 +00E1,JetMail,Atari_ST/STE/TT,Packer,Daniel_Roesen,2:243/93.8 +00E2,MainDoor,MS-DOS,Packer/mailer,Francisco_Sedano,2:341/20 +00E3,Starnet_Products,MS-DOS/OS2,Mailer/Packer,Starnet_Software_Development,1:102/925,,19951209 +00E4,BMB,Amiga,Packer,Dentato_Remo,2:335/311.33 +00E5,BNP,MS-DOS,Packer,Nathan_Moschkin,1:109/427 +00E6,MailMaster,MS-DOS,Packer/mailer,Gary_Murphy,1:130/85 +00E7,Mail_Manager_+Plus+,MS-DOS,Packer,Chip_Morrow,1:226/1240 +00E8,BloufGate,Atari_ST/Unix,Packer,Vincent_Pomey,2:320/100.2 +00E9,CrossPoint,MS-DOS,Packer/mailer,Peter_Mandrella,2:2454/97.80,19920713,19960601 +00EA,DeltaEcho,MS-DOS,Packer,Mikael_Staldal,2:201/337 +00EB,ALLFIX,MS-DOS,Packer,Harald_Harms,2:512/145 +00EC,NetWay,Archimedes,Mailer,Steve_Haslam,2:250/116.3 +00ED,MARSmail,Atari_ST,Packer,Folkert_val_Heusden,2:285/750.2,,19940122 +00EE,ITRACK,MS-DOS/OS2,Packer,Frank_Prade,2:2480/55,,19990119 +00EF,GateUtil,MS-DOS,Packer,Michael_Skurka,1:397/2.1 +00F0,Bert,MS-DOS,Packer/mailer,Arnim_Wiezer,2:241/2104.9 +00F1,Techno,MS-DOS,Packer,Patrik_Holmsten,2:203/133 +00F2,AutoMail,MS-DOS,Packer,Mats_Wallin,2:201/239 +00F3,April,Amiga,Packer,Nick_de_Jong,2:282/309.3 +00F4,Amanda,MS-DOS,Packer,David_Douthitt,1:121/99.14 +00F5,NmFwd,MS-DOS,Packer,Alberto_Pasquale,2:332/504 +00F6,FileScan,MS-DOS,Packer,Matthias_Duesterhoeft,2:241/4512.2 +00F7,FredMail,MS-DOS,Packer,Michael_Butler,3:712/515 +00F8,TP_Kom,MS-DOS,Packer/mailer,Per_Sten,2:201/124 +00F9,FidoZerb,MS-DOS,Packer,Ulrich_Schlechte,2:241/3410.12 +00FA,!!MessageBase,MS-DOS,Packer/mailer,Holger_Lembke,2:240/500.20 +00FB,EMFido,Amiga,Packer,Gary_Glendown,2:249/3.999 +00FC,GS-Toss,MS-DOS,Packer,Marco_Bungalski,2:241/2021 +00FD,QWKDoor,Atari_ST,Packer,Christian_Limpach,2:270/20.1 +00FE,No_product_id_allocated,Any,Packer,No_Author,3:3/20 +00FF,16-bit_product_id,Any,Packer/Mailer,No_Author,3:3/20 +0100,Reserved,None,None,No_Author,3:3/20,19951209 +0101,The_Brake!,Mailer,John_Gladkih,2:5051/16,19951209 +0102,Zeus_BBS,Amiga,Mailer,Alex_May,2:441/58.0,19951209 +0103,XenoPhobe-Mailer,Msdos/Windows/OS2/Linux,Mailer,Peter_Kling,1:374/969.0,19951209 +0104,None,None,None,None,0:0/0, +0105,Terminate,Msdos/Os2/Windows,Mailer/Packer,SerWiz_Comm_&_Bo_Bendtsen,2:254/261,19951209 +0106,TeleMail,Msdos,Mailer/Packer,Juergen_Weigelt,2:2453/900,19951209 +0107,CMBBS,Msdos/Os2,Mailer/Packer,Christof_Engel,2:2490/5110,19951209 +0108,Shuttle,Windows,Mailer/Packer,MCH_Development_&_Marvin_Hart,1:106/500,19951209 +0109,Quater,Amiga,Mailer,Felice_Murolo,2:335/206,19951209 +010A,Windo,Windows,Mailer,Alan_Chavis,1:147/55,19951209 +010B,Xenia,Msdos/Os2,Mailer,Arjen_Lentz,2:283/512,19960601 +010C,GMS,AmigaOS,Mailer,Mirko_Viviani,2:331/213,19960601 +010D,HNET,Msdos,???,Pedro_Jaramillo,1:102/160,19960601 +010E,Shotgun_Professional,Msdos,???,Brent_Shellenberg,1:140/146,19960621 +010F,SLIPgate,Msdos,???,Kieran_Morrissey,3:634/376,19960723 +0110,BBBS,MSDOS/OS2/NT/Amiga/Unix,Mailer/Packer,Kim_Heino,2:22/222,19980216 +0111,NewsGate,Windows/NT,Packer/Gateway,Leilo_denna_Pietra,2:335/244,19980216 +01FF,BBBS,MSDOS/OS2/NT/Amiga/Unix,Mailer/Packer,Kim_Heino,2:22/222,19980216 +02FF,NewsGate,Windows/NT,Packer/Gateway,Leilo_denna_Pietra,2:335/244,19980216 +03FF,Ravel,Macintosh,Mailer/Packer,Cyril_Moorzin,2:5030/700,19980310 +04FF,Beemail,Windows,Mailer/Packer,Andrius_Cepaitis,2:470/1,19980310 +05FF,QuickToss,DOS,Packer,Sandra_Godinez,1:387/601.3,19980310 +06FF,SpaceMail,???,Mailer,Andreas_Habicht,2:244/6121,19980710 +07FF,Argus,Windows/NT,Mailer,Max_Masyutin,2:469/84,19990216 +08FF,Hurricane,Windows/NT/Solaris,Packer,Paul_Walker,2:254/175.44,19990216 +09FF,Hub_Mailer,OS2,Mailer,Viatcheslav_Odintsov,2:5020/181,19990216 +0AFF,FDInt,MSDOS,Packer,Colin_Turner,2:443/13,19990216 +0BFF,GPMail,OS2,Mailer,Igor_Vanin,2:5030/448,19990216 +0CFF,FTrack,NT/OS2,Tracker,Fyodor_Ustinov,2:5020/79,19990313 +0DFF,Nice_Tosser,DOS/OS2/Win32,Tosser,Robert_Agababyan,2:5020/234.1,19990518 +0EFF,LuckyGate,DOS/OS2/Linux,Packer,Pavel_Gulchouck,2:463/68,19990709 +0FFF,McMail,DOS,Mailer,Simon_Slater,2:443/777,20000102 diff --git a/lib/ftscprod.c b/lib/ftscprod.c new file mode 100644 index 00000000..75d64792 --- /dev/null +++ b/lib/ftscprod.c @@ -0,0 +1,296 @@ +#include "libs.h" +#include "structs.h" +#include "common.h" + +struct _ftscprod ftscprod[] = { + {0x0000,(char *)"Fido"}, + {0x0001,(char *)"Rover"}, + {0x0002,(char *)"SEAdog"}, + {0x0003,(char *)"WinDog"}, + {0x0004,(char *)"Slick-150"}, + {0x0005,(char *)"Opus"}, + {0x0006,(char *)"Dutchie"}, + {0x0007,(char *)"WPL_Library"}, + {0x0008,(char *)"Tabby"}, + {0x0009,(char *)"SWMail"}, + {0x000A,(char *)"Wolf-68k"}, + {0x000B,(char *)"QMM"}, + {0x000C,(char *)"FrontDoor"}, + {0x000D,(char *)"GOmail"}, + {0x000E,(char *)"FFGate"}, + {0x000F,(char *)"FileMgr"}, + {0x0010,(char *)"FIDZERCP"}, + {0x0011,(char *)"MailMan"}, + {0x0012,(char *)"OOPS"}, + {0x0013,(char *)"GS-Point"}, + {0x0014,(char *)"BGMail"}, + {0x0015,(char *)"ComMotion/2"}, + {0x0016,(char *)"OurBBS_Fidomailer"}, + {0x0017,(char *)"FidoPcb"}, + {0x0018,(char *)"WimpLink"}, + {0x0019,(char *)"BinkScan"}, + {0x001A,(char *)"D'Bridge"}, + {0x001B,(char *)"BinkleyTerm"}, + {0x001C,(char *)"Yankee"}, + {0x001D,(char *)"uuGate"}, + {0x001E,(char *)"Daisy"}, + {0x001F,(char *)"Polar_Bear"}, + {0x0020,(char *)"The-Box"}, + {0x0021,(char *)"STARgate/2"}, + {0x0022,(char *)"TMail"}, + {0x0023,(char *)"TCOMMail"}, + {0x0024,(char *)"GIGO"}, + {0x0025,(char *)"RBBSMail"}, + {0x0026,(char *)"Apple-Netmail"}, + {0x0027,(char *)"Chameleon"}, + {0x0028,(char *)"Majik_Board"}, + {0x0029,(char *)"QM"}, + {0x002A,(char *)"Point_And_Click"}, + {0x002B,(char *)"Aurora_Three_Bundler"}, + {0x002C,(char *)"FourDog"}, + {0x002D,(char *)"MSG-PACK"}, + {0x002E,(char *)"AMAX"}, + {0x002F,(char *)"Domain_Communication_System"}, + {0x0030,(char *)"LesRobot"}, + {0x0031,(char *)"Rose"}, + {0x0032,(char *)"Paragon"}, + {0x0033,(char *)"BinkleyTerm/oMMM/ST"}, + {0x0034,(char *)"StarNet"}, + {0x0035,(char *)"ZzyZx"}, + {0x0036,(char *)"QEcho"}, + {0x0037,(char *)"BOOM"}, + {0x0038,(char *)"PBBS"}, + {0x0039,(char *)"TrapDoor"}, + {0x003A,(char *)"Welmat"}, + {0x003B,(char *)"NetGate"}, + {0x003C,(char *)"Odie"}, + {0x003D,(char *)"Quick_Gimme"}, + {0x003E,(char *)"dbLink"}, + {0x003F,(char *)"TosScan"}, + {0x0040,(char *)"Beagle"}, + {0x0041,(char *)"Igor"}, + {0x0042,(char *)"TIMS"}, + {0x0043,(char *)"Phoenix"}, + {0x0044,(char *)"FrontDoor_APX"}, + {0x0045,(char *)"XRS"}, + {0x0046,(char *)"Juliet_Mail_System"}, + {0x0047,(char *)"Jabberwocky"}, + {0x0048,(char *)"XST"}, + {0x0049,(char *)"MailStorm"}, + {0x004A,(char *)"BIX-Mail"}, + {0x004B,(char *)"IMAIL"}, + {0x004C,(char *)"FTNGate"}, + {0x004D,(char *)"RealMail"}, + {0x004E,(char *)"Lora-CBIS"}, + {0x004F,(char *)"TDCS"}, + {0x0050,(char *)"InterMail"}, + {0x0051,(char *)"RFD"}, + {0x0052,(char *)"Yuppie!"}, + {0x0053,(char *)"EMMA"}, + {0x0054,(char *)"QBoxMail"}, + {0x0055,(char *)"Number_4"}, + {0x0056,(char *)"Number_5"}, + {0x0057,(char *)"GSBBS"}, + {0x0058,(char *)"Merlin"}, + {0x0059,(char *)"TPCS"}, + {0x005A,(char *)"Raid"}, + {0x005B,(char *)"Outpost"}, + {0x005C,(char *)"Nizze"}, + {0x005D,(char *)"Armadillo"}, + {0x005E,(char *)"rfmail"}, + {0x005F,(char *)"Msgtoss"}, + {0x0060,(char *)"InfoTex"}, + {0x0061,(char *)"GEcho"}, + {0x0062,(char *)"CDEhost"}, + {0x0063,(char *)"Pktize"}, + {0x0064,(char *)"PC-RAIN"}, + {0x0065,(char *)"Truffle"}, + {0x0066,(char *)"Foozle"}, + {0x0067,(char *)"White_Pointer"}, + {0x0068,(char *)"GateWorks"}, + {0x0069,(char *)"Portal_of_Power"}, + {0x006A,(char *)"MacWoof"}, + {0x006B,(char *)"Mosaic"}, + {0x006C,(char *)"TPBEcho"}, + {0x006D,(char *)"HandyMail"}, + {0x006E,(char *)"EchoSmith"}, + {0x006F,(char *)"FileHost"}, + {0x0070,(char *)"SFTS"}, + {0x0071,(char *)"Benjamin"}, + {0x0072,(char *)"RiBBS"}, + {0x0073,(char *)"MP"}, + {0x0074,(char *)"Ping"}, + {0x0075,(char *)"Door2Europe"}, + {0x0076,(char *)"SWIFT"}, + {0x0077,(char *)"WMAIL"}, + {0x0078,(char *)"RATS"}, + {0x0079,(char *)"Harry_the_Dirty_Dog"}, + {0x007A,(char *)"Maximus-CBCS"}, + {0x007B,(char *)"SwifEcho"}, + {0x007C,(char *)"GCChost"}, + {0x007D,(char *)"RPX-Mail"}, + {0x007E,(char *)"Tosser"}, + {0x007F,(char *)"TCL"}, + {0x0080,(char *)"MsgTrack"}, + {0x0081,(char *)"FMail"}, + {0x0082,(char *)"Scantoss"}, + {0x0083,(char *)"Point_Manager"}, + {0x0084,(char *)"IMBINK"}, + {0x0085,(char *)"Simplex"}, + {0x0086,(char *)"UMTP"}, + {0x0087,(char *)"Indaba"}, + {0x0088,(char *)"Echomail_Engine"}, + {0x0089,(char *)"DragonMail"}, + {0x008A,(char *)"Prox"}, + {0x008B,(char *)"Tick"}, + {0x008C,(char *)"RA-Echo"}, + {0x008D,(char *)"TrapToss"}, + {0x008E,(char *)"Babel"}, + {0x008F,(char *)"UMS"}, + {0x0090,(char *)"RWMail"}, + {0x0091,(char *)"WildMail"}, + {0x0092,(char *)"AlMAIL"}, + {0x0093,(char *)"XCS"}, + {0x0094,(char *)"Fone-Link"}, + {0x0095,(char *)"Dogfight"}, + {0x0096,(char *)"Ascan"}, + {0x0097,(char *)"FastMail"}, + {0x0098,(char *)"DoorMan"}, + {0x0099,(char *)"PhaedoZap"}, + {0x009A,(char *)"SCREAM"}, + {0x009B,(char *)"MoonMail"}, + {0x009C,(char *)"Backdoor"}, + {0x009D,(char *)"MailLink"}, + {0x009E,(char *)"Mail_Manager"}, + {0x009F,(char *)"Black_Star"}, + {0x00A0,(char *)"Bermuda"}, + {0x00A1,(char *)"PT"}, + {0x00A2,(char *)"UltiMail"}, + {0x00A3,(char *)"GMD"}, + {0x00A4,(char *)"FreeMail"}, + {0x00A5,(char *)"Meliora"}, + {0x00A6,(char *)"Foodo"}, + {0x00A7,(char *)"MSBBS"}, + {0x00A8,(char *)"Boston_BBS"}, + {0x00A9,(char *)"XenoMail"}, + {0x00AA,(char *)"XenoLink"}, + {0x00AB,(char *)"ObjectMatrix"}, + {0x00AC,(char *)"Milquetoast"}, + {0x00AD,(char *)"PipBase"}, + {0x00AE,(char *)"EzyMail"}, + {0x00AF,(char *)"FastEcho"}, + {0x00B0,(char *)"IOS"}, + {0x00B1,(char *)"Communique"}, + {0x00B2,(char *)"PointMail"}, + {0x00B3,(char *)"Harvey's_Robot"}, + {0x00B4,(char *)"2daPoint"}, + {0x00B5,(char *)"CommLink"}, + {0x00B6,(char *)"fronttoss"}, + {0x00B7,(char *)"SysopPoint"}, + {0x00B8,(char *)"PTMAIL"}, + {0x00B9,(char *)"MHS"}, + {0x00BA,(char *)"DLGMail"}, + {0x00BB,(char *)"GatePrep"}, + {0x00BC,(char *)"Spoint"}, + {0x00BD,(char *)"TurboMail"}, + {0x00BE,(char *)"FXMAIL"}, + {0x00BF,(char *)"NextBBS"}, + {0x00C0,(char *)"EchoToss"}, + {0x00C1,(char *)"SilverBox"}, + {0x00C2,(char *)"MBMail"}, + {0x00C3,(char *)"SkyFreq"}, + {0x00C4,(char *)"ProMailer"}, + {0x00C5,(char *)"Mega_Mail"}, + {0x00C6,(char *)"YaBom"}, + {0x00C7,(char *)"TachEcho"}, + {0x00C8,(char *)"XAP"}, + {0x00C9,(char *)"EZMAIL"}, + {0x00CA,(char *)"Arc-Binkley"}, + {0x00CB,(char *)"Roser"}, + {0x00CC,(char *)"UU2"}, + {0x00CD,(char *)"NMS"}, + {0x00CE,(char *)"BBCSCAN"}, + {0x00CF,(char *)"XBBS"}, + {0x00D0,(char *)"LoTek_Vzrul"}, + {0x00D1,(char *)"Private_Point_Project"}, + {0x00D2,(char *)"NoSnail"}, + {0x00D3,(char *)"SmlNet"}, + {0x00D4,(char *)"STIR"}, + {0x00D5,(char *)"RiscBBS"}, + {0x00D6,(char *)"Hercules"}, + {0x00D7,(char *)"AMPRGATE"}, + {0x00D8,(char *)"BinkEMSI"}, + {0x00D9,(char *)"EditMsg"}, + {0x00DA,(char *)"Roof"}, + {0x00DB,(char *)"QwkPkt"}, + {0x00DC,(char *)"MARISCAN"}, + {0x00DD,(char *)"NewsFlash"}, + {0x00DE,(char *)"Paradise"}, + {0x00DF,(char *)"DogMatic-ACB"}, + {0x00E0,(char *)"T-Mail"}, + {0x00E1,(char *)"JetMail"}, + {0x00E2,(char *)"MainDoor"}, + {0x00E3,(char *)"Starnet_Products"}, + {0x00E4,(char *)"BMB"}, + {0x00E5,(char *)"BNP"}, + {0x00E6,(char *)"MailMaster"}, + {0x00E7,(char *)"Mail_Manager_+Plus+"}, + {0x00E8,(char *)"BloufGate"}, + {0x00E9,(char *)"CrossPoint"}, + {0x00EA,(char *)"DeltaEcho"}, + {0x00EB,(char *)"ALLFIX"}, + {0x00EC,(char *)"NetWay"}, + {0x00ED,(char *)"MARSmail"}, + {0x00EE,(char *)"ITRACK"}, + {0x00EF,(char *)"GateUtil"}, + {0x00F0,(char *)"Bert"}, + {0x00F1,(char *)"Techno"}, + {0x00F2,(char *)"AutoMail"}, + {0x00F3,(char *)"April"}, + {0x00F4,(char *)"Amanda"}, + {0x00F5,(char *)"NmFwd"}, + {0x00F6,(char *)"FileScan"}, + {0x00F7,(char *)"FredMail"}, + {0x00F8,(char *)"TP_Kom"}, + {0x00F9,(char *)"FidoZerb"}, + {0x00FA,(char *)"!!MessageBase"}, + {0x00FB,(char *)"EMFido"}, + {0x00FC,(char *)"GS-Toss"}, + {0x00FD,(char *)"QWKDoor"}, + {0x00FE,(char *)"No_product_id_allocated"}, + {0x00FF,(char *)"16-bit_product_id"}, + {0x0100,(char *)"Reserved"}, + {0x0101,(char *)"The_Brake!"}, + {0x0102,(char *)"Zeus_BBS"}, + {0x0103,(char *)"XenoPhobe-Mailer"}, + {0x0104,(char *)"None"}, + {0x0105,(char *)"Terminate"}, + {0x0106,(char *)"TeleMail"}, + {0x0107,(char *)"CMBBS"}, + {0x0108,(char *)"Shuttle"}, + {0x0109,(char *)"Quater"}, + {0x010A,(char *)"Windo"}, + {0x010B,(char *)"Xenia"}, + {0x010C,(char *)"GMS"}, + {0x010D,(char *)"HNET"}, + {0x010E,(char *)"Shotgun_Professional"}, + {0x010F,(char *)"SLIPgate"}, + {0x0110,(char *)"BBBS"}, + {0x0111,(char *)"NewsGate"}, + {0x01FF,(char *)"BBBS"}, + {0x02FF,(char *)"NewsGate"}, + {0x03FF,(char *)"Ravel"}, + {0x04FF,(char *)"Beemail"}, + {0x05FF,(char *)"QuickToss"}, + {0x06FF,(char *)"SpaceMail"}, + {0x07FF,(char *)"Argus"}, + {0x08FF,(char *)"Hurricane"}, + {0x09FF,(char *)"Hub_Mailer"}, + {0x0AFF,(char *)"FDInt"}, + {0x0BFF,(char *)"GPMail"}, + {0x0CFF,(char *)"FTrack"}, + {0x0DFF,(char *)"Nice_Tosser"}, + {0x0EFF,(char *)"LuckyGate"}, + {0x0FFF,(char *)"McMail"}, + {0xff,(char*)0L} +}; diff --git a/lib/getheader.c b/lib/getheader.c new file mode 100644 index 00000000..e8aa010d --- /dev/null +++ b/lib/getheader.c @@ -0,0 +1,188 @@ +/***************************************************************************** + * + * File ..................: getheader.c + * Purpose ...............: Read fidonet .pkt header + * Last modification date : 29-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#define DB_NODES + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +faddr pktfrom; +char pktpwd[9]; + + +/* + * Return codes: + * 0 - All Seems Well + * 1 - Invalid type (not 2 or 2+) + * 2 - Read header error + * 3 - Not for me + * 4 - Password error + */ +int getheader(faddr *f, faddr *t, FILE *pkt, char *pname) +{ + unsigned char buffer[0x3a]; + int i, pwdok; + int capword, prodx; + int major, minor = 0; + int tome = FALSE; + char *p, *prodn = NULL; + char buf[5]; + long year, month, day, hour, min, sec; + + f->domain = NULL; + f->name = NULL; + t->domain = NULL; + t->name = NULL; + + /* + * Read type 2+ packet header, see FSC-0039 version 4 + * and FTS-0001 + */ + if (fread(buffer, 1, 0x3a, pkt) != 0x3a) { + WriteError("$Could not read header (%s)", pname); + return 2; + } + if ((buffer[0x12] + (buffer[0x13] << 8)) != 2) { + WriteError("Not a type 2 packet (%s)", pname); + return 1; + } + + f->node = (buffer[0x01] << 8) + buffer[0x00]; + t->node = (buffer[0x03] << 8) + buffer[0x02]; + f->net = (buffer[0x15] << 8) + buffer[0x14]; + t->net = (buffer[0x17] << 8) + buffer[0x16]; + f->zone = (buffer[0x23] << 8) + buffer[0x22]; + t->zone = (buffer[0x25] << 8) + buffer[0x24]; + + year = (buffer[0x05] << 8) + buffer[0x04]; + month = (buffer[0x07] << 8) + buffer[0x06] + 1; + day = (buffer[0x09] << 8) + buffer[0x08]; + hour = (buffer[0x0b] << 8) + buffer[0x0a]; + min = (buffer[0x0d] << 8) + buffer[0x0c]; + sec = (buffer[0x0f] << 8) + buffer[0x0e]; + prodx = buffer[0x18]; + major = buffer[0x19]; + + capword = (buffer[0x2d] << 8) + buffer[0x2c]; + if (capword != ((buffer[0x28] << 8) + buffer[0x29])) + capword = 0; + + if (capword & 0x0001) { + /* + * FSC-0039 packet type 2+ + */ + prodx = prodx + (buffer[0x2a] << 8); + minor = buffer[0x2b]; + f->zone = buffer[0x2e] + (buffer[0x2f] << 8); + t->zone = buffer[0x30] + (buffer[0x31] << 8); + f->point = buffer[0x32] + (buffer[0x33] << 8); + t->point = buffer[0x34] + (buffer[0x35] << 8); + } + + for (i = 0; i < 8; i++) + pktpwd[i] = buffer[0x1a + i]; + pktpwd[8]='\0'; + for (p = pktpwd + 7; (p >= pktpwd) && (*p == ' '); p--) *p='\0'; + if (pktpwd[0]) + f->name = pktpwd; + + /* + * Fill in a default product code in case it doesn't exist + */ + sprintf(buf, "%04x", prodx); + prodn = xstrcpy((char *)"Unknown 0x"); + prodn = xstrcat(prodn, buf); + for (i = 0; ftscprod[i].name; i++) + if (ftscprod[i].code == prodx) { + free(prodn); + prodn = xstrcpy(ftscprod[i].name); + break; + } + + pktfrom.name = NULL; + pktfrom.domain = NULL; + pktfrom.zone = f->zone; + pktfrom.net = f->net; + pktfrom.node = f->node; + if (capword & 0x0001) + pktfrom.point = f->point; + else + pktfrom.point = 0; + + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && + ((t->zone == 0) || (t->zone == CFG.aka[i].zone)) && + (t->net == CFG.aka[i].net) && + (t->node == CFG.aka[i].node) && + ((!(capword & 0x0001)) || (t->point == CFG.aka[i].point))) + tome = TRUE; + } + + Syslog('+', "Packet : %s type %s", pname, (capword & 0x0001) ? "2+":"stone-age"); + Syslog('+', "From : %s to %s", xstrcpy(ascfnode(f, 0x1f)), xstrcpy(ascfnode(t,0x1f))); + Syslog('+', "Dated : %02u-%02u-%u %02u:%02u:%02u", day, month, year, hour, min, sec); + Syslog('+', "Program : %s %d.%d", prodn, major, minor); + + if (capword & 0x0001) { + buf[0] = buffer[0x36]; + buf[1] = buffer[0x37]; + buf[2] = buffer[0x38]; + buf[3] = buffer[0x39]; + buf[4] = '\0'; + } + + pwdok = TRUE; + if (noderecord(f)) { + if (strcasecmp(nodes.Epasswd, pktpwd) != 0) { + pwdok = FALSE; + if (strlen(pktpwd)) + Syslog('!', "Password : got \"%s\", expected \"%s\"", pktpwd, nodes.Epasswd); + } + } else { + Syslog('+', "Node not in setup"); + } + + if (prodn) + free(prodn); + + if (!tome) + return 3; + else if (!pwdok && nodes.MailPwdCheck) + return 4; + else + return 0; +} + + diff --git a/lib/gmtoffset.c b/lib/gmtoffset.c new file mode 100644 index 00000000..5d81fe55 --- /dev/null +++ b/lib/gmtoffset.c @@ -0,0 +1,169 @@ +/***************************************************************************** + * + * File ..................: gmtoffset.c + * Purpose ...............: Calculate UTC offset + * Last modification date : 18-Dec-1999 + * Source ................: Eugene G. Crosser's ifmail package. + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + + +/* + * Returns the offset from your location to UTC. So in the MET timezone + * this returns -60 (wintertime). People in the USA get positive results. + */ +long gmt_offset(time_t now) +{ + struct tm ptm; + struct tm gtm; + long offset; + + if (!now) + time(&now); + ptm = *localtime(&now); + + /* + * To get the timezone, compare localtime with GMT. + */ + gtm = *gmtime(&now); + + /* + * Assume we are never more than 24 hours away. + */ + offset = gtm.tm_yday - ptm.tm_yday; + if (offset > 1) + offset = -24; + else if (offset < -1) + offset = 24; + else + offset *= 24; + + /* + * Scale in the hours and minutes; ignore seconds. + */ + offset += gtm.tm_hour - ptm.tm_hour; + offset *= 60; + offset += gtm.tm_min - ptm.tm_min; + + return offset; +} + + + +/* + * Returns the TZUTC string, note that the sign is opposite from the + * function above. + */ +char *gmtoffset(time_t now) +{ + static char buf[6]="+0000"; + char sign; + int hr, min; + long offset; + + offset = gmt_offset(now); + + if (offset <= 0) { + sign = '+'; + offset = -offset; + } else + sign = '-'; + + hr = offset / 60L; + min = offset % 60L; + + if (sign == '-') + sprintf(buf, "%c%02d%02d", sign, hr, min); + else + sprintf(buf, "%02d%02d", hr, min); + + return(buf); +} + + + +char *str_time(time_t total) +{ + static char buf[10]; + int h, m; + + memset(&buf, 0, sizeof(buf)); + + /* + * 0 .. 59 seconds + */ + if (total < (time_t)60) { + sprintf(buf, "%2d.00s", (int)total); + return buf; + } + + /* + * 1:00 .. 59:59 minutes:seconds + */ + if (total < (time_t)3600) { + h = total / 60; + m = total % 60; + sprintf(buf, "%2d:%02d ", h, m); + return buf; + } + + /* + * 1:00 .. 23:59 hours:minutes + */ + if (total < (time_t)86400) { + h = (total / 60) / 60; + m = (total / 60) % 60; + sprintf(buf, "%2d:%02dm", h, m); + return buf; + } + + /* + * 1/00 .. 30/23 days/hours + */ + if (total < (time_t)2592000) { + h = (total / 3600) / 24; + m = (total / 3600) % 24; + sprintf(buf, "%2d/%02dh", h, m); + return buf; + } + + sprintf(buf, "N/A "); + return buf; +} + + + +char *t_elapsed(time_t start, time_t end) +{ + return str_time(end - start); +} + + diff --git a/lib/hdr.c b/lib/hdr.c new file mode 100644 index 00000000..10093ba2 --- /dev/null +++ b/lib/hdr.c @@ -0,0 +1,47 @@ +/***************************************************************************** + * + * File ..................: hdr.c + * Purpose ...............: Header parser + * Last modification date : 22-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + + +char *hdr(char *key, rfcmsg *msg) +{ + for (; msg; msg = msg->next) + if (!strcasecmp(key, msg->key)) { + return(msg->val); + } + return(NULL); +} + + diff --git a/lib/jam.h b/lib/jam.h new file mode 100644 index 00000000..14892a18 --- /dev/null +++ b/lib/jam.h @@ -0,0 +1,196 @@ +/* +** JAM(mbp) - The Joaquim-Andrew-Mats Message Base Proposal +** +** C API +** +** Written by Joaquim Homrighausen. +** +** ---------------------------------------------------------------------- +** +** jam.h (JAMmb) +** +** Prototypes and definitions for the JAM message base format +** +** Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch, and +** Mats Wallin. ALL RIGHTS RESERVED. +** +** 93-06-28 JoHo +** Initial coding. +** +*/ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __JAM_H__ +#define __JAM_H__ + +#ifndef __JAMSYS_H__ +#include "jamsys.h" +#endif + +/* +** File extensions +*/ +#define EXT_HDRFILE ".jhr" +#define EXT_TXTFILE ".jdt" +#define EXT_IDXFILE ".jdx" +#define EXT_LRDFILE ".jlr" + +/* +** Revision level and header signature +*/ +#define CURRENTREVLEV 1 +#define HEADERSIGNATURE "JAM" + +/* +** Header file information block, stored first in all .JHR files +*/ +typedef struct + { + CHAR8 Signature[4]; /* followed by */ + UINT32 DateCreated; /* Creation date */ + UINT32 ModCounter; /* Last processed counter */ + UINT32 ActiveMsgs; /* Number of active (not deleted) msgs */ + UINT32 PasswordCRC; /* CRC-32 of password to access */ + UINT32 BaseMsgNum; /* Lowest message number in index file */ + CHAR8 RSRVD[1000]; /* Reserved space */ + } + JAMHDRINFO, _JAMDATA * JAMHDRINFOptr; + +/* +** Message status bits +*/ +#define MSG_LOCAL 0x00000001L /* Msg created locally */ +#define MSG_INTRANSIT 0x00000002L /* Msg is in-transit */ +#define MSG_PRIVATE 0x00000004L /* Private */ +#define MSG_READ 0x00000008L /* Read by addressee */ +#define MSG_SENT 0x00000010L /* Sent to remote */ +#define MSG_KILLSENT 0x00000020L /* Kill when sent */ +#define MSG_ARCHIVESENT 0x00000040L /* Archive when sent */ +#define MSG_HOLD 0x00000080L /* Hold for pick-up */ +#define MSG_CRASH 0x00000100L /* Crash */ +#define MSG_IMMEDIATE 0x00000200L /* Send Msg now, ignore restrictions */ +#define MSG_DIRECT 0x00000400L /* Send directly to destination */ +#define MSG_GATE 0x00000800L /* Send via gateway */ +#define MSG_FILEREQUEST 0x00001000L /* File request */ +#define MSG_FILEATTACH 0x00002000L /* File(s) attached to Msg */ +#define MSG_TRUNCFILE 0x00004000L /* Truncate file(s) when sent */ +#define MSG_KILLFILE 0x00008000L /* Delete file(s) when sent */ +#define MSG_RECEIPTREQ 0x00010000L /* Return receipt requested */ +#define MSG_CONFIRMREQ 0x00020000L /* Confirmation receipt requested */ +#define MSG_ORPHAN 0x00040000L /* Unknown destination */ +#define MSG_ENCRYPT 0x00080000L /* Msg text is encrypted */ +#define MSG_COMPRESS 0x00100000L /* Msg text is compressed */ +#define MSG_ESCAPED 0x00200000L /* Msg text is seven bit ASCII */ +#define MSG_FPU 0x00400000L /* Force pickup */ +#define MSG_TYPELOCAL 0x00800000L /* Msg is for local use only (not for export) */ +#define MSG_TYPEECHO 0x01000000L /* Msg is for conference distribution */ +#define MSG_TYPENET 0x02000000L /* Msg is direct network mail */ +#define MSG_NODISP 0x20000000L /* Msg may not be displayed to user */ +#define MSG_LOCKED 0x40000000L /* Msg is locked, no editing possible */ +#define MSG_DELETED 0x80000000L /* Msg is deleted */ + + +/* +** Message header +*/ +typedef struct + { + CHAR8 Signature[4]; /* followed by */ + UINT16 Revision; /* CURRENTREVLEV */ + UINT16 ReservedWord; /* Reserved */ + UINT32 SubfieldLen; /* Length of subfields */ + UINT32 TimesRead; /* Number of times message read */ + UINT32 MsgIdCRC; /* CRC-32 of MSGID line */ + UINT32 ReplyCRC; /* CRC-32 of REPLY line */ + UINT32 ReplyTo; /* This msg is a reply to.. */ + UINT32 Reply1st; /* First reply to this msg */ + UINT32 ReplyNext; /* Next msg in reply chain */ + UINT32 DateWritten; /* When msg was written */ + UINT32 DateReceived; /* When msg was received/read */ + UINT32 DateProcessed; /* When msg was processed by packer */ + UINT32 MsgNum; /* Message number (1-based) */ + UINT32 Attribute; /* Msg attribute, see "Status bits" */ + UINT32 Attribute2; /* Reserved for future use */ + UINT32 TxtOffset; /* Offset of text in text file */ + UINT32 TxtLen; /* Length of message text */ + UINT32 PasswordCRC; /* CRC-32 of password to access msg */ + UINT32 Cost; /* Cost of message */ + } + JAMHDR, _JAMDATA * JAMHDRptr; + +/* +** Message header subfield types +*/ +#define JAMSFLD_OADDRESS 0 +#define JAMSFLD_DADDRESS 1 +#define JAMSFLD_SENDERNAME 2 +#define JAMSFLD_RECVRNAME 3 +#define JAMSFLD_MSGID 4 +#define JAMSFLD_REPLYID 5 +#define JAMSFLD_SUBJECT 6 +#define JAMSFLD_PID 7 +#define JAMSFLD_TRACE 8 +#define JAMSFLD_ENCLFILE 9 +#define JAMSFLD_ENCLFWALIAS 10 +#define JAMSFLD_ENCLFREQ 11 +#define JAMSFLD_ENCLFILEWC 12 +#define JAMSFLD_ENCLINDFILE 13 +#define JAMSFLD_EMBINDAT 1000 +#define JAMSFLD_FTSKLUDGE 2000 +#define JAMSFLD_SEENBY2D 2001 +#define JAMSFLD_PATH2D 2002 +#define JAMSFLD_FLAGS 2003 +#define JAMSFLD_TZUTCINFO 2004 +#define JAMSFLD_UNKNOWN 0xffff + +/* +** Message header subfield +*/ +typedef struct + { + UINT16 LoID; /* Field ID, 0 - 0xffff */ + UINT16 HiID; /* Reserved for future use */ + UINT32 DatLen; /* Length of buffer that follows */ + CHAR8 Buffer[1]; /* DatLen bytes of data */ + } + JAMSUBFIELD, _JAMDATA * JAMSUBFIELDptr; + +typedef struct + { + UINT16 LoID; /* Field ID, 0 - 0xffff */ + UINT16 HiID; /* Reserved for future use */ + UINT32 DatLen; /* Length of buffer that follows */ + } + JAMBINSUBFIELD, _JAMDATA * JAMBINSUBFIELDptr; + +/* +** Message index record +*/ +typedef struct + { + UINT32 UserCRC; /* CRC-32 of destination username */ + UINT32 HdrOffset; /* Offset of header in .JHR file */ + } + JAMIDXREC, _JAMDATA * JAMIDXRECptr; + +/* +** Lastread structure, one per user +*/ +typedef struct + { + UINT32 UserCRC; /* CRC-32 of user name (lowercase) */ + UINT32 UserID; /* Unique UserID */ + UINT32 LastReadMsg; /* Last read message number */ + UINT32 HighReadMsg; /* Highest read message number */ + } + JAMLREAD, _JAMDATA * JAMLREADptr; + +#endif /* __JAM_H__ */ + +#ifdef __cplusplus +} +#endif + +/* end of file "jam.h" */ diff --git a/lib/jammsg.c b/lib/jammsg.c new file mode 100644 index 00000000..0e9a2038 --- /dev/null +++ b/lib/jammsg.c @@ -0,0 +1,1370 @@ +/***************************************************************************** + * + * File ..................: jammsg.c + * Purpose ...............: JAM message base functions + * Last modification date : 23-Jun-2001 + * + ***************************************************************************** + * + * Original written in C++ by Marco Maccaferri for LoraBBS and was + * distributed under GNU GPL. This version is modified for use with + * MBSE BBS and utilities. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" +#include "msgtext.h" +#include "msg.h" +#include "jam.h" +#include "jammsg.h" + +#define MAX_TEXT 2048 + +int fdHdr = -1; +int fdJdt = -1; +int fdJdx = -1; +int fdJlr = -1; +char *pSubfield; +char BaseName[PATH_MAX]; +char *pLine, *pBuff; +char szBuff[MAX_LINE_LENGTH + 1]; +char szLine[MAX_LINE_LENGTH + 1]; +JAMHDRINFO jamHdrInfo; +JAMHDR jamHdr; +unsigned long LastReadRec; + + + +unsigned long AddSubfield(unsigned int, char *); +unsigned long AddSubfield(unsigned int JamSFld, char *SubStr) +{ + JAMSUBFIELD jamSubfield; + unsigned long Len; + + jamSubfield.HiID = 0; + jamSubfield.LoID = JamSFld; + jamSubfield.DatLen = strlen(SubStr); /* + 1; */ + Len = jamSubfield.DatLen + sizeof(JAMBINSUBFIELD); + write(fdHdr, &jamSubfield, sizeof(JAMBINSUBFIELD)); + write(fdHdr, SubStr, strlen(SubStr)); /* + 1); */ + + return Len; +} + + + +void JAMset_flags(void); +void JAMset_flags() +{ + jamHdr.Attribute |= (Msg.Local) ? MSG_LOCAL : 0; + jamHdr.Attribute |= (Msg.Intransit) ? MSG_INTRANSIT : 0; + jamHdr.Attribute |= (Msg.Private) ? MSG_PRIVATE : 0; + jamHdr.Attribute |= (Msg.Received) ? MSG_READ : 0; + jamHdr.Attribute |= (Msg.Sent) ? MSG_SENT : 0; + jamHdr.Attribute |= (Msg.KillSent) ? MSG_KILLSENT : 0; + jamHdr.Attribute |= (Msg.ArchiveSent) ? MSG_ARCHIVESENT : 0; + jamHdr.Attribute |= (Msg.Hold) ? MSG_HOLD : 0; + jamHdr.Attribute |= (Msg.Crash) ? MSG_CRASH : 0; + jamHdr.Attribute |= (Msg.Immediate) ? MSG_IMMEDIATE : 0; + jamHdr.Attribute |= (Msg.Direct) ? MSG_DIRECT : 0; + jamHdr.Attribute |= (Msg.Gate) ? MSG_GATE : 0; + jamHdr.Attribute |= (Msg.FileRequest) ? MSG_FILEREQUEST : 0; + jamHdr.Attribute |= (Msg.FileAttach) ? MSG_FILEATTACH : 0; + jamHdr.Attribute |= (Msg.TruncFile) ? MSG_TRUNCFILE : 0; + jamHdr.Attribute |= (Msg.KillFile) ? MSG_KILLFILE : 0; + jamHdr.Attribute |= (Msg.ReceiptRequest) ? MSG_RECEIPTREQ : 0; + jamHdr.Attribute |= (Msg.ConfirmRequest) ? MSG_CONFIRMREQ : 0; + jamHdr.Attribute |= (Msg.Orphan) ? MSG_ORPHAN : 0; + jamHdr.Attribute |= (Msg.Encrypt) ? MSG_ENCRYPT : 0; + jamHdr.Attribute |= (Msg.Compressed) ? MSG_COMPRESS : 0; + jamHdr.Attribute |= (Msg.Escaped) ? MSG_ESCAPED : 0; + jamHdr.Attribute |= (Msg.ForcePU) ? MSG_FPU : 0; + jamHdr.Attribute |= (Msg.Localmail) ? MSG_TYPELOCAL : 0; + jamHdr.Attribute |= (Msg.Echomail) ? MSG_TYPEECHO : 0; + jamHdr.Attribute |= (Msg.Netmail) ? MSG_TYPENET : 0; + jamHdr.Attribute |= (Msg.Nodisplay) ? MSG_NODISP : 0; + jamHdr.Attribute |= (Msg.Locked) ? MSG_LOCKED : 0; + jamHdr.Attribute |= (Msg.Deleted) ? MSG_DELETED : 0; + + jamHdr.ReplyTo = Msg.Original; + jamHdr.ReplyNext = Msg.Reply; + jamHdr.DateReceived = Msg.Read; + jamHdr.MsgIdCRC = Msg.MsgIdCRC; + jamHdr.ReplyCRC = Msg.ReplyCRC; +} + + + + +/* + * Add a message, the structure msg must contain all needed + * information. + */ +int JAM_AddMsg() +{ + int i, RetVal = TRUE; + unsigned long ulMsg = JAM_Highest() + 1L; + char *pszText, *Sign= (char *)HEADERSIGNATURE; + JAMIDXREC jamIdx; + int Oke; + + memset(&jamHdr, 0, sizeof(JAMHDR)); + jamHdr.Signature[0] = Sign[0]; + jamHdr.Signature[1] = Sign[1]; + jamHdr.Signature[2] = Sign[2]; + jamHdr.Signature[3] = Sign[3]; + jamHdr.Revision = CURRENTREVLEV; + jamHdr.MsgNum = ulMsg; + + jamHdr.DateWritten = Msg.Written; + jamHdr.DateProcessed = Msg.Arrived; + + JAMset_flags(); + lseek(fdHdr, 0L, SEEK_END); + + jamIdx.UserCRC = 0; + jamIdx.HdrOffset = tell(fdHdr); + lseek(fdJdx, 0L, SEEK_END); + write(fdJdx, &jamIdx, sizeof(JAMIDXREC)); + + write(fdHdr, &jamHdr, sizeof(JAMHDR)); + + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_SENDERNAME, Msg.From); + + if (Msg.To[0]) + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_RECVRNAME, Msg.To); + + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_SUBJECT, Msg.Subject); + + if (Msg.FromAddress[0] != '\0') + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_OADDRESS, Msg.FromAddress); + + if (Msg.ToAddress[0] != '\0') + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_DADDRESS, Msg.ToAddress); + + Msg.Id = jamHdr.MsgNum; + + lseek(fdJdt, 0L, SEEK_END); + jamHdr.TxtOffset = tell(fdJdt); + jamHdr.TxtLen = 0; + + /* + * Read message text from memory, this also contains kludges. + * Extract those that are defined by the JAMmb specs, except + * the AREA: kludge. This one is only present in bad and dupe + * echomail areas and is present for tossbad and tossdupe. + */ + if ((pszText = (char *)MsgText_First ()) != NULL) + do { + if ((pszText[0] == '\001') || (!strncmp(pszText, "SEEN-BY:", 8))) { + Oke = FALSE; + + if (!strncmp(pszText, "\001PID: ", 6)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_PID, pszText + 6); + Oke = TRUE; + } + + if (!strncmp(pszText, "\001MSGID: ", 8)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_MSGID, pszText + 8); + Oke = TRUE; + } + + if (!strncmp(pszText, "\001REPLY: ", 8)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_REPLYID, pszText + 8); + Oke = TRUE; + } + + if (!strncmp(pszText, "\001PATH: ", 7)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_PATH2D, pszText + 7); + Oke = TRUE; + } + + if (!strncmp(pszText, "\001Via", 4)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_TRACE, pszText + 5); + Oke = TRUE; + } + + if (!strncmp(pszText, "SEEN-BY: ", 9)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_SEENBY2D, pszText + 9); + Oke = TRUE; + } + + /* + * Other non-JAM kludges + */ + if ((!Oke) && (pszText[0] == '\001')) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_FTSKLUDGE, pszText + 1); + Oke = TRUE; + } + + if (!Oke) { + for (i = 0; i < strlen(pszText); i++) { + if (pszText[i] < 32) + printf("<%x>", pszText[i]); + else + printf("%c", pszText[i]); + } + } + } else { + write(fdJdt, pszText, strlen (pszText)); + jamHdr.TxtLen += strlen (pszText); + write(fdJdt, "\r", 1); + jamHdr.TxtLen += 1; + } + } while ((pszText = (char *)MsgText_Next ()) != NULL); + + /* + * Write final message header + */ + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + write(fdHdr, &jamHdr, sizeof (JAMHDR)); + + + /* + * Update area information + */ + lseek(fdHdr, 0L, SEEK_SET); + read(fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)); + jamHdrInfo.ActiveMsgs++; + jamHdrInfo.ModCounter++; + lseek(fdHdr, 0L, SEEK_SET); + write(fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)); + + return RetVal; +} + + + +/* + * Close current message base + */ +void JAM_Close(void) +{ + if (fdJdx != -1) + close(fdJdx); + if (fdJdt != -1) + close(fdJdt); + if (fdHdr != -1) + close(fdHdr); + if (fdJlr != -1) + close(fdJlr); + + if (pSubfield != NULL) + free(pSubfield); + + fdHdr = fdJdt = fdJdx = fdJlr = -1; + pSubfield = NULL; + Msg.Id = 0L; +} + + + +/* + * Delete message number + */ +int JAM_Delete(unsigned long ulMsg) +{ + int RetVal = FALSE; + JAMIDXREC jamIdx; + + if (JAM_ReadHeader(ulMsg) == TRUE) { + jamHdr.Attribute |= MSG_DELETED; + + lseek(fdJdx, tell(fdJdx) - sizeof(jamIdx), SEEK_SET); + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + write(fdHdr, &jamHdr, sizeof(JAMHDR)); + + lseek(fdHdr, 0L, SEEK_SET); + read(fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)); + jamHdrInfo.ActiveMsgs--; + lseek(fdHdr, 0L, SEEK_SET); + write(fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)); + RetVal = TRUE; + } + } + + return RetVal; +} + + + +/* + * Search for requested LastRead record. + */ +int JAM_GetLastRead(lastread *LR) +{ + lastread lr; + + LastReadRec = 0L; + lseek(fdJlr, 0, SEEK_SET); + + while (read(fdJlr, &lr, sizeof(lastread)) == sizeof(lastread)) { + if (lr.UserID == LR->UserID) { + LR->LastReadMsg = lr.LastReadMsg; + LR->HighReadMsg = lr.HighReadMsg; + return TRUE; + } + LastReadRec++; + } + + return FALSE; +} + + + +/* + * Get highest message number + */ +unsigned long JAM_Highest(void) +{ + unsigned long RetVal = 0L; + JAMIDXREC jamIdx; + + if (jamHdrInfo.ActiveMsgs > 0L) { + lseek(fdJdx, filelength(fdJdx) - sizeof(jamIdx), SEEK_SET); + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof(JAMHDR)); + RetVal = jamHdr.MsgNum; + } + } + + Msg.Id = RetVal; + + return RetVal; +} + + + +int JAM_Lock(unsigned long ulTimeout) +{ +// char *File; +// int fd = -1, Tries = 0; + int Tries = 0; + struct flock fl; + + fl.l_type = F_WRLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 1L; /* GoldED locks 1 byte as well */ + fl.l_pid = getpid(); + + while (fcntl(fdHdr, F_SETLK, &fl) && ((errno == EACCES) || (errno == EAGAIN))) { + if (++Tries >= (ulTimeout * 4)) { + fcntl(fdHdr, F_GETLK, &fl); + WriteError("JAM messagebase is locked by pid %d", fl.l_pid); + return FALSE; + } + usleep(250000); + Syslog('m', "JAM messagebase lock attempt %d", Tries); + } + +// File = calloc(PATH_MAX, sizeof(char)); +// sprintf(File, "%s%s", BaseName, ".LCK"); + +// while ((fd = creat(File, 0)) == -1 && errno == EACCES) { +// if (++Tries >= ulTimeout) { +// free(File); +// return FALSE; +// } +// sleep(1); +// } +// free(File); + +// if (fd == -1) +// return FALSE; + +// close(fd); + return TRUE; +} + + + +/* + * Get lowest message number + */ +unsigned long JAM_Lowest(void) +{ + unsigned long RetVal = 0L; + JAMIDXREC jamIdx; + + if (jamHdrInfo.ActiveMsgs > 0L) { + lseek(fdJdx, 0L, SEEK_SET); + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof(JAMHDR)); + RetVal = jamHdr.MsgNum; + } + } + + Msg.Id = RetVal; + + return RetVal; +} + + + +void JAM_New(void) +{ + memset(&Msg, 0, sizeof(Msg)); + MsgText_Clear(); +} + + + +int JAM_NewLastRead(lastread LR) +{ + lseek(fdJlr, 0, SEEK_END); + return (write(fdJlr, &LR, sizeof(lastread)) == sizeof(lastread)); +} + + + +int JAM_Next(unsigned long * ulMsg) +{ + int RetVal = FALSE, MayBeNext = FALSE; + JAMIDXREC jamIdx; + unsigned long _Msg; + + _Msg = *ulMsg; + + if (jamHdrInfo.ActiveMsgs > 0L) { + // -------------------------------------------------------------------- + // The first attempt to retrive the next message number suppose that + // the file pointers are located after the current message number. + // Usually this is the 99% of the situations because the messages are + // often readed sequentially. + // -------------------------------------------------------------------- + if (tell(fdJdx) >= sizeof (jamIdx)) + lseek(fdJdx, tell(fdJdx) - sizeof(jamIdx), SEEK_SET); + do { + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof (JAMHDR)); + if (MayBeNext == TRUE) { + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum > _Msg) { + _Msg = jamHdr.MsgNum; + RetVal = TRUE; + } + } + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == _Msg) + MayBeNext = TRUE; + } + } while (RetVal == FALSE && tell(fdJdx) < filelength(fdJdx)); + + if (RetVal == FALSE && MayBeNext == FALSE) { + // -------------------------------------------------------------------- + // It seems that the file pointers are not located where they should be + // so our next attempt is to scan the database from the beginning to + // find the next message number. + // -------------------------------------------------------------------- + lseek(fdJdx, 0L, SEEK_SET); + do { + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum > _Msg) { + _Msg = jamHdr.MsgNum; + RetVal = TRUE; + } + } + } while (RetVal == FALSE && tell(fdJdx) < filelength(fdJdx)); + } + + Msg.Id = 0L; + if (RetVal == TRUE) + Msg.Id = _Msg; + } + + memcpy(ulMsg, &_Msg, sizeof(unsigned long)); + return RetVal; +} + + + +/* + * Return number of messages + */ +unsigned long JAM_Number(void) +{ + return jamHdrInfo.ActiveMsgs; +} + + + +/* + * Open specified JAM message base + */ +int JAM_Open(char *Msgbase) +{ + int RetVal = FALSE; + char *File; + char *Signature = (char *)HEADERSIGNATURE; + + fdJdt = fdJdx = fdJlr = -1; + pSubfield = NULL; + File = calloc(PATH_MAX, sizeof(char)); + + sprintf(File, "%s%s", Msgbase, EXT_HDRFILE); + if ((fdHdr = open(File, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != -1) { + if (read(fdHdr, &jamHdrInfo, sizeof(JAMHDRINFO)) != sizeof(JAMHDRINFO)) { + memset(&jamHdrInfo, 0, sizeof(JAMHDRINFO)); + jamHdrInfo.Signature[0] = Signature[0]; + jamHdrInfo.Signature[1] = Signature[1]; + jamHdrInfo.Signature[2] = Signature[2]; + jamHdrInfo.Signature[3] = Signature[3]; + jamHdrInfo.DateCreated = time(NULL); + jamHdrInfo.BaseMsgNum = 1; + + lseek(fdHdr, 0, SEEK_SET); + write(fdHdr, &jamHdrInfo, sizeof(JAMHDRINFO)); + } + + if (jamHdrInfo.Signature[0] == Signature[0] && + jamHdrInfo.Signature[1] == Signature[1] && + jamHdrInfo.Signature[2] == Signature[2] && + jamHdrInfo.Signature[3] == Signature[3]) { + sprintf(File, "%s%s", Msgbase, EXT_TXTFILE); + fdJdt = open(File, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", Msgbase, EXT_IDXFILE); + fdJdx = open(File, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", Msgbase, EXT_LRDFILE); + fdJlr = open(File, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + RetVal = TRUE; + + strcpy(BaseName, Msgbase); + } else { + close(fdHdr); + fdHdr = -1; + } + } else + memset(&jamHdrInfo, 0, sizeof(JAMHDRINFO)); + + Msg.Id = 0L; + free(File); + + return RetVal; +} + + + +/* + * Pack deleted messages from the message base. The messages are + * renumbered on the fly. LR update + */ +void JAM_Pack(void) +{ + int fdnHdr, fdnJdx, fdnJdt, fdnJlr; + int ToRead, Readed; + char *File, *New, *Subfield, *Temp; + JAMIDXREC jamIdx; + unsigned long NewNumber = 0, RefNumber = 0, Written = 0; + lastread LR; + + File = calloc(PATH_MAX, sizeof(char)); + New = calloc(PATH_MAX, sizeof(char)); + sprintf(File, "%s%s", BaseName, ".$dr"); + fdnHdr = open(File, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", BaseName, ".$dt"); + fdnJdt = open(File, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", BaseName, ".$dx"); + fdnJdx = open(File, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", BaseName, ".$lr"); + fdnJlr = open(File, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + + if (fdnHdr != -1 && fdnJdt != -1 && fdnJdx != -1 && fdnJlr != -1) { + lseek(fdHdr, 0L, SEEK_SET); + if (read(fdHdr, &jamHdrInfo, sizeof(JAMHDRINFO)) == sizeof(JAMHDRINFO)) { + write(fdnHdr, &jamHdrInfo, sizeof(JAMHDRINFO)); + while (read(fdHdr, &jamHdr, sizeof(JAMHDR)) == sizeof(JAMHDR)) { + RefNumber++; + if (strncmp(jamHdr.Signature, "JAM", 3)) { + WriteError("jamPack: %s headerfile corrupt", BaseName); + lseek(fdJdx, (RefNumber -1) * sizeof(JAMIDXREC), SEEK_SET); + read(fdJdx, &jamIdx, sizeof(JAMIDXREC)); + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof(JAMHDR)); + if ((strncmp(jamHdr.Signature, "JAM", 3) == 0) && (jamHdr.MsgNum == RefNumber)) + WriteError("jamPack: corrected the problem"); + else { + WriteError("jamPack: PANIC, problem cannot be solved, skipping this area"); + Written = 0; + break; + } + } + if (jamHdr.Attribute & MSG_DELETED) { + if (jamHdr.SubfieldLen > 0L) + lseek (fdHdr, jamHdr.SubfieldLen, SEEK_CUR); + } else { + jamIdx.UserCRC = 0; + jamIdx.HdrOffset = tell(fdnHdr); + write(fdnJdx, &jamIdx, sizeof(JAMIDXREC)); + + lseek(fdJdt, jamHdr.TxtOffset, SEEK_SET); + jamHdr.TxtOffset = tell(fdnJdt); + NewNumber++; + Written++; + + lseek(fdJlr, 0, SEEK_SET); + while (read(fdJlr, &LR, sizeof(lastread)) == sizeof(lastread)) { + /* + * Test if one of the lastread pointer is the current + * old message number. + */ + if ((LR.LastReadMsg == jamHdr.MsgNum) || (LR.HighReadMsg == jamHdr.MsgNum)) { + /* + * Adjust the matching numbers + */ + if (LR.LastReadMsg == jamHdr.MsgNum) + LR.LastReadMsg = NewNumber; + if (LR.HighReadMsg == jamHdr.MsgNum) + LR.HighReadMsg = NewNumber; + lseek(fdJlr, - sizeof(lastread), SEEK_CUR); + write(fdJlr, &LR, sizeof(lastread)); + } + } + jamHdr.MsgNum = NewNumber; + write(fdnHdr, &jamHdr, sizeof(JAMHDR)); + + if (jamHdr.SubfieldLen > 0L) { + if ((Subfield = (char *)malloc ((size_t)(jamHdr.SubfieldLen + 1))) != NULL) { + read (fdHdr, Subfield, (size_t)jamHdr.SubfieldLen); + write (fdnHdr, Subfield, (size_t)jamHdr.SubfieldLen); + free(Subfield); + } + } + + if ((Temp = (char *)malloc (MAX_TEXT)) != NULL) { + do { + if ((ToRead = MAX_TEXT) > jamHdr.TxtLen) + ToRead = (int)jamHdr.TxtLen; + Readed = (int)read (fdJdt, Temp, ToRead); + write (fdnJdt, Temp, Readed); + jamHdr.TxtLen -= Readed; + } while (jamHdr.TxtLen > 0); + free(Temp); + } + } + } + } + + /* + * Correct any errors in the header + */ + if (Written) { + lseek(fdnHdr, 0, SEEK_SET); + if (read(fdnHdr, &jamHdrInfo, sizeof(JAMHDRINFO)) == sizeof(JAMHDRINFO)) { + if (jamHdrInfo.ActiveMsgs != Written) { + WriteError("jamPack: repair msgs %lu to %lu area %s", + jamHdrInfo.ActiveMsgs, Written, BaseName); + jamHdrInfo.ActiveMsgs = Written; + lseek(fdnHdr, 0, SEEK_SET); + write(fdnHdr, &jamHdrInfo, sizeof(JAMHDRINFO)); + } + } + } + + /* + * Now copy the lastread file + */ + + lseek(fdJlr, 0, SEEK_SET); + while (read(fdJlr, &LR, sizeof(lastread)) == sizeof(lastread)) + write(fdnJlr, &LR, sizeof(lastread)); + + close(fdnHdr); + close(fdnJdt); + close(fdnJdx); + close(fdnJlr); + fdnHdr = fdnJdt = fdnJdx = fdnJlr = -1; + + close(fdHdr); + close(fdJdt); + close(fdJdx); + close(fdJlr); + fdHdr = fdJdt = fdJdx = fdJlr = -1; + + sprintf(File, "%s%s", BaseName, ".$dr"); + sprintf(New, "%s%s", BaseName, EXT_HDRFILE); + unlink(New); + rename(File, New); + sprintf(File, "%s%s", BaseName, ".$dt"); + sprintf(New, "%s%s", BaseName, EXT_TXTFILE); + unlink(New); + rename(File, New); + sprintf(File, "%s%s", BaseName, ".$dx"); + sprintf(New, "%s%s", BaseName, EXT_IDXFILE); + unlink(New); + rename(File, New); + sprintf(File, "%s%s", BaseName, ".$lr"); + sprintf(New, "%s%s", BaseName, EXT_LRDFILE); + unlink(New); + rename(File, New); + + JAM_Open(BaseName); + } + + if (fdnHdr != -1) + close(fdnHdr); + sprintf(File, "%s%s", BaseName, ".$dr"); + unlink(File); + if (fdnJdt != -1) + close(fdnJdt); + sprintf(File, "%s%s", BaseName, ".$dt"); + unlink(File); + if (fdnJdx != -1) + close(fdnJdx); + sprintf(File, "%s%s", BaseName, ".$dx"); + unlink(File); + if (fdnJlr != -1) + close(fdnJlr); + sprintf(File, "%s%s", BaseName, ".$lr"); + unlink(File); + free(File); + free(New); +} + + + +int JAM_Previous (unsigned long *ulMsg) +{ + int RetVal = FALSE, MayBeNext = FALSE; + long Pos; + JAMIDXREC jamIdx; + unsigned long _Msg; + + _Msg = *ulMsg; + + if (jamHdrInfo.ActiveMsgs > 0L) { + // -------------------------------------------------------------------- + // The first attempt to retrive the next message number suppose that + // the file pointers are located after the current message number. + // Usually this is the 99% of the situations because the messages are + // often readed sequentially. + // -------------------------------------------------------------------- + if (tell (fdJdx) >= sizeof (jamIdx)) { + Pos = tell (fdJdx) - sizeof (jamIdx); + do { + lseek (fdJdx, Pos, SEEK_SET); + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (MayBeNext == TRUE) { + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum < _Msg) { + _Msg = jamHdr.MsgNum; + RetVal = TRUE; + } + } + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == _Msg) + MayBeNext = TRUE; + } + Pos -= sizeof (jamIdx); + } while (RetVal == FALSE && Pos >= 0L); + } + + if (RetVal == FALSE && MayBeNext == FALSE) { + // -------------------------------------------------------------------- + // It seems that the file pointers are not located where they should be + // so our next attempt is to scan the database from the end to find + // the next message number. + // -------------------------------------------------------------------- + Pos = filelength (fdJdx) - sizeof (jamIdx); + do { + lseek (fdJdx, Pos, SEEK_SET); + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum < _Msg) { + _Msg = jamHdr.MsgNum; + RetVal = TRUE; + } + } + Pos -= sizeof (jamIdx); + } while (RetVal == FALSE && Pos >= 0L); + } + + Msg.Id = 0L; + if (RetVal == TRUE) + Msg.Id = _Msg; + } + + memcpy(ulMsg, &_Msg, sizeof(unsigned long)); + return (RetVal); +} + + + +int JAM_ReadHeader (unsigned long ulMsg) +{ + int i, RetVal = FALSE; + unsigned char *pPos; + unsigned long ulSubfieldLen, tmp; + JAMIDXREC jamIdx; + JAMBINSUBFIELD *jamSubField; + + tmp = Msg.Id; + JAM_New (); + Msg.Id = tmp; + + if (Msg.Id == ulMsg) { + // -------------------------------------------------------------------- + // The user is requesting the header of the last message retrived + // so our first attempt is to read the last index from the file and + // check if this is the correct one. + // -------------------------------------------------------------------- + lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET); + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } + + if (((Msg.Id + 1) == ulMsg) && (RetVal == FALSE)) { + //--------------------------------------------------------------------- + // If the user is requesting the header of the next message we attempt + // to read the next header and check if this is the correct one. + // This is EXPERIMENTAL + //--------------------------------------------------------------------- + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof(JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } + + + if (RetVal == FALSE) { + // -------------------------------------------------------------------- + // The message request is not the last retrived or the file pointers + // are not positioned where they should be, so now we attempt to + // retrive the message header scanning the database from the beginning. + // -------------------------------------------------------------------- + Msg.Id = 0L; + lseek (fdJdx, 0L, SEEK_SET); + do { + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } while (RetVal == FALSE && tell (fdJdx) < filelength (fdJdx)); + } + + if (RetVal == TRUE) { + Msg.Current = Msg.Id = ulMsg; + + Msg.Local = (unsigned char)((jamHdr.Attribute & MSG_LOCAL) ? TRUE : FALSE); + Msg.Intransit = (unsigned char)((jamHdr.Attribute & MSG_INTRANSIT) ? TRUE : FALSE); + Msg.Private = (unsigned char)((jamHdr.Attribute & MSG_PRIVATE) ? TRUE : FALSE); + Msg.Received = (unsigned char)((jamHdr.Attribute & MSG_READ) ? TRUE : FALSE); + Msg.Sent = (unsigned char)((jamHdr.Attribute & MSG_SENT) ? TRUE : FALSE); + Msg.KillSent = (unsigned char)((jamHdr.Attribute & MSG_KILLSENT) ? TRUE : FALSE); + Msg.ArchiveSent = (unsigned char)((jamHdr.Attribute & MSG_ARCHIVESENT) ? TRUE : FALSE); + Msg.Hold = (unsigned char)((jamHdr.Attribute & MSG_HOLD) ? TRUE : FALSE); + Msg.Crash = (unsigned char)((jamHdr.Attribute & MSG_CRASH) ? TRUE : FALSE); + Msg.Immediate = (unsigned char)((jamHdr.Attribute & MSG_IMMEDIATE) ? TRUE : FALSE); + Msg.Direct = (unsigned char)((jamHdr.Attribute & MSG_DIRECT) ? TRUE : FALSE); + Msg.Gate = (unsigned char)((jamHdr.Attribute & MSG_GATE) ? TRUE : FALSE); + Msg.FileRequest = (unsigned char)((jamHdr.Attribute & MSG_FILEREQUEST) ? TRUE : FALSE); + Msg.FileAttach = (unsigned char)((jamHdr.Attribute & MSG_FILEATTACH) ? TRUE : FALSE); + Msg.TruncFile = (unsigned char)((jamHdr.Attribute & MSG_TRUNCFILE) ? TRUE : FALSE); + Msg.KillFile = (unsigned char)((jamHdr.Attribute & MSG_KILLFILE) ? TRUE : FALSE); + Msg.ReceiptRequest = (unsigned char)((jamHdr.Attribute & MSG_RECEIPTREQ) ? TRUE : FALSE); + Msg.ConfirmRequest = (unsigned char)((jamHdr.Attribute & MSG_CONFIRMREQ) ? TRUE : FALSE); + Msg.Orphan = (unsigned char)((jamHdr.Attribute & MSG_ORPHAN) ? TRUE : FALSE); + Msg.Encrypt = (unsigned char)((jamHdr.Attribute & MSG_ENCRYPT) ? TRUE : FALSE); + Msg.Compressed = (unsigned char)((jamHdr.Attribute & MSG_COMPRESS) ? TRUE : FALSE); + Msg.Escaped = (unsigned char)((jamHdr.Attribute & MSG_ESCAPED) ? TRUE : FALSE); + Msg.ForcePU = (unsigned char)((jamHdr.Attribute & MSG_FPU) ? TRUE : FALSE); + Msg.Localmail = (unsigned char)((jamHdr.Attribute & MSG_TYPELOCAL) ? TRUE : FALSE); + Msg.Echomail = (unsigned char)((jamHdr.Attribute & MSG_TYPEECHO) ? TRUE : FALSE); + Msg.Netmail = (unsigned char)((jamHdr.Attribute & MSG_TYPENET) ? TRUE : FALSE); + Msg.Nodisplay = (unsigned char)((jamHdr.Attribute & MSG_NODISP) ? TRUE : FALSE); + Msg.Locked = (unsigned char)((jamHdr.Attribute & MSG_LOCKED) ? TRUE : FALSE); + Msg.Deleted = (unsigned char)((jamHdr.Attribute & MSG_DELETED) ? TRUE : FALSE); + + Msg.Written = jamHdr.DateWritten; + Msg.Arrived = jamHdr.DateProcessed; + Msg.Read = jamHdr.DateReceived; + + Msg.Original = jamHdr.ReplyTo; + Msg.Reply = jamHdr.ReplyNext; + + if (pSubfield != NULL) + free (pSubfield); + pSubfield = NULL; + + if (jamHdr.SubfieldLen > 0L) { + ulSubfieldLen = jamHdr.SubfieldLen; + pPos = pSubfield = (unsigned char *)malloc ((size_t)(ulSubfieldLen + 1)); + if (pSubfield == NULL) + return (FALSE); + + read (fdHdr, pSubfield, (size_t)jamHdr.SubfieldLen); + + while (ulSubfieldLen > 0L) { + jamSubField = (JAMBINSUBFIELD *)pPos; + pPos += sizeof (JAMBINSUBFIELD); + /* + * The next check is to prevent a segmentation + * fault by corrupted subfields. + */ + if ((jamSubField->DatLen < 0) || (jamSubField->DatLen > jamHdr.SubfieldLen)) + return FALSE; + + switch (jamSubField->LoID) { + case JAMSFLD_SENDERNAME: + if (jamSubField->DatLen > 100) { + memcpy (Msg.From, pPos, 100); + Msg.From[100] = '\0'; + } else { + memcpy (Msg.From, pPos, (int)jamSubField->DatLen); + Msg.From[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_RECVRNAME: + if (jamSubField->DatLen > 100) { + memcpy (Msg.To, pPos, 100); + Msg.To[100] = '\0'; + } else { + memcpy (Msg.To, pPos, (int)jamSubField->DatLen); + Msg.To[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_SUBJECT: + if (jamSubField->DatLen > 100) { + memcpy (Msg.Subject, pPos, 100); + Msg.Subject[100] = '\0'; + } else { + memcpy (Msg.Subject, pPos, (int)jamSubField->DatLen); + Msg.Subject[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_OADDRESS: + if (jamSubField->DatLen > 100) { + memcpy (Msg.FromAddress, pPos, 100); + Msg.FromAddress[100] = '\0'; + } else { + memcpy (Msg.FromAddress, pPos, (int)jamSubField->DatLen); + Msg.FromAddress[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_DADDRESS: + if (jamSubField->DatLen > 100) { + memcpy(Msg.ToAddress, pPos, 100); + Msg.ToAddress[100] = '\0'; + } else { + memcpy (Msg.ToAddress, pPos, (int)jamSubField->DatLen); + Msg.ToAddress[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_MSGID: + memcpy (Msg.Msgid, pPos, (int)jamSubField->DatLen); + Msg.Msgid[(int)jamSubField->DatLen] = '\0'; + break; + + default: + break; + } + ulSubfieldLen -= sizeof (JAMBINSUBFIELD) + jamSubField->DatLen; + if (ulSubfieldLen > 0) + pPos += (int)jamSubField->DatLen; + } + } + /* + * In the original BBS we found that GEcho was not + * setting the FromAddress. We take it from the MSGID + * if there is one. + */ + if ((!strlen(Msg.FromAddress)) && (strlen(Msg.Msgid))) { + for (i = 0; i < strlen(Msg.Msgid); i++) { + if ((Msg.Msgid[i] == '@') || (Msg.Msgid[i] == ' ')) + break; + Msg.FromAddress[i] = Msg.Msgid[i]; + } + } + } + + return (RetVal); +} + + + +/* + * Read message + */ +int JAM_Read(unsigned long ulMsg, int nWidth) +{ + int RetVal = FALSE, SkipNext; + int i, nReaded, nCol, nRead; + unsigned char *pPos; + unsigned long ulTxtLen, ulSubfieldLen; + JAMIDXREC jamIdx; + JAMBINSUBFIELD *jamSubField; + LDATA *Bottom = NULL, *New; + + MsgText_Clear(); + + if ((RetVal = JAM_ReadHeader(ulMsg)) == TRUE) { + lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET); + read (fdJdx, &jamIdx, sizeof (jamIdx)); + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + + if (pSubfield != NULL) + free (pSubfield); + pSubfield = NULL; + + if (jamHdr.SubfieldLen > 0L) { + ulSubfieldLen = jamHdr.SubfieldLen; + pPos = pSubfield = (unsigned char *)malloc ((size_t)(ulSubfieldLen + 1)); + if (pSubfield == NULL) + return (FALSE); + + read (fdHdr, pSubfield, (size_t)jamHdr.SubfieldLen); + + while (ulSubfieldLen > 0L) { + jamSubField = (JAMBINSUBFIELD *)pPos; + pPos += sizeof (JAMBINSUBFIELD); + + /* + * Check for corrupted subfields + */ + if ((jamSubField->DatLen < 0) || (jamSubField->DatLen > jamHdr.SubfieldLen)) + return FALSE; + + switch (jamSubField->LoID) { + case JAMSFLD_MSGID: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + memset(&Msg.Msgid, 0, sizeof(Msg.Msgid)); + sprintf(Msg.Msgid, "%s", szBuff); + sprintf (szLine, "\001MSGID: %s", szBuff); + MsgText_Add2(szLine); + break; + + case JAMSFLD_REPLYID: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001REPLY: %s", szBuff); + MsgText_Add2(szLine); + break; + + case JAMSFLD_PID: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001PID: %s", szBuff); + MsgText_Add2(szLine); + break; + + case JAMSFLD_TRACE: + memcpy(szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001Via %s", szBuff); + MsgText_Add2(szLine); + break; + + case JAMSFLD_FTSKLUDGE: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + if (!strncmp(szBuff, "AREA:", 5)) + sprintf(szLine, "%s", szBuff); + else { + sprintf (szLine, "\001%s", szBuff); + if (strncmp(szLine, "\001REPLYADDR:", 11) == 0) { + sprintf(Msg.ReplyAddr, "%s", szLine+12); + } + if (strncmp(szLine, "\001REPLYTO:", 9) == 0) { + sprintf(Msg.ReplyTo, "%s", szLine+10); + } + if (strncmp(szLine, "\001REPLYADDR", 10) == 0) { + sprintf(Msg.ReplyAddr, "%s", szLine+11); + } + if (strncmp(szLine, "\001REPLYTO", 8) == 0) { + sprintf(Msg.ReplyTo, "%s", szLine+9); + } + } + MsgText_Add2(szLine); + break; + + case JAMSFLD_SEENBY2D: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "SEEN-BY: %s", szBuff); + if ((New = (LDATA *)malloc(sizeof(LDATA))) != NULL) { + memset(New, 0, sizeof(LDATA)); + New->Value = strdup(szLine); + if (Bottom != NULL) { + while (Bottom->Next != NULL) + Bottom = Bottom->Next; + New->Previous = Bottom; + New->Next = Bottom->Next; + if (New->Next != NULL) + New->Next->Previous = New; + Bottom->Next = New; + } + Bottom = New; + } + break; + + case JAMSFLD_PATH2D: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001PATH: %s", szBuff); + if ((New = (LDATA *)malloc(sizeof(LDATA))) != NULL) { + memset(New, 0, sizeof(LDATA)); + New->Value = strdup(szLine); + if (Bottom != NULL) { + while (Bottom->Next != NULL) + Bottom = Bottom->Next; + New->Previous = Bottom; + New->Next = Bottom->Next; + if (New->Next != NULL) + New->Next->Previous = New; + Bottom->Next = New; + } + Bottom = New; + } + break; + + case JAMSFLD_FLAGS: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001FLAGS %s", szLine); + MsgText_Add2(szLine); + break; + + case JAMSFLD_TZUTCINFO: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szBuff, "\001TZUTC %s", szLine); + MsgText_Add2(szLine); + break; + + default: + break; + } + + ulSubfieldLen -= sizeof (JAMBINSUBFIELD) + jamSubField->DatLen; + if (ulSubfieldLen > 0) + pPos += (int)jamSubField->DatLen; + } + } + + lseek (fdJdt, jamHdr.TxtOffset, SEEK_SET); + ulTxtLen = jamHdr.TxtLen; + pLine = szLine; + nCol = 0; + SkipNext = FALSE; + + do { + if ((unsigned long)(nRead = sizeof (szBuff)) > ulTxtLen) + nRead = (int)ulTxtLen; + + nReaded = (int)read (fdJdt, szBuff, nRead); + + for (i = 0, pBuff = szBuff; i < nReaded; i++, pBuff++) { + if (*pBuff == '\r') { + *pLine = '\0'; + if (pLine > szLine && SkipNext == TRUE) { + pLine--; + while (pLine > szLine && *pLine == ' ') + *pLine-- = '\0'; + if (pLine > szLine) + MsgText_Add3(szLine, (int)(strlen (szLine) + 1)); + } else + if (SkipNext == FALSE) + MsgText_Add2(szLine); + SkipNext = FALSE; + pLine = szLine; + nCol = 0; + } else + if (*pBuff != '\n') { + *pLine++ = *pBuff; + nCol++; + if (nCol >= nWidth) { + *pLine = '\0'; + if (strchr (szLine, ' ') != NULL) { + while (nCol > 1 && *pLine != ' ') { + nCol--; + pLine--; + } + if (nCol > 0) { + while (*pLine == ' ') + pLine++; + strcpy (szWrp, pLine); + } + *pLine = '\0'; + } else + szWrp[0] = '\0'; + MsgText_Add2(szLine); + strcpy (szLine, szWrp); + pLine = strchr (szLine, '\0'); + nCol = (int)strlen (szLine); + SkipNext = TRUE; + } + } + } + + ulTxtLen -= nRead; + } while (ulTxtLen > 0); + + if (Bottom != NULL) { + while (Bottom->Previous != NULL) + Bottom = Bottom->Previous; + MsgText_Add2(Bottom->Value); + + while (Bottom->Next != NULL) { + Bottom = Bottom->Next; + MsgText_Add2(Bottom->Value); + } + while (Bottom != NULL) { + if (Bottom->Previous != NULL) + Bottom->Previous->Next = Bottom->Next; + if (Bottom->Next != NULL) + Bottom->Next->Previous = Bottom->Previous; + New = Bottom; + if (Bottom->Next != NULL) + Bottom = Bottom->Next; + else if (Bottom->Previous != NULL) + Bottom = Bottom->Previous; + else + Bottom = NULL; + free(New->Value); + free(New); + } + } + } + + return (RetVal); +} + + + +int JAM_SetLastRead(lastread LR) +{ + if (lseek(fdJlr, LastReadRec * sizeof(lastread), SEEK_SET) != -1) + if (write(fdJlr, &LR, sizeof(lastread)) == sizeof(lastread)) + return TRUE; + return FALSE; +} + + + +/* + * Unlock the message base + */ +void JAM_UnLock(void) +{ + struct flock fl; + + fl.l_type = F_UNLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 1L; /* GoldED locks 1 byte as well */ + fl.l_pid = getpid(); + + if (fcntl(fdHdr, F_SETLK, &fl)) { + WriteError("$Can't unlock JAM message base"); + } + +// char *File; + +// File = calloc(PATH_MAX, sizeof(char)); +// sprintf(File, "%s%s", BaseName, ".LCK"); + +// if (unlink(File) == -1) +// WriteError("jammsg: unlock error"); +// free(File); +} + + + +/* + * Write message header + */ +int JAM_WriteHeader (unsigned long ulMsg) +{ + int RetVal = FALSE; + JAMIDXREC jamIdx; + + if (Msg.Id == ulMsg) { + // -------------------------------------------------------------------- + // The user is requesting to write the header of the last message + // retrived so our first attempt is to read the last index from the + // file and check if this is the correct one. + // -------------------------------------------------------------------- + lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET); + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } + + if (RetVal == FALSE) { + // -------------------------------------------------------------------- + // The message requested is not the last retrived or the file pointers + // are not positioned where they should be, so now we attempt to + // retrive the message header scanning the database from the beginning. + // -------------------------------------------------------------------- + Msg.Id = 0L; + lseek (fdJdx, 0L, SEEK_SET); + do { + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } while (RetVal == FALSE && tell (fdJdx) < filelength (fdJdx)); + } + + if (RetVal == TRUE) { + Msg.Id = jamHdr.MsgNum; + jamHdr.Attribute &= MSG_DELETED; + JAMset_flags(); + + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + write (fdHdr, &jamHdr, sizeof (JAMHDR)); + } + + return RetVal; +} + + diff --git a/lib/jammsg.h b/lib/jammsg.h new file mode 100644 index 00000000..a87e6493 --- /dev/null +++ b/lib/jammsg.h @@ -0,0 +1,27 @@ +#ifndef _JAMMSG_H +#define _JAMMSG_H + + +int JAM_AddMsg(void); +void JAM_Close(void); +int JAM_Delete(unsigned long); +int JAM_GetLastRead(lastread *); +unsigned long JAM_Highest(void); +int JAM_Lock(unsigned long); +unsigned long JAM_Lowest(void); +void JAM_New(void); +int JAM_NewLastRead(lastread); +int JAM_Next(unsigned long *); +unsigned long JAM_Number(void); +int JAM_Open(char *); +void JAM_Pack(void); +int JAM_Previous(unsigned long *); +int JAM_ReadHeader(unsigned long); +int JAM_Read(unsigned long, int); +int JAM_SetLastRead(lastread); +void JAM_UnLock(void); +int JAM_WriteHeader(unsigned long); + + +#endif + diff --git a/lib/jamsys.h b/lib/jamsys.h new file mode 100644 index 00000000..e8cb85c4 --- /dev/null +++ b/lib/jamsys.h @@ -0,0 +1,100 @@ +/* +** JAM(mbp) - The Joaquim-Andrew-Mats Message Base Proposal +** +** C API +** +** Written by Joaquim Homrighausen and Mats Wallin. +** +** ---------------------------------------------------------------------- +** +** jamsys.h (JAMmb) +** +** Compiler and platform dependant definitions +** +** Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch, and +** Mats Wallin. ALL RIGHTS RESERVED. +** +** 93-06-28 JoHo/MW +** Initial coding. +*/ + +#ifndef __JAMSYS_H__ +#define __JAMSYS_H__ + +/* +** The following assumptions are made about compilers and platforms: +** +** __MSDOS__ Defined if compiling for MS-DOS +** _WINDOWS Defined if compiling for Microsoft Windows +** __NT__ Defined if compiling for Windows NT +** __OS2__ Defined if compiling for OS/2 2.x +** __sparc__ Defined if compiling for Sun Sparcstation +** __50SERIES Defined if compiling for Prime with Primos +** +** __SMALL__ Defined if compiling under MS-DOS in small memory model +** __MEDIUM__ Defined if compiling under MS-DOS in medium memory model +** __COMPACT__ Defined if compiling under MS-DOS in compact memory model +** __LARGE__ Defined if compiling under MS-DOS in large memory model +** +** __ZTC__ Zortech C++ 3.x +** __BORLANDC__ Borland C++ 3.x +** __TURBOC__ Turbo C 2.0 +** __TSC__ JPI TopSpeed C 1.06 +** _MSC_VER Microsoft C 6.0 and later +** _QC Microsoft Quick C +*/ + +typedef long INT32; /* 32 bits signed integer */ +typedef unsigned long UINT32; /* 32 bits unsigned integer */ +typedef short int INT16; /* 16 bits signed integer */ +typedef unsigned short int UINT16; /* 16 bits unsigned integer */ +typedef char CHAR8; /* 8 bits signed integer */ +typedef unsigned char UCHAR8; /* 8 bits unsigned integer */ +typedef int FHANDLE; /* File handle */ + +#define _JAMFAR +#define _JAMPROC +#define _JAMDATA + + +typedef INT32 _JAMDATA * INT32ptr; +typedef UINT32 _JAMDATA * UINT32ptr; +typedef INT16 _JAMDATA * INT16ptr; +typedef UINT16 _JAMDATA * UINT16ptr; +typedef CHAR8 _JAMDATA * CHAR8ptr; +typedef UCHAR8 _JAMDATA * UCHAR8ptr; +typedef void _JAMDATA * VOIDptr; + +/* +** Values for "AccessMode" and "ShareMode" parameter to JAMsysSopen. +*/ + +#define JAMO_RDWR O_RDWR +#define JAMO_RDONLY O_RDONLY +#define JAMO_WRONLY O_WRONLY +#define JAMSH_DENYNO 0 +#define JAMSH_DENYRD 0 +#define JAMSH_DENYWR 0 +#define JAMSH_DENYRW 0 + + +/* +** Structure to contain date/time information +*/ +typedef struct JAMtm + { + int tm_sec, /* Seconds 0..59 */ + tm_min, /* Minutes 0..59 */ + tm_hour, /* Hour of day 0..23 */ + tm_mday, /* Day of month 1..31 */ + tm_mon, /* Month 0..11 */ + tm_year, /* Years since 1900 */ + tm_wday, /* Day of week 0..6 (Sun..Sat) */ + tm_yday, /* Day of year 0..365 */ + tm_isdst; /* Daylight savings time (not used) */ + } JAMTM, _JAMDATA * JAMTMptr; + +#endif /* __JAMSYS_H__ */ + + +/* end of file "jamsys.h" */ diff --git a/lib/libs.h b/lib/libs.h new file mode 100644 index 00000000..e3f2a744 --- /dev/null +++ b/lib/libs.h @@ -0,0 +1,89 @@ +/***************************************************************************** + * + * File ..................: libs.h + * Purpose ...............: Libraries include list + * Last modification date : 23-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#ifndef _LIBS_H +#define _LIBS_H + +#include "../config.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +#define _REGEX_RE_COMP + +#define TRUE 1 +#define FALSE 0 + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../lib/memwatch.h" + +#pragma pack(1) + +#endif + diff --git a/lib/mbfile.c b/lib/mbfile.c new file mode 100644 index 00000000..fefc4449 --- /dev/null +++ b/lib/mbfile.c @@ -0,0 +1,304 @@ +/***************************************************************************** + * + * File ..................: mbfile + * Purpose ...............: Basic File I/O + * Last modification date : 05-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This toolkit is free software; you can redistribute 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. + * + * MBSE BBS 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 MBTOOL; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +/* + * Buffered file copy, filetime is preserved. + */ +int file_cp(char *from, char *to) +{ + char *line; + FILE *stfrom, *stto; + int dummy, bread; + static int error; + struct stat sb; + struct utimbuf ut; + + stfrom = fopen(from, "r"); + if (stfrom == NULL) + return errno; + + stto = fopen(to, "w"); + if (stto == NULL) { + error = errno; + fclose(stfrom); + return error; + } + + line = malloc(16384); + + do { + bread = fread(line, 1, 16384, stfrom); + dummy = fwrite(line, 1, bread, stto); + if (bread != dummy) { + error = errno; + fclose(stfrom); + fclose(stto); + unlink(to); + free(line); + return error; + } + } while (bread != 0); + + free(line); + fclose(stfrom); + if (fclose(stto) != 0) { + error = errno; + unlink(to); + return error; + } + + /* + * copy successfull, now copy file- and modification-time + */ + if (stat(from, &sb) == 0) { + ut.actime = mktime(localtime(&sb.st_atime)); + ut.modtime = mktime(localtime(&sb.st_mtime)); + if (utime(to, &ut) != 0) { + error = errno; + unlink(to); + return error; + } + chmod(to, sb.st_mode); + } + + return 0; +} + + + +/* + * Remove a file + */ +int file_rm(char *path) +{ + if (unlink(path) != 0) + return errno; + return 0; +} + + + +/* + * Move or rename a file. Not fullproof if using NFS, see + * man 2 rename. If we are trying to move a file accross + * filesystems, which is not allowed, we fall back to simple + * copy the file and then delete the old file. + */ +int file_mv(char *oldpath, char *newpath) +{ + static int error; + + if (rename(oldpath, newpath) != 0) { + error = errno; + if (error != EXDEV) + return error; + /* + * We tried cross-device link, now the slow way :-) + */ + error = file_cp(oldpath, newpath); + if (error != 0) + return error; + error = file_rm(oldpath); + return 0; + } + + return 0; +} + + + +/* + * Test if the given file exists. The second option is: + * R_OK - test for Read rights + * W_OK - test for Write rights + * X_OK - test for eXecute rights + * F_OK - test file presence only + */ +int file_exist(char *path, int mode) +{ + if (access(path, mode) != 0) + return errno; + + return 0; +} + + + +/* + * Return size of file, or -1 if file doesn't exist + */ +long file_size(char *path) +{ + static struct stat sb; + + if (stat(path, &sb) == -1) + return -1; + + return sb.st_size; +} + + + +/* + * Claclulate the 32 bit CRC of a file. Return -1 if file not found. + */ +long file_crc(char *path, int slow) +{ + static long crc; + int bread; + FILE *fp; + char *line; + + if ((fp = fopen(path, "r")) == NULL) + return -1; + + line = malloc(32768); + crc = 0xffffffff; + + do { + bread = fread(line, 1, 32768, fp); + crc = upd_crc32(line, crc, bread); + if (slow) + usleep(1); + } while (bread > 0); + + free(line); + fclose(fp); + return crc ^ 0xffffffff; +} + + + +/* + * Return time of file, or -1 if file doen't exist, which is + * the same as 1 second before 1 jan 1970. You may test the + * result on -1 since time_t is actualy a long integer. + */ +time_t file_time(char *path) +{ + static struct stat sb; + + if (stat(path, &sb) == -1) + return -1; + + return sb.st_mtime; +} + + + +/* + * Make directory tree, the name must end with a / + */ +int mkdirs(char *name) +{ + char buf[PATH_MAX], *p, *q; + int rc, last = 0, oldmask; + + memset(&buf, 0, sizeof(buf)); + strncpy(buf, name, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + + p = buf+1; + + oldmask = umask(000); + while ((q = strchr(p, '/'))) { + *q = '\0'; + rc = mkdir(buf, 0775); + last = errno; + *q = '/'; + p = q+1; + } + + umask(oldmask); + + if ((last == 0) || (last == EEXIST)) { + return TRUE; + } else { + WriteError("$mkdirs(%s)", name); + return FALSE; + } +} + + + +int diskfree(int needed) +{ + char *mtab, *dev, *fs, *type; + FILE *fp; + struct statfs sfs; + int RetVal = TRUE; + unsigned long temp; + + if (! needed) + return TRUE; + + mtab = calloc(PATH_MAX, sizeof(char)); + if ((fp = fopen((char *)"/etc/mtab", "r")) == 0) { + WriteError("$Can't open /etc/mtab"); + return TRUE; + } + + while (fgets(mtab, PATH_MAX, fp)) { + dev = strtok(mtab, " "); + fs = strtok(NULL, " "); + type = strtok(NULL, " "); + if (strncmp((char *)"/dev/", dev, 5) == 0) { + /* + * Filter out unwanted filesystems, floppy. + * Also filter out the /boot file system. + */ + if (strncmp((char *)"/dev/fd", dev, 7) && strncmp((char *)"/boot", fs, 5) && + (!strncmp((char *)"ext2", type, 4) || !strncmp((char *)"reiserfs", type, 8) || + !strncmp((char *)"vfat", type, 4) || !strncmp((char *)"msdos", type, 5))) { + if (statfs(fs, &sfs) == 0) { + temp = (unsigned long)(sfs.f_bsize / 512L); + if (((unsigned long)(sfs.f_bavail * temp) / 2048L) < needed) { + RetVal = FALSE; + WriteError("On \"%s\" only %d kb left, need %d kb", fs, + (sfs.f_bavail * sfs.f_bsize) / 1024, needed * 1024); + } + } + } + } + } + fclose(fp); + free(mtab); + + return RetVal; +} + + diff --git a/lib/mbinet.h b/lib/mbinet.h new file mode 100644 index 00000000..93cbbc84 --- /dev/null +++ b/lib/mbinet.h @@ -0,0 +1,24 @@ +#ifndef _MBINET_H +#define _MBINET_H + + +int smtp_connect(void); +int smtp_send(char *); +char *smtp_receive(void); +int smtp_close(void); +int smtp_cmd(char *, int); + +int nntp_connect(void); +int nntp_send(char *); +char *nntp_receive(void); +int nntp_close(void); +int nntp_cmd(char *, int); + +int pop3_connect(void); +int pop3_send(char *); +char *pop3_receive(void); +int pop3_close(void); +int pop3_cmd(char *); + +#endif + diff --git a/lib/mbse.h b/lib/mbse.h new file mode 100644 index 00000000..4ffe6f05 --- /dev/null +++ b/lib/mbse.h @@ -0,0 +1,117 @@ +/***************************************************************************** + * + * File ..................: mbse.h + * Purpose ...............: Global variables for MBSE BBS + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#ifndef _MBSE_H +#define _MBSE_H + +#define Max_passlen 14 /* Define maximum passwd length */ +#define LINES 24 /* Lines for MoreFile */ +#define LANG 500 /* Amount of Language Entries */ + + + +typedef struct _TagRec { + long Area; /* File Area number */ + int Active; /* Not deleted from taglist */ + int Cost; /* Free download */ + off_t Size; /* File Size */ + char File[81]; /* File Name */ +} _Tag; + + + +/* + * File Areas + */ +int iAreaNumber; /* Current File Area -1 */ +char sAreaDesc[PATH_MAX]; /* Current File Area Name */ +char sAreaPath[PATH_MAX]; /* Current File Area path */ +FILE *pTagList; /* Tagged files for download */ +_Tag Tag; /* Tag record */ + + + +/* + * Msg Areas + */ +int iMsgAreaNumber; /* Current Message Area number -1 */ +int iMsgAreaType; /* Current Message Area Type */ +char sMsgAreaDesc[PATH_MAX]; /* Current Message Area Name */ +char sMsgAreaBase[PATH_MAX]; /* Current Message Area Base */ +char sMailbox[21]; /* Current e-mail mailbox */ +char sMailpath[PATH_MAX]; /* Current e-mail path */ + + + +/* + * Protocols + */ +char sProtName[21]; /* Current Transfer Protocol name */ +char sProtUp[51]; /* Upload path & binary */ +char sProtDn[51]; /* Download path & binary */ +char sProtAdvice[31]; /* Advice for protocol */ +unsigned uProtBatch; /* Batching protocol */ +unsigned uProtBidir; /* Bi-directional protocol */ +int iProtEfficiency; /* Protocol efficiency */ + + + +/* + * Global variables + */ +char *mLanguage[LANG]; /* Define LANG=nnn Language Variables */ +char *mKeystroke[LANG]; /* Possible keystrokes */ +char *Date1, *Date2; /* Result from function SwapDate() */ +char *pTTY; /* Current tty name */ +char sUserTimeleft[7]; /* Global Time Left Variable */ +int iUserTimeLeft; /* Global Time Left Variable */ +char LastLoginDate[12]; /* Last login date */ +char LastLoginTime[9]; /* Last login time */ +char LastCaller[36]; /* Last caller on system */ +char FirstName[20]; /* Users First name */ +char LastName[30]; /* Users Last name */ +int LoginPrompt; /* Login prompt check - timeout */ +int UserAge; /* Users age */ +int grecno; /* User's Record Number in user file */ +int SYSOP; /* Int to see if user is Sysop */ +int iLineCount; /* Line Counter */ +int iExpired; /* Check if users time ran out */ +int iUnixMode; /* Using Unix Accounts */ +char sUnixName[9]; /* Unix login name */ +time_t Time2Go; /* Calculated time to force logout */ +struct tm *l_date; /* Structure for Date */ + +time_t ltime; +time_t Time_Now; + + + +#endif diff --git a/lib/memwatch.c b/lib/memwatch.c new file mode 100644 index 00000000..34221d11 --- /dev/null +++ b/lib/memwatch.c @@ -0,0 +1,2356 @@ +/* +** MEMWATCH.C +** Nonintrusive ANSI C memory leak / overwrite detection +** Copyright (C) 1992-99 Johan Lindh +** All rights reserved. +** Version 2.62 +** +** 920810 JLI [1.00] +** 920830 JLI [1.10 double-free detection] +** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit] +** 921022 JLI [1.20 ASSERT and VERIFY] +** 921105 JLI [1.30 C++ support and TRACE] +** 921116 JLI [1.40 mwSetOutFunc] +** 930215 JLI [1.50 modified ASSERT/VERIFY] +** 930327 JLI [1.51 better auto-init & PC-lint support] +** 930506 JLI [1.55 MemWatch class, improved C++ support] +** 930507 JLI [1.60 mwTest & CHECK()] +** 930809 JLI [1.65 Abort/Retry/Ignore] +** 930820 JLI [1.70 data dump when unfreed] +** 931016 JLI [1.72 modified C++ new/delete handling] +** 931108 JLI [1.77 mwSetAssertAction() & some small changes] +** 940110 JLI [1.80 no-mans-land alloc/checking] +** 940328 JLI [2.00 version 2.0 rewrite] +** Improved NML (no-mans-land) support. +** Improved performance (especially for free()ing!). +** Support for 'read-only' buffers (checksums) +** ^^ NOTE: I never did this... maybe I should? +** FBI (free'd block info) tagged before freed blocks +** Exporting of the mwCounter variable +** mwBreakOut() localizes debugger support +** Allocation statistics (global, per-module, per-line) +** Self-repair ability with relinking +** 950913 JLI [2.10 improved garbage handling] +** 951201 JLI [2.11 improved auto-free in emergencies] +** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()] +** 960514 JLI [2.12 undefining of existing macros] +** 960515 JLI [2.13 possibility to use default new() & delete()] +** 960516 JLI [2.20 suppression of file flushing on unfreed msgs] +** 960516 JLI [2.21 better support for using MEMWATCH with DLL's] +** 960710 JLI [X.02 multiple logs and mwFlushNow()] +** 960801 JLI [2.22 merged X.01 version with current] +** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's] +** 960805 JLI [2.31 merged X.02 version with current] +** 961002 JLI [2.32 support for realloc() + fixed STDERR bug] +** 961222 JLI [2.40 added mwMark() & mwUnmark()] +** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY] +** 970113 JLI [2.42 added support for PC-Lint 7.00g] +** 970207 JLI [2.43 added support for strdup()] +** 970209 JLI [2.44 changed default filename to lowercase] +** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers] +** 970723 JLI [2.46 added MW_ARI_NULLREAD flag] +** 970813 JLI [2.47 stabilized marker handling] +** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway] +** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support] +** 980417 JLI [2.51 more checks for invalid addresses] +** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting] +** 990112 JLI [2.53 added check for empty heap to mwIsOwned] +** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML] +** 990224 JLI [2.56 changed ordering of members in structures] +** 990303 JLI [2.57 first maybe-fixit-for-hpux test] +** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit] +** 990517 JLI [2.59 fixed some high-sensitivity warnings] +** 990610 JLI [2.60 fixed some more high-sensitivity warnings] +** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names] +** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()] +*/ + +#include "../config.h" + +#ifdef MEMWATCH + +#define __MEMWATCH_C 1 + +#ifdef MW_NOCPP +#define MEMWATCH_NOCPP +#endif +#ifdef MW_STDIO +#define MEMWATCH_STDIO +#endif + +/*********************************************************************** +** Include files +***********************************************************************/ + +#include "../config.h" +#include "libs.h" +#include "memwatch.h" + + +/*********************************************************************** +** Defines & other weird stuff +***********************************************************************/ + +/*lint -save -e767 */ +#define MW_VERSION "2.62" /* the current version number */ +#define CHKVAL(mw) (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line) +#define FLUSH() mwFlush() +#define TESTS(f,l) if(mwTestAlways) (void)mwTestNow(f,l,1) +#define PRECHK 0x01234567L +#define POSTCHK 0x76543210L +/*lint -restore */ + +#define MW_NML 0x0001 + +#ifdef _MSC_VER +#define COMMIT "c" /* Microsoft C requires the 'c' to perform as desired */ +#else +#define COMMIT "" /* Normal ANSI */ +#endif /* _MSC_VER */ + +#ifdef __cplusplus +#define CPPTEXT "++" +#else +#define CPPTEXT "" +#endif /* __cplusplus */ + +#ifdef MEMWATCH_STDIO +#define mwSTDERR stderr +#else +#define mwSTDERR mwLog +#endif + +/*********************************************************************** +** Defines to read/write 32 bit words in a portable way +** Note: Assumes that a 'long int' is 32 bits, and a 'char' is 8 bits. +***********************************************************************/ + +typedef unsigned char mwBYTE; +typedef unsigned long mwDWORD; + +#define GETDWORD(l, cp) { \ + register mwBYTE *t_cp = (mwBYTE *)(cp); \ + (l) = ((mwDWORD)t_cp[0] << 24) \ + | ((mwDWORD)t_cp[1] << 16) \ + | ((mwDWORD)t_cp[2] << 8) \ + | ((mwDWORD)t_cp[3]) \ + ; \ +} + +#define PUTDWORD(l, cp) { \ + register mwDWORD t_l = (mwDWORD)(l); \ + register mwBYTE *t_cp = (mwBYTE *)(cp); \ + *t_cp++ = (mwBYTE)(t_l >> 24); \ + *t_cp++ = (mwBYTE)(t_l >> 16); \ + *t_cp++ = (mwBYTE)(t_l >> 8); \ + *t_cp = (mwBYTE)t_l; \ +} + +/*********************************************************************** +** Typedefs & structures +***********************************************************************/ + +/* main data holding area, precedes actual allocation */ +typedef struct mwData_ mwData; +struct mwData_ { + mwData* prev; /* previous allocation in chain */ + mwData* next; /* next allocation in chain */ + const char* file; /* file name where allocated */ + long count; /* action count */ + long check; /* integrity check value */ +#if 0 + long crc; /* data crc value */ +#endif + size_t size; /* size of allocation */ + int line; /* line number where allocated */ + unsigned flag; /* flag word */ + }; + +/* statistics structure */ +typedef struct mwStat_ mwStat; +struct mwStat_ { + mwStat* next; /* next statistic buffer */ + const char* file; + long total; /* total bytes allocated */ + long num; /* total number of allocations */ + long max; /* max allocated at one time */ + long curr; /* current allocations */ + int line; + }; + +/* grabbing structure, 1K in size */ +typedef struct mwGrabData_ mwGrabData; +struct mwGrabData_ { + mwGrabData* next; + int type; + char blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ]; + }; + +typedef struct mwMarker_ mwMarker; +struct mwMarker_ { + void *host; + char *text; + mwMarker *next; + int level; + }; + +/*********************************************************************** +** Static variables +***********************************************************************/ + +static int mwInited = 0; +static int mwInfoWritten = 0; +static int mwUseAtexit = 0; +static FILE* mwLog = NULL; +static int mwFlushing = 0; +static int mwStatLevel = MW_STAT_DEFAULT; +static int mwNML = MW_NML_DEFAULT; +static int mwFBI = 0; +static long mwAllocLimit = 0L; +static int mwUseLimit = 0; + +static long mwNumCurAlloc = 0L; +static mwData* mwHead = NULL; +static mwData* mwTail = NULL; + +static void (*mwOutFunction)(int) = NULL; +static int (*mwAriFunction)(const char*) = NULL; +static int mwAriAction = MW_ARI_ABORT; + +static char mwPrintBuf[MW_TRACE_BUFFER+8]; + +static unsigned long mwCounter = 0L; +static long mwErrors = 0L; + +static int mwTestFlags = 0; +static int mwTestAlways = 0; + +static FILE* mwLogB1 = NULL; +static int mwFlushingB1 = 0; + +static mwStat* mwStatList = NULL; +static long mwStatTotAlloc = 0L; +static long mwStatMaxAlloc = 0L; +static long mwStatNumAlloc = 0L; +static long mwStatCurAlloc = 0L; +static long mwNmlNumAlloc = 0L; +static long mwNmlCurAlloc = 0L; + +static mwGrabData* mwGrabList = NULL; +static long mwGrabSize = 0L; + +static void * mwLastFree[MW_FREE_LIST]; +static const char *mwLFfile[MW_FREE_LIST]; +static int mwLFline[MW_FREE_LIST]; +static int mwLFcur = 0; + +static mwMarker* mwFirstMark = NULL; + +static FILE* mwLogB2 = NULL; +static int mwFlushingB2 = 0; + +/*********************************************************************** +** Static function declarations +***********************************************************************/ + +static void mwAutoInit( void ); +static FILE* mwLogR( void ); +static void mwLogW( FILE* ); +static int mwFlushR( void ); +static void mwFlushW( int ); +static void mwFlush( void ); +static void mwIncErr( void ); +static void mwUnlink( mwData*, const char* file, int line ); +static int mwRelink( mwData*, const char* file, int line ); +static int mwIsHeapOK( mwData *mw ); +static int mwIsOwned( mwData* mw, const char* file, int line ); +static int mwTestBuf( mwData* mw, const char* file, int line ); +static void mwDefaultOutFunc( int ); +static void mwWrite( const char* format, ... ); +static void mwLogFile( const char* name ); +static size_t mwFreeUp( size_t, int ); +static const void *mwTestMem( const void *, unsigned, int ); +static int mwStrCmpI( const char *s1, const char *s2 ); +static int mwTestNow( const char *file, int line, int always_invoked ); +static void mwDropAll( void ); +static const char *mwGrabType( int type ); +static unsigned mwGrab_( unsigned kb, int type, int silent ); +static unsigned mwDrop_( unsigned kb, int type, int silent ); +static int mwARI( const char* text ); +static void mwStatReport( void ); +static mwStat* mwStatGet( const char*, int, int ); +static void mwStatAlloc( size_t, const char*, int ); +static void mwStatFree( size_t, const char*, int ); + +/*********************************************************************** +** System functions +***********************************************************************/ + +void mwInit( void ) { + time_t tid; + + if( mwInited++ > 0 ) return; + + /* start a log if none is running */ + if( mwLogR() == NULL ) mwLogFile( "/opt/mbse/log/memwatch.log" ); + if( mwLogR() == NULL ) { + int i; + char buf[32]; + /* oops, could not open it! */ + /* probably because it's already open */ + /* so we try some other names */ + for( i=1; i<100; i++ ) { + sprintf( buf, "memwat%02d.log", i ); + mwLogFile( buf ); + if( mwLogR() != NULL ) break; + } + } + + /* initialize the statistics */ + mwStatList = NULL; + mwStatTotAlloc = 0L; + mwStatCurAlloc = 0L; + mwStatMaxAlloc = 0L; + mwStatNumAlloc = 0L; + mwNmlCurAlloc = 0L; + mwNmlNumAlloc = 0L; + + /* write informational header if needed */ + if( !mwInfoWritten ) { + mwInfoWritten = 1; + (void) time( &tid ); + mwWrite( + "\n=============" + " MEMWATCH " MW_VERSION " Copyright (C) 1992-1999 Johan Lindh " + "=============\n"); + mwWrite( "\nStarted at %s\n", ctime( &tid ) ); + +/**************************************************************** Generic */ +#ifdef mwNew + mwWrite( "C++ new/delete tracking enabled\n" ); +#endif /* mwNew */ +#ifdef __STDC__ + mwWrite( "Compiled as standard ANSI C\n" ); +#endif /* __STDC__ */ +/**************************************************************** Generic */ + +/************************************************************ Microsoft C */ +#ifdef _MSC_VER + mwWrite( "Compiled using Microsoft C" CPPTEXT + " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 ); +#endif /* _MSC_VER */ +/************************************************************ Microsoft C */ + +/************************************************************** Borland C */ +#ifdef __BORLANDC__ + mwWrite( "Compiled using Borland C" +#ifdef __cplusplus + "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 ); +#else + " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 ); +#endif /* __cplusplus */ +#endif /* __BORLANDC__ */ +/************************************************************** Borland C */ + +/************************************************************** Watcom C */ +#ifdef __WATCOMC__ + mwWrite( "Compiled using Watcom C %d.%02d ", + __WATCOMC__/100, __WATCOMC__%100 ); +#ifdef __FLAT__ + mwWrite( "(32-bit flat model)" ); +#endif /* __FLAT__ */ + mwWrite( "\n" ); +#endif /* __WATCOMC__ */ +/************************************************************** Watcom C */ + + mwWrite( "\n" ); + FLUSH(); + } + + if( mwUseAtexit ) (void) atexit( mwAbort ); + return; + } + +void mwAbort( void ) { + mwData *mw; + mwMarker *mrk; + char *data; + time_t tid; + int c, i, j; + int errors; + long chk; + + tid = time( NULL ); + mwWrite( "\nStopped at %s\n", ctime( &tid) ); + + if( !mwInited ) + mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" ); + + /* release the grab list */ + mwDropAll(); + + /* report mwMarked items */ + while( mwFirstMark ) { + mrk = mwFirstMark->next; + mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text ); + free( mwFirstMark->text ); + free( mwFirstMark ); + mwFirstMark = mrk; + mwErrors ++; + } + + /* release all still allocated memory */ + errors = 0; + while( mwHead != NULL && errors < 3 ) { + if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) { + if( errors < 3 ) + { + errors ++; + mwWrite( "internal: NML/unfreed scan restarting\n" ); + FLUSH(); + mwHead = mwHead; + continue; + } + mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" ); + FLUSH(); + break; + } + mwFlushW(0); + if( !(mwHead->flag & MW_NML) ) { + mwErrors++; + data = ((char*)(mwHead+1)); + mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ", + mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+sizeof(long) ); + GETDWORD( chk, data ); + if( chk != PRECHK ) { + mwWrite( "[underflowed] "); + FLUSH(); + } + GETDWORD( chk, (data+sizeof(long)+mwHead->size) ); + if( chk != POSTCHK ) { + mwWrite( "[overflowed] "); + FLUSH(); + } + mwWrite( " \t{" ); + j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size; + for( i=0;i<16;i++ ) { + if( i 126 ) c = '.'; + mwWrite( "%c", c ); + } + mwWrite( "}\n" ); + mw = mwHead; + mwUnlink( mw, __FILE__, __LINE__ ); + free( mw ); + } + else { + data = ((char*)(mwHead+1)) + sizeof(long); + if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) { + mwErrors++; + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mwHead->count, data + sizeof(long), mwHead->file, mwHead->line ); + FLUSH(); + } + mwNmlNumAlloc --; + mwNmlCurAlloc -= mwHead->size; + mw = mwHead; + mwUnlink( mw, __FILE__, __LINE__ ); + free( mw ); + } + } + + if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc ); + if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc ); + + /* report statistics */ + mwStatReport(); + FLUSH(); + + mwInited = 0; + mwHead = mwTail = NULL; + if( mwErrors ) + fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors); + mwLogFile( NULL ); + mwErrors = 0; + } + +void mwTerm( void ) { + if( mwInited == 1 ) + { + mwAbort(); + return; + } + if( !mwInited ) + mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n"); + else + mwInited --; + } + +void mwStatistics( int level ) +{ + mwAutoInit(); + if( level<0 ) level=0; + if( mwStatLevel != level ) + { + mwWrite( "statistics: now collecting on a %s basis\n", + level<1?"global":(level<2?"module":"line") ); + mwStatLevel = level; + } +} + +void mwAutoCheck( int onoff ) { + mwAutoInit(); + mwTestAlways = onoff; + if( onoff ) mwTestFlags = MW_TEST_ALL; + } + +void mwSetOutFunc( void (*func)(int) ) { + mwAutoInit(); + mwOutFunction = func; + } + +int mwTest( const char *file, int line, int items ) { + mwAutoInit(); + mwTestFlags = items; + return mwTestNow( file, line, 0 ); + } + +/* +** Returns zero if there are no errors. +** Returns nonzero if there are errors. +*/ +int mwTestBuffer( const char *file, int line, void *p ) { + mwData* mw; + + mwAutoInit(); + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + + if( mwIsOwned( mw, file, line ) ) { + return mwTestBuf( mw, file, line ); + } + return 1; + } + +void mwBreakOut( const char* cause ) { + fprintf(mwSTDERR, "breakout: %s\n", cause); + mwWrite("breakout: %s\n", cause ); + return; + } + +/* +** 981217 JLI: is it possible that ->next is not always set? +*/ +void * mwMark( void *p, const char *desc, const char *file, unsigned line ) { + mwMarker *mrk; + unsigned n, isnew; + char *buf; + int tot, oflow = 0; + char wherebuf[128]; + + mwAutoInit(); + TESTS(NULL,0); + + if( desc == NULL ) desc = "unknown"; + if( file == NULL ) file = "unknown"; + + tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line ); + if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; } + + if( p == NULL ) { + mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc ); + return p; + } + + if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) ) + { + mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n", + file, line, mwFirstMark, desc ); + return p; + } + + for( mrk=mwFirstMark; mrk; mrk=mrk->next ) + { + if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) ) + { + mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n", + file, line, mrk, mrk->next, desc ); + return p; + } + if( mrk->host == p ) break; + } + + if( mrk == NULL ) { + isnew = 1; + mrk = (mwMarker*) malloc( sizeof( mwMarker ) ); + if( mrk == NULL ) { + mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); + return p; + } + mrk->next = NULL; + n = 0; + } + else { + isnew = 0; + n = strlen( mrk->text ); + } + + n += strlen( wherebuf ); + buf = (char*) malloc( n+3 ); + if( buf == NULL ) { + if( isnew ) free( mrk ); + mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); + return p; + } + + if( isnew ) { + memcpy( buf, wherebuf, n+1 ); + mrk->next = mwFirstMark; + mrk->host = p; + mrk->text = buf; + mrk->level = 1; + mwFirstMark = mrk; + } + else { + strcpy( buf, mrk->text ); + strcat( buf, ", " ); + strcat( buf, wherebuf ); + free( mrk->text ); + mrk->text = buf; + mrk->level ++; + } + + if( oflow ) { + mwIncErr(); + mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); + } + return p; + } + +void* mwUnmark( void *p, const char *file, unsigned line ) { + mwMarker *mrk, *prv; + mrk = mwFirstMark; + prv = NULL; + while( mrk ) { + if( mrk->host == p ) { + if( mrk->level < 2 ) { + if( prv ) prv->next = mrk->next; + else mwFirstMark = mrk->next; + free( mrk->text ); + free( mrk ); + return p; + } + mrk->level --; + return p; + } + prv = mrk; + mrk = mrk->next; + } + mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p ); + return p; + } + +/*********************************************************************** +** Safe memory checkers +** +** Using ifdefs, implement the operating-system specific mechanism +** of identifying a piece of memory as legal to access with read +** and write priviliges. Default: return nonzero for non-NULL pointers. +***********************************************************************/ + +static char mwDummy( char c ) +{ + return c; +} + +#ifndef MW_SAFEADDR +#ifdef WIN32 +#define MW_SAFEADDR +#define WIN32_LEAN_AND_MEAN +#include +int mwIsReadAddr( const void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( IsBadReadPtr(p,len) ) return 0; + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + /* NOTE: For some reason, under Win95 the IsBad... */ + /* can return false for invalid pointers. */ + if( p == NULL ) return 0; + if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0; + return 1; +} +#endif /* WIN32 */ +#endif /* MW_SAFEADDR */ + +#ifndef MW_SAFEADDR +#ifdef SIGSEGV +#define MW_SAFEADDR + +typedef void (*mwSignalHandlerPtr)( int ); +mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0; +jmp_buf mwSIGSEGVjump; +static void mwSIGSEGV( int n ); + +static void mwSIGSEGV( int n ) +{ + longjmp( mwSIGSEGVjump, 1 ); +} + +int mwIsReadAddr( const void *p, unsigned len ) +{ + const char *ptr; + + if( p == NULL ) return 0; + if( !len ) return 1; + + /* set up to catch the SIGSEGV signal */ + mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); + + if( setjmp( mwSIGSEGVjump ) ) + { + signal( SIGSEGV, mwOldSIGSEGV ); + return 0; + } + + /* read all the bytes in the range */ + ptr = (const char *)p; + ptr += len; + + /* the reason for this rather strange construct is that */ + /* we want to keep the number of used parameters and locals */ + /* to a minimum. if we use len for a counter gcc will complain */ + /* it may get clobbered by longjmp() at high warning levels. */ + /* it's a harmless warning, but this way we don't have to see it. */ + do + { + ptr --; + if( *ptr == 0x7C ) (void) mwDummy( (char)0 ); + } while( ptr != p ); + + /* remove the handler */ + signal( SIGSEGV, mwOldSIGSEGV ); + + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + char *ptr; + + if( p == NULL ) return 0; + if( !len ) return 1; + + /* set up to catch the SIGSEGV signal */ + mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); + + if( setjmp( mwSIGSEGVjump ) ) + { + signal( SIGSEGV, mwOldSIGSEGV ); + return 0; + } + + /* read and write-back all the bytes in the range */ + ptr = (char *)p; + ptr += len; + + /* the reason for this rather strange construct is that */ + /* we want to keep the number of used parameters and locals */ + /* to a minimum. if we use len for a counter gcc will complain */ + /* it may get clobbered by longjmp() at high warning levels. */ + /* it's a harmless warning, but this way we don't have to see it. */ + do + { + ptr --; + *ptr = mwDummy( *ptr ); + } while( ptr != p ); + + /* remove the handler */ + signal( SIGSEGV, mwOldSIGSEGV ); + + return 1; +} +#endif /* SIGSEGV */ +#endif /* MW_SAFEADDR */ + +#ifndef MW_SAFEADDR +int mwIsReadAddr( const void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( len == 0 ) return 1; + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( len == 0 ) return 1; + return 1; +} +#endif + +/*********************************************************************** +** Abort/Retry/Ignore handlers +***********************************************************************/ + +static int mwARI( const char *estr ) { + char inbuf[81]; + int c; + fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr); + (void) fgets(inbuf,sizeof(inbuf),stdin); + for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ; + c = inbuf[c]; + if( c == 'R' || c == 'r' ) { + mwBreakOut( estr ); + return MW_ARI_RETRY; + } + if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE; + return MW_ARI_ABORT; + } + +/* standard ARI handler (exported) */ +int mwAriHandler( const char *estr ) { + mwAutoInit(); + return mwARI( estr ); + } + +/* used to set the ARI function */ +void mwSetAriFunc( int (*func)(const char *) ) { + mwAutoInit(); + mwAriFunction = func; + } + +/*********************************************************************** +** Allocation handlers +***********************************************************************/ + +void* mwMalloc( size_t size, const char* file, int line) { + size_t needed; + mwData *mw; + char *ptr; + void *p; + + mwAutoInit(); + + TESTS(file,line); + + mwCounter ++; + needed = sizeof(mwData) + sizeof(long) + sizeof(long) + size; + + /* if this allocation would violate the limit, fail it */ + if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) { + mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", + mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + + mw = (mwData*) malloc( needed ); + if( mw == NULL ) { + if( mwFreeUp(needed,0) >= needed ) { + mw = (mwData*) malloc(needed); + if( mw == NULL ) { + mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed ); + mwIncErr(); + FLUSH(); + } + } + if( mw == NULL ) { + mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n", + mwCounter, file, line, (long)size, mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + } + + mw->count = mwCounter; + mw->prev = NULL; + mw->next = mwHead; + mw->file = file; + mw->size = size; + mw->line = line; + mw->flag = 0; + mw->check = CHKVAL(mw); + + if( mwHead ) mwHead->prev = mw; + mwHead = mw; + if( mwTail == NULL ) mwTail = mw; + + ptr = (char*)(void*)(mw+1); + PUTDWORD( PRECHK, ptr ); /* '*(long*)ptr = PRECHK;' */ + ptr += sizeof(long); + p = ptr; + memset( ptr, MW_VAL_NEW, size ); + ptr += size; + PUTDWORD( POSTCHK, ptr ); /* '*(long*)ptr = POSTCHK;' */ + + mwNumCurAlloc ++; + mwStatCurAlloc += (long) size; + mwStatTotAlloc += (long) size; + if( mwStatCurAlloc > mwStatMaxAlloc ) + mwStatMaxAlloc = mwStatCurAlloc; + mwStatNumAlloc ++; + + if( mwStatLevel ) mwStatAlloc( size, file, line ); + + return p; + } + +void* mwRealloc( void *p, size_t size, const char* file, int line) { + int oldUseLimit, i; + mwData *mw; + char *ptr; + + mwAutoInit(); + + if( p == NULL ) return mwMalloc( size, file, line ); + if( size == 0 ) { mwFree( p, file, line ); return NULL; } + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + if( mwIsOwned( mw, file, line ) ) { + + /* if the buffer is an NML, treat this as a double-free */ + if( mw->flag & MW_NML ) + { + mwIncErr(); + if( *((unsigned char*)(mw+1)+sizeof(long)) != MW_VAL_NML ) + { + mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", + mwCounter, file, line, mw ); + } + goto check_dbl_free; + } + + /* if this allocation would violate the limit, fail it */ + if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) { + TESTS(file,line); + mwCounter ++; + mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", + mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + + /* fake realloc operation */ + oldUseLimit = mwUseLimit; + mwUseLimit = 0; + ptr = (char*) mwMalloc( size, file, line ); + if( ptr != NULL ) { + if( size < mw->size ) + memcpy( ptr, p, size ); + else + memcpy( ptr, p, mw->size ); + mwFree( p, file, line ); + } + mwUseLimit = oldUseLimit; + return (void*) ptr; + } + + /* Unknown pointer! */ + + /* using free'd pointer? */ +check_dbl_free: + for(i=0;i %s(%d), %p was" + " freed from %s(%d)\n", + mwCounter, file, line, p, + mwLFfile[i], mwLFline[i] ); + FLUSH(); + return NULL; + } + } + + /* some weird pointer */ + mwIncErr(); + mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n", + mwCounter, file, line, p ); + FLUSH(); + return NULL; + } + +char *mwStrdup( char* str, const char* file, int line ) { + size_t len; + char *newstring; + if( str == NULL ) { + mwIncErr(); + mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n", + mwCounter, file, line ); + FLUSH(); + return NULL; + } + len = strlen( str ) + 1; + newstring = (char*) mwMalloc( len, file, line ); + if( newstring != NULL ) memcpy( newstring, str, len ); + return newstring; + } + +void mwFree( void* p, const char* file, int line ) { + int i; + mwData* mw; + char buffer[ sizeof(mwData) + sizeof(long) + 64 ]; + + TESTS(file,line); + + /* this code is in support of C++ delete */ + if( file == NULL ) { + mwFree_( p ); + return; + } + + mwAutoInit(); + mwCounter ++; + + /* on NULL free, write a warning and return */ + if( p == NULL ) { + mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n", + mwCounter, file, line ); + FLUSH(); + return; + } + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + + if( mwIsOwned( mw, file, line ) ) { + (void) mwTestBuf( mw, file, line ); + + /* if the buffer is an NML, treat this as a double-free */ + if( mw->flag & MW_NML ) + { + if( *((unsigned char*)(mw+1)+sizeof(long)) != MW_VAL_NML ) + { + mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", + mwCounter, file, line, mw ); + } + goto check_dbl_free; + } + + /* update the statistics */ + mwNumCurAlloc --; + mwStatCurAlloc -= (long) mw->size; + if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line ); + + /* we should either free the allocation or keep it as NML */ + if( mwNML ) { + mw->flag |= MW_NML; + mwNmlNumAlloc ++; + mwNmlCurAlloc += (long) mw->size; + memset( (char*)(mw+1)+sizeof(long), MW_VAL_NML, mw->size ); + } + else { + /* unlink the allocation, and enter the post-free data */ + mwUnlink( mw, file, line ); + memset( mw, MW_VAL_DEL, + mw->size + sizeof(mwData)+sizeof(long)+sizeof(long) ); + if( mwFBI ) { + memset( mw, '.', sizeof(mwData) + sizeof(long) ); + sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line ); + strncpy( (char*)(void*)mw, buffer, sizeof(mwData) + sizeof(long) ); + } + free( mw ); + } + + /* add the pointer to the last-free track */ + mwLFfile[ mwLFcur ] = file; + mwLFline[ mwLFcur ] = line; + mwLastFree[ mwLFcur++ ] = p; + if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0; + + return; + } + + /* check for double-freeing */ +check_dbl_free: + for(i=0;i %s(%d), %p was" + " freed from %s(%d)\n", + mwCounter, file, line, p, + mwLFfile[i], mwLFline[i] ); + FLUSH(); + return; + } + } + + /* some weird pointer... block the free */ + mwIncErr(); + mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n", + mwCounter, file, line, p ); + FLUSH(); + return; + } + +void* mwCalloc( size_t a, size_t b, const char *file, int line ) { + void *p; + size_t size = a * b; + p = mwMalloc( size, file, line ); + if( p == NULL ) return NULL; + memset( p, 0, size ); + return p; + } + +void mwFree_( void *p ) { + TESTS(NULL,0); + free(p); + } + +void* mwMalloc_( size_t size ) { + TESTS(NULL,0); + return malloc( size ); + } + +void* mwRealloc_( void *p, size_t size ) { + TESTS(NULL,0); + return realloc( p, size ); + } + +void* mwCalloc_( size_t a, size_t b ) { + TESTS(NULL,0); + return calloc( a, b ); + } + +void mwFlushNow( void ) { + if( mwLogR() ) fflush( mwLogR() ); + return; + } + +void mwDoFlush( int onoff ) { + mwFlushW( onoff<1?0:onoff ); + if( onoff ) if( mwLogR() ) fflush( mwLogR() ); + return; + } + +void mwLimit( long lim ) { + TESTS(NULL,0); + mwWrite("limit: old limit = "); + if( !mwAllocLimit ) mwWrite( "none" ); + else mwWrite( "%ld bytes", mwAllocLimit ); + mwWrite( ", new limit = "); + if( !lim ) { + mwWrite( "none\n" ); + mwUseLimit = 0; + } + else { + mwWrite( "%ld bytes\n", lim ); + mwUseLimit = 1; + } + mwAllocLimit = lim; + FLUSH(); + } + +void mwSetAriAction( int action ) { + TESTS(NULL,0); + mwAriAction = action; + return; + } + +int mwAssert( int exp, const char *exps, const char *fn, int ln ) { + int i; + char buffer[MW_TRACE_BUFFER+8]; + TESTS(fn,ln); + if( exp ) return 0; + mwAutoInit(); + mwIncErr(); + mwCounter++; + mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); + if( mwAriFunction != NULL ) { + sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps ); + i = (*mwAriFunction)(buffer); + switch( i ) { + case MW_ARI_IGNORE: + mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter ); + return 0; + case MW_ARI_RETRY: + mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter ); + return 1; + } + } + else { + if( mwAriAction & MW_ARI_IGNORE ) { + mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); + return 0; + } + fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps ); + } + + FLUSH(); + (void) mwTestNow( fn, ln, 1 ); + FLUSH(); + + if( mwAriAction & MW_ARI_NULLREAD ) { + /* This is made in an attempt to kick in */ + /* any debuggers or OS stack traces */ + FLUSH(); + /*lint -save -e413 */ + i = *((int*)NULL); + mwDummy( (char)i ); + /*lint -restore */ + } + + exit(255); + /* NOT REACHED - the return statement is in to keep */ + /* stupid compilers from squeaking about differing return modes. */ + /* Smart compilers instead say 'code unreachable...' */ + /*lint -save -e527 */ + return 0; + /*lint -restore */ + } + +int mwVerify( int exp, const char *exps, const char *fn, int ln ) { + int i; + char buffer[MW_TRACE_BUFFER+8]; + TESTS(fn,ln); + if( exp ) return 0; + mwAutoInit(); + mwIncErr(); + mwCounter++; + mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); + if( mwAriFunction != NULL ) { + sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps ); + i = (*mwAriFunction)(buffer); + if( i == 0 ) { + mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter ); + return 0; + } + if( i == 1 ) { + mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter ); + return 1; + } + } + else { + if( mwAriAction & MW_ARI_NULLREAD ) { + /* This is made in an attempt to kick in */ + /* any debuggers or OS stack traces */ + FLUSH(); + /*lint -save -e413 */ + i = *((int*)NULL); + mwDummy( (char)i ); + /*lint -restore */ + } + if( mwAriAction & MW_ARI_IGNORE ) { + mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); + return 0; + } + fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps ); + } + FLUSH(); + (void) mwTestNow( fn, ln, 1 ); + FLUSH(); + exit(255); + /* NOT REACHED - the return statement is in to keep */ + /* stupid compilers from squeaking about differing return modes. */ + /* Smart compilers instead say 'code unreachable...' */ + /*lint -save -e527 */ + return 0; + /*lint -restore */ + } + +void mwTrace( const char *format, ... ) { + int tot, oflow = 0; + va_list mark; + + mwAutoInit(); + TESTS(NULL,0); + if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; + + va_start( mark, format ); + tot = vsprintf( mwPrintBuf, format, mark ); + va_end( mark ); + if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } + for(tot=0;mwPrintBuf[tot];tot++) + (*mwOutFunction)( mwPrintBuf[tot] ); + if( oflow ) { + mwIncErr(); + mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); + } + + FLUSH(); + } + + +/*********************************************************************** +** Grab & Drop +***********************************************************************/ + +unsigned mwGrab( unsigned kb ) { + TESTS(NULL,0); + return mwGrab_( kb, MW_VAL_GRB, 0 ); + } + +unsigned mwDrop( unsigned kb ) { + TESTS(NULL,0); + return mwDrop_( kb, MW_VAL_GRB, 0 ); + } + +static void mwDropAll() { + TESTS(NULL,0); + (void) mwDrop_( 0, MW_VAL_GRB, 0 ); + (void) mwDrop_( 0, MW_VAL_NML, 0 ); + if( mwGrabList != NULL ) + mwWrite( "internal: the grab list is not empty after mwDropAll()\n"); + } + +static const char *mwGrabType( int type ) { + switch( type ) { + case MW_VAL_GRB: + return "grabbed"; + case MW_VAL_NML: + return "no-mans-land"; + default: + /* do nothing */ + ; + } + return ""; + } + +static unsigned mwGrab_( unsigned kb, int type, int silent ) { + unsigned i = kb; + mwGrabData *gd; + if( !kb ) i = kb = 65000U; + + for(;kb;kb--) { + if( mwUseLimit && + (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) { + if( !silent ) { + mwWrite("grabbed: all allowed memory to %s (%u kb)\n", + mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + gd = (mwGrabData*) malloc( sizeof(mwGrabData) ); + if( gd == NULL ) { + if( !silent ) { + mwWrite("grabbed: all available memory to %s (%u kb)\n", + mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + mwGrabSize += (long) sizeof(mwGrabData); + gd->next = mwGrabList; + memset( gd->blob, type, sizeof(gd->blob) ); + gd->type = type; + mwGrabList = gd; + } + if( !silent ) { + mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) ); + FLUSH(); + } + return i; + } + +static unsigned mwDrop_( unsigned kb, int type, int silent ) { + unsigned i = kb; + mwGrabData *gd,*tmp,*pr; + const void *p; + + if( mwGrabList == NULL && kb == 0 ) return 0; + if( !kb ) i = kb = 60000U; + + pr = NULL; + gd = mwGrabList; + for(;kb;) { + if( gd == NULL ) { + if( i-kb > 0 && !silent ) { + mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + if( gd->type == type ) { + if( pr ) pr->next = gd->next; + kb --; + tmp = gd; + if( mwGrabList == gd ) mwGrabList = gd->next; + gd = gd->next; + p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type ); + if( p != NULL ) { + mwWrite( "wild pointer: <%ld> %s memory hit at %p\n", + mwCounter, mwGrabType(type), p ); + FLUSH(); + } + mwGrabSize -= (long) sizeof(mwGrabData); + free( tmp ); + } + else { + pr = gd; + gd = gd->next; + } + } + if( !silent ) { + mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) ); + FLUSH(); + } + return i; + } + +/*********************************************************************** +** No-Mans-Land +***********************************************************************/ + +void mwNoMansLand( int level ) { + mwAutoInit(); + TESTS(NULL,0); + switch( level ) { + case MW_NML_NONE: + (void) mwDrop_( 0, MW_VAL_NML, 0 ); + break; + case MW_NML_FREE: + break; + case MW_NML_ALL: + (void) mwGrab_( 0, MW_VAL_NML, 0 ); + break; + default: + return; + } + mwNML = level; + } + +/*********************************************************************** +** Static functions +***********************************************************************/ + +static void mwAutoInit( void ) +{ + if( mwInited ) return; + mwUseAtexit = 1; + mwInit(); + return; +} + +static FILE *mwLogR() { + if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog; + if( mwLog == mwLogB1 ) mwLogB2 = mwLog; + if( mwLog == mwLogB2 ) mwLogB1 = mwLog; + if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1; + if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) { + mwWrite("internal: log file handle damaged and recovered\n"); + FLUSH(); + return mwLog; + } + fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" ); + mwLog = mwLogB1 = mwLogB2 = mwSTDERR; + return mwSTDERR; + } + +static void mwLogW( FILE *p ) { + mwLog = mwLogB1 = mwLogB2 = p; + } + +static int mwFlushR() { + if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing; + if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing; + if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing; + if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1; + if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) { + mwWrite("internal: flushing flag damaged and recovered\n"); + FLUSH(); + return mwFlushing; + } + mwWrite("internal: flushing flag destroyed, so set to true\n"); + mwFlushing = mwFlushingB1 = mwFlushingB2 = 1; + return 1; + } + +static void mwFlushW( int n ) { + mwFlushing = mwFlushingB1 = mwFlushingB2 = n; + } + +static void mwIncErr() { + mwErrors++; + mwFlushW( mwFlushR()+1 ); + FLUSH(); + } + +static void mwFlush() { + if( mwLogR() == NULL ) return; +#ifdef MW_FLUSH + fflush( mwLogR() ); +#else + if( mwFlushR() ) fflush( mwLogR() ); +#endif + return; + } + +static void mwUnlink( mwData* mw, const char* file, int line ) { + if( mw->prev == NULL ) { + if( mwHead != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n", + mwCounter, file, line, mw ); + mwHead = mw->next; + } + else { + if( mw->prev->next != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n", + mwCounter, file, line, mw ); + else mw->prev->next = mw->next; + } + if( mw->next == NULL ) { + if( mwTail != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n", + mwCounter, file, line, mw ); + mwTail = mw->prev; + } + else { + if( mw->next->prev != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n", + mwCounter, file, line, mw ); + else mw->next->prev = mw->prev; + } + } + +/* +** Relinking tries to repair a damaged mw block. +** Returns nonzero if it thinks it successfully +** repaired the heap chain. +*/ +static int mwRelink( mwData* mw, const char* file, int line ) { + int fails; + mwData *mw1, *mw2; + long count, size; + mwStat *ms; + + if( file == NULL ) file = "unknown"; + + if( mw == NULL ) { + mwWrite("relink: cannot repair MW at NULL\n"); + FLUSH(); + goto emergency; + } + + if( !mwIsSafeAddr(mw, sizeof(mwData)) ) { + mwWrite("relink: MW-%p is a garbage pointer\n"); + FLUSH(); + goto emergency; + } + + mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw ); + FLUSH(); + fails = 0; + + /* Repair from head */ + if( mwHead != mw ) { + if( !mwIsSafeAddr( mwHead, sizeof(mwData) ) ) { + mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw ); + FLUSH(); + goto emergency; + } + for( mw1=mwHead; mw1; mw1=mw1->next ) { + if( mw1->next == mw ) { + mw->prev = mw1; + break; + } + if( mw1->next && + ( !mwIsSafeAddr(mw1->next, sizeof(mwData)) || mw1->next->prev != mw1) ) { + mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next ); + FLUSH(); + goto emergency; + } + } + if( mw1 == NULL ) { + mwWrite("relink: MW-%p not found in forward chain search\n", mw ); + FLUSH(); + fails ++; + } + } + else + { + mwWrite( "relink: MW-%p is the head (first) allocation\n", mw ); + if( mw->prev != NULL ) + { + mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw ); + mw->prev = NULL; + } + } + + /* Repair from tail */ + if( mwTail != mw ) { + if( !mwIsSafeAddr( mwTail, sizeof(mwData) ) ) { + mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw ); + FLUSH(); + goto emergency; + } + for( mw1=mwTail; mw1; mw1=mw1->prev ) { + if( mw1->prev == mw ) { + mw->next = mw1; + break; + } + if( mw1->prev && (!mwIsSafeAddr(mw1->prev, sizeof(mwData)) || mw1->prev->next != mw1) ) { + mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev ); + FLUSH(); + goto emergency; + } + } + if( mw1 == NULL ) { + mwWrite("relink: MW-%p not found in reverse chain search\n", mw ); + FLUSH(); + fails ++; + } + } + else + { + mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw ); + if( mw->next != NULL ) + { + mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw ); + mw->next = NULL; + } + } + + if( fails > 1 ) { + mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw ); + FLUSH(); + goto verifyok; + } + + /* restore MW info where possible */ + if( mwIsReadAddr( mw->file, 1 ) ) { + ms = mwStatGet( mw->file, -1, 0 ); + if( ms == NULL ) mw->file = ""; + } + mw->check = CHKVAL(mw); + goto verifyok; + + /* Emergency repair */ + emergency: + + if( mwHead == NULL && mwTail == NULL ) + { + if( mwStatCurAlloc == 0 ) + mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line ); + else + mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line ); + FLUSH(); + return 0; + } + + mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line ); + FLUSH(); + + if( mwHead == NULL || mwTail == NULL ) + { + if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail ); + else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead ); + } + + mw1=NULL; + if( mwHead != NULL ) + { + if( !mwIsReadAddr(mwHead,sizeof(mwData)) || mwHead->check != CHKVAL(mwHead) ) + { + mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead ); + mwHead = NULL; + goto scan_reverse; + } + if( mwHead->prev != NULL ) + { + mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev ); + } + for( mw1=mwHead; mw1; mw1=mw1->next ) + { + if( mw1->next ) + { + if( !mwIsReadAddr(mw1->next,sizeof(mwData)) || + !mw1->next->check != CHKVAL(mw1) || + mw1->next->prev != mw1 ) + { + mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line ); + if( mwIsReadAddr(mw1->next,sizeof(mwData) ) ) + { + mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", + mwIsReadAddr(mw1->file,16)?mw1->file:"", mw1->line ); + } + else + { + mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n", + mw1->next ); + } + break; + } + } + } + } + + +scan_reverse: + mw2=NULL; + if( mwTail != NULL ) + { + if( !mwIsReadAddr(mwTail,sizeof(mwData)) || mwTail->check != CHKVAL(mwTail) ) + { + mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail ); + mwTail = NULL; + goto analyze; + } + if( mwTail->next != NULL ) + { + mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next ); + } + for( mw2=mwTail; mw2; mw2=mw2->prev ) + { + if( mw2->prev ) + { + if( !mwIsReadAddr(mw2->prev,sizeof(mwData)) || + !mw2->prev->check != CHKVAL(mw2) || + mw2->prev->next != mw2 ) + { + mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line ); + if( mwIsReadAddr(mw2->prev,sizeof(mwData) ) ) + { + mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", + mwIsReadAddr(mw2->file,16)?mw2->file:"", mw2->line ); + } + else + { + mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n", + mw2->prev ); + } + break; + } + } + } + } + +analyze: + if( mwHead == NULL && mwTail == NULL ) + { + mwWrite("relink: both head and tail pointers damaged, aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + if( mwHead == NULL ) + { + mwHead = mw2; + mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 ); + mw2->prev = NULL; + mw1 = mw2 = NULL; + } + if( mwTail == NULL ) + { + mwTail = mw1; + mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 ); + mw1->next = NULL; + mw1 = mw2 = NULL; + } + if( mw1 == NULL && mw2 == NULL && + mwHead->prev == NULL && mwTail->next == NULL ) { + mwWrite("relink: verifying heap integrity...\n" ); + FLUSH(); + goto verifyok; + } + if( mw1 && mw2 && mw1 != mw2 ) { + mw1->next = mw2; + mw2->prev = mw1; + mwWrite("relink: emergency repairs successful, assessing damage...\n"); + FLUSH(); + } + else { + mwWrite("relink: heap totally destroyed, aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + + /* Verify by checking that the number of active allocations */ + /* match the number of entries in the chain */ +verifyok: + if( !mwIsHeapOK( NULL ) ) { + mwWrite("relink: heap verification FAILS - aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) { + count ++; + size += (long) mw1->size; + } + if( count == mwNumCurAlloc ) { + mwWrite("relink: successful, "); + if( size == mwStatCurAlloc ) { + mwWrite("no allocations lost\n"); + } + else { + if( mw != NULL ) { + mwWrite("size information lost for MW-%p\n", mw); + mw->size = 0; + } + } + } + else { + mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n", + mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size ); + return 0; + } + + return 1; + } + +/* +** If mwData* is NULL: +** Returns 0 if heap chain is broken. +** Returns 1 if heap chain is intact. +** If mwData* is not NULL: +** Returns 0 if mwData* is missing or if chain is broken. +** Returns 1 if chain is intact and mwData* is found. +*/ +static int mwIsHeapOK( mwData *includes_mw ) { + int found = 0; + mwData *mw; + + for( mw = mwHead; mw; mw=mw->next ) { + if( includes_mw == mw ) found++; + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) return 0; + if( mw->prev ) { + if( !mwIsSafeAddr( mw->prev, sizeof(mwData) ) ) return 0; + if( mw==mwHead || mw->prev->next != mw ) return 0; + } + if( mw->next ) { + if( !mwIsSafeAddr( mw->next, sizeof(mwData) ) ) return 0; + if( mw==mwTail || mw->next->prev != mw ) return 0; + } + else if( mw!=mwTail ) return 0; + } + + if( includes_mw != NULL && !found ) return 0; + + return 1; + } + +static int mwIsOwned( mwData* mw, const char *file, int line ) { + int retv; + mwStat *ms; + + /* see if the address is legal according to OS */ + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) return 0; + + /* make sure we have _anything_ allocated */ + if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 ) + return 0; + + /* calculate checksum */ + if( mw->check != CHKVAL(mw) ) { + /* may be damaged checksum, see if block is in heap */ + if( mwIsHeapOK( mw ) ) { + /* damaged checksum, repair it */ + mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n", + mwCounter, file, line, mw ); + mwIncErr(); + if( mwIsReadAddr( mw->file, 1 ) ) { + ms = mwStatGet( mw->file, -1, 0 ); + if( ms == NULL ) mw->file = ""; + } + else mw->file = ""; + mw->check = CHKVAL(mw); + return 1; + } + /* no, it's just some garbage data */ + return 0; + } + + /* check that the non-NULL pointers are safe */ + if( mw->prev && !mwIsSafeAddr( mw->prev, sizeof(mwData) ) ) mwRelink( mw, file, line ); + if( mw->next && !mwIsSafeAddr( mw->next, sizeof(mwData) ) ) mwRelink( mw, file, line ); + + /* safe address, checksum OK, proceed with heap checks */ + + /* see if the block is in the heap */ + retv = 0; + if( mw->prev ) { if( mw->prev->next == mw ) retv ++; } + else { if( mwHead == mw ) retv++; } + if( mw->next ) { if( mw->next->prev == mw ) retv ++; } + else { if( mwTail == mw ) retv++; } + if( mw->check == CHKVAL(mw) ) retv ++; + if( retv > 2 ) return 1; + + /* block not in heap, check heap for corruption */ + + if( !mwIsHeapOK( mw ) ) { + if( mwRelink( mw, file, line ) ) + return 1; + } + + /* unable to repair */ + mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n", + mwCounter, file, line, mw ); + mwIncErr(); + + return 0; + } + +/* +** mwTestBuf: +** Checks a buffers links and pre/postfixes. +** Writes errors found to the log. +** Returns zero if no errors found. +*/ +static int mwTestBuf( mwData* mw, const char* file, int line ) { + int retv = 0; + char *p; + long chk; + + if( file == NULL ) file = "unknown"; + + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) { + mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n", + mwCounter, file, line, mw ); + mwIncErr(); + return 2; + } + + if( mw->check != CHKVAL(mw) ) { + mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n", + mwCounter, file, line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) return 2; + } + + if( mw->prev && mw->prev->next != mw ) { + mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) retv = 2; + } + if( mw->next && mw->next->prev != mw ) { + mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) retv = 2; + } + + p = (char*)(mw+1); + GETDWORD( chk, p ); + if( chk != PRECHK ) { + mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + retv = 1; + } + p += mw->size + sizeof(long); + GETDWORD( chk, p ); + if( chk != POSTCHK ) { + mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + retv = 1; + } + + return retv; + } + +static void mwDefaultOutFunc( int c ) { + if( mwLogR() ) fputc( c, mwLogR() ); + } + +static void mwWrite( const char *format, ... ) { + int tot, oflow = 0; + va_list mark; + mwAutoInit(); + if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; + va_start( mark, format ); + tot = vsprintf( mwPrintBuf, format, mark ); + va_end( mark ); + if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } + for(tot=0;mwPrintBuf[tot];tot++) + (*mwOutFunction)( mwPrintBuf[tot] ); + if( oflow ) { + mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 ); + FLUSH(); + } + return; + } + +static void mwLogFile( const char *name ) { + time_t tid; + (void) time( &tid ); + if( mwLogR() != NULL ) { + fclose( mwLogR() ); + mwLogW( NULL ); + } + if( name == NULL ) return; + mwLogW( fopen( name, "a" COMMIT ) ); + if( mwLogR() == NULL ) + mwWrite( "logfile: failed to open/create file '%s'\n", name ); + } + +/* +** Try to free NML memory until a contiguous allocation of +** 'needed' bytes can be satisfied. If this is not enough +** and the 'urgent' parameter is nonzero, grabbed memory is +** also freed. +*/ +static size_t mwFreeUp( size_t needed, int urgent ) { + void *p; + mwData *mw, *mw2; + char *data; + + /* free grabbed NML memory */ + for(;;) { + if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + + /* free normal NML memory */ + mw = mwHead; + while( mw != NULL ) { + if( !(mw->flag & MW_NML) ) mw = mw->next; + else { + data = ((char*)(mw+1)) + sizeof(long); + if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { + mwIncErr(); + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mw->count, data + sizeof(long), mw->file, mw->line ); + } + mw2 = mw->next; + mwUnlink( mw, "mwFreeUp", 0 ); + free( mw ); + mw = mw2; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + } + + /* if not urgent (for internal purposes), fail */ + if( !urgent ) return 0; + + /* free grabbed memory */ + for(;;) { + if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + + return 0; + } + +static const void * mwTestMem( const void *p, unsigned len, int c ) { + const unsigned char *ptr; + ptr = (const unsigned char *) p; + while( len-- ) { + if( *ptr != (unsigned char)c ) return (const void*)ptr; + ptr ++; + } + return NULL; + } + +static int mwStrCmpI( const char *s1, const char *s2 ) { + if( s1 == NULL || s2 == NULL ) return 0; + while( *s1 ) { + if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; } + return 1; + } + return 0; + } + +#define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; } + +static int mwTestNow( const char *file, int line, int always_invoked ) { + int retv = 0; + mwData *mw; + char *data; + + if( file && !always_invoked ) + mwWrite("check: <%ld> %s(%d), checking %s%s%s\n", + mwCounter, file, line, + (mwTestFlags & MW_TEST_CHAIN) ? "chain ": "", + (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "", + (mwTestFlags & MW_TEST_NML) ? "nomansland ": "" + ); + + if( mwTestFlags & MW_TEST_CHAIN ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( !mwIsSafeAddr(mw, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw->prev ) { + if( !mwIsSafeAddr(mw->prev, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw==mwHead || mw->prev->next != mw ) { + AIPH(); + mwWrite("check: heap chain broken, prev link incorrect\n"); + mwIncErr(); + retv ++; + } + } + if( mw->next ) { + if( !mwIsSafeAddr(mw->next, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw==mwTail || mw->next->prev != mw ) { + AIPH(); + mwWrite("check: heap chain broken, next link incorrect\n"); + mwIncErr(); + retv ++; + } + } + else if( mw!=mwTail ) { + AIPH(); + mwWrite("check: heap chain broken, tail incorrect\n"); + mwIncErr(); + retv ++; + } + } + } + if( mwTestFlags & MW_TEST_ALLOC ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( mwTestBuf( mw, file, line ) ) retv ++; + } + } + if( mwTestFlags & MW_TEST_NML ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( (mw->flag & MW_NML) ) { + data = ((char*)(mw+1)) + sizeof(long); + if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { + mwIncErr(); + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mw->count, data + sizeof(long), mw->file, mw->line ); + } + } + } + } + + + if( file && !always_invoked && !retv ) + mwWrite("check: <%ld> %s(%d), complete; no errors\n", + mwCounter, file, line ); + return retv; + } + +/********************************************************************** +** Statistics +**********************************************************************/ + +static void mwStatReport() +{ + mwStat* ms, *ms2; + const char *modname; + int modnamelen; + + /* global statistics report */ + mwWrite( "\nMemory usage statistics (global):\n" ); + mwWrite( " N)umber of allocations made: %ld\n", mwStatNumAlloc ); + mwWrite( " L)argest memory usage : %ld\n", mwStatMaxAlloc ); + mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc ); + mwWrite( " U)nfreed bytes totals : %ld\n", mwStatCurAlloc ); + FLUSH(); + + if( mwStatLevel < 1 ) return; + + /* on a per-module basis */ + mwWrite( "\nMemory usage statistics (detailed):\n"); + mwWrite( " Module/Line Number Largest Total Unfreed \n"); + for( ms=mwStatList; ms; ms=ms->next ) + { + if( ms->line == -1 ) + { + if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = ""; + else modname = ms->file; + modnamelen = strlen(modname); + if( modnamelen > 42 ) + { + modname = modname + modnamelen - 42; + } + + mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n", + modname, ms->num, ms->max, ms->total, ms->curr ); + if( ms->file && mwStatLevel > 1 ) + { + for( ms2=mwStatList; ms2; ms2=ms2->next ) + { + if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) ) + { + mwWrite( " %-8d %-8ld %-8ld %-8ld %-8ld\n", + ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr ); + } + } + } + } + } +} + +static mwStat* mwStatGet( const char *file, int line, int makenew ) { + mwStat* ms; + + if( mwStatLevel < 2 ) line = -1; + + for( ms=mwStatList; ms!=NULL; ms=ms->next ) { + if( line != ms->line ) continue; + if( file==NULL ) { + if( ms->file == NULL ) break; + continue; + } + if( ms->file == NULL ) continue; + if( !strcmp( ms->file, file ) ) break; + } + + if( ms != NULL ) return ms; + + if( !makenew ) return NULL; + + ms = (mwStat*) malloc( sizeof(mwStat) ); + if( ms == NULL ) { + if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) || + (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) { + mwWrite("internal: memory low, statistics incomplete for '%s'\n", file ); + return NULL; + } + } + ms->file = file; + ms->line = line; + ms->total = 0L; + ms->max = 0L; + ms->num = 0L; + ms->curr = 0L; + ms->next = mwStatList; + mwStatList = ms; + return ms; + } + +static void mwStatAlloc( size_t size, const char* file, int line ) { + mwStat* ms; + + /* update the module statistics */ + ms = mwStatGet( file, -1, 1 ); + if( ms != NULL ) { + ms->total += (long) size; + ms->curr += (long) size; + ms->num ++; + if( ms->curr > ms->max ) ms->max = ms->curr; + } + + /* update the line statistics */ + if( mwStatLevel > 1 && line != -1 && file ) { + ms = mwStatGet( file, line, 1 ); + if( ms != NULL ) { + ms->total += (long) size; + ms->curr += (long) size; + ms->num ++; + if( ms->curr > ms->max ) ms->max = ms->curr; + } + } + + } + +static void mwStatFree( size_t size, const char* file, int line ) { + mwStat* ms; + + /* update the module statistics */ + ms = mwStatGet( file, -1, 1 ); + if( ms != NULL ) ms->curr -= (long) size; + + /* update the line statistics */ + if( mwStatLevel > 1 && line != -1 && file ) { + ms = mwStatGet( file, line, 1 ); + if( ms != NULL ) ms->curr -= (long) size; + } + } + +#if 0 /* 980317: disabled C++ */ + +/********************************************************************** +** C++ new & delete +**********************************************************************/ + +#ifdef __cplusplus +#ifndef MEMWATCH_NOCPP + +int mwNCur = 0; +const char *mwNFile = NULL; +int mwNLine = 0; + +class MemWatch { +public: + MemWatch(); + ~MemWatch(); + }; + +MemWatch::MemWatch() { + if( mwInited ) return; + mwUseAtexit = 0; + mwInit(); + } + +MemWatch::~MemWatch() { + if( mwUseAtexit ) return; + mwTerm(); + } + +/* +** This global new will catch all 'new' calls where MEMWATCH is +** not active. +*/ +void* operator new( unsigned size ) { + mwNCur = 0; + return mwMalloc( size, "", 0 ); + } + +/* +** This is the new operator that's called when a module uses mwNew. +*/ +void* operator new( unsigned size, const char *file, int line ) { + mwNCur = 0; + return mwMalloc( size, file, line ); + } + +/* +** Since this delete operator will recieve ALL delete's +** even those from within libraries, we must accept +** delete's before we've been initialized. Nor can we +** reliably check for wild free's if the mwNCur variable +** is not set. +*/ +void operator delete( void *p ) { + if( p == NULL ) return; + if( !mwInited ) { + free( p ); + return; + } + if( mwNCur ) { + mwFree( p, mwNFile, mwNLine ); + mwNCur = 0; + return; + } + mwFree_( p ); + } + +#endif /* MEMWATCH_NOCPP */ +#endif /* __cplusplus */ + +#endif /* 980317: disabled C++ */ + +#endif /* MEMWATCH.C */ diff --git a/lib/memwatch.c.org b/lib/memwatch.c.org new file mode 100644 index 00000000..4540127e --- /dev/null +++ b/lib/memwatch.c.org @@ -0,0 +1,2360 @@ +/* +** MEMWATCH.C +** Nonintrusive ANSI C memory leak / overwrite detection +** Copyright (C) 1992-99 Johan Lindh +** All rights reserved. +** Version 2.62 +** +** 920810 JLI [1.00] +** 920830 JLI [1.10 double-free detection] +** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit] +** 921022 JLI [1.20 ASSERT and VERIFY] +** 921105 JLI [1.30 C++ support and TRACE] +** 921116 JLI [1.40 mwSetOutFunc] +** 930215 JLI [1.50 modified ASSERT/VERIFY] +** 930327 JLI [1.51 better auto-init & PC-lint support] +** 930506 JLI [1.55 MemWatch class, improved C++ support] +** 930507 JLI [1.60 mwTest & CHECK()] +** 930809 JLI [1.65 Abort/Retry/Ignore] +** 930820 JLI [1.70 data dump when unfreed] +** 931016 JLI [1.72 modified C++ new/delete handling] +** 931108 JLI [1.77 mwSetAssertAction() & some small changes] +** 940110 JLI [1.80 no-mans-land alloc/checking] +** 940328 JLI [2.00 version 2.0 rewrite] +** Improved NML (no-mans-land) support. +** Improved performance (especially for free()ing!). +** Support for 'read-only' buffers (checksums) +** ^^ NOTE: I never did this... maybe I should? +** FBI (free'd block info) tagged before freed blocks +** Exporting of the mwCounter variable +** mwBreakOut() localizes debugger support +** Allocation statistics (global, per-module, per-line) +** Self-repair ability with relinking +** 950913 JLI [2.10 improved garbage handling] +** 951201 JLI [2.11 improved auto-free in emergencies] +** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()] +** 960514 JLI [2.12 undefining of existing macros] +** 960515 JLI [2.13 possibility to use default new() & delete()] +** 960516 JLI [2.20 suppression of file flushing on unfreed msgs] +** 960516 JLI [2.21 better support for using MEMWATCH with DLL's] +** 960710 JLI [X.02 multiple logs and mwFlushNow()] +** 960801 JLI [2.22 merged X.01 version with current] +** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's] +** 960805 JLI [2.31 merged X.02 version with current] +** 961002 JLI [2.32 support for realloc() + fixed STDERR bug] +** 961222 JLI [2.40 added mwMark() & mwUnmark()] +** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY] +** 970113 JLI [2.42 added support for PC-Lint 7.00g] +** 970207 JLI [2.43 added support for strdup()] +** 970209 JLI [2.44 changed default filename to lowercase] +** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers] +** 970723 JLI [2.46 added MW_ARI_NULLREAD flag] +** 970813 JLI [2.47 stabilized marker handling] +** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway] +** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support] +** 980417 JLI [2.51 more checks for invalid addresses] +** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting] +** 990112 JLI [2.53 added check for empty heap to mwIsOwned] +** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML] +** 990224 JLI [2.56 changed ordering of members in structures] +** 990303 JLI [2.57 first maybe-fixit-for-hpux test] +** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit] +** 990517 JLI [2.59 fixed some high-sensitivity warnings] +** 990610 JLI [2.60 fixed some more high-sensitivity warnings] +** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names] +** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()] +*/ + +#define __MEMWATCH_C 1 + +#ifdef MW_NOCPP +#define MEMWATCH_NOCPP +#endif +#ifdef MW_STDIO +#define MEMWATCH_STDIO +#endif + +/*********************************************************************** +** Include files +***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "memwatch.h" + +#ifndef toupper +#include +#endif + +/*********************************************************************** +** Defines & other weird stuff +***********************************************************************/ + +/*lint -save -e767 */ +#define VERSION "2.62" /* the current version number */ +#define CHKVAL(mw) (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line) +#define FLUSH() mwFlush() +#define TESTS(f,l) if(mwTestAlways) (void)mwTestNow(f,l,1) +#define PRECHK 0x01234567L +#define POSTCHK 0x76543210L +/*lint -restore */ + +#define MW_NML 0x0001 + +#ifdef _MSC_VER +#define COMMIT "c" /* Microsoft C requires the 'c' to perform as desired */ +#else +#define COMMIT "" /* Normal ANSI */ +#endif /* _MSC_VER */ + +#ifdef __cplusplus +#define CPPTEXT "++" +#else +#define CPPTEXT "" +#endif /* __cplusplus */ + +#ifdef MEMWATCH_STDIO +#define mwSTDERR stderr +#else +#define mwSTDERR mwLog +#endif + +/*********************************************************************** +** Defines to read/write 32 bit words in a portable way +** Note: Assumes that a 'long int' is 32 bits, and a 'char' is 8 bits. +***********************************************************************/ + +typedef unsigned char mwBYTE; +typedef unsigned long mwDWORD; + +#define GETDWORD(l, cp) { \ + register mwBYTE *t_cp = (mwBYTE *)(cp); \ + (l) = ((mwDWORD)t_cp[0] << 24) \ + | ((mwDWORD)t_cp[1] << 16) \ + | ((mwDWORD)t_cp[2] << 8) \ + | ((mwDWORD)t_cp[3]) \ + ; \ +} + +#define PUTDWORD(l, cp) { \ + register mwDWORD t_l = (mwDWORD)(l); \ + register mwBYTE *t_cp = (mwBYTE *)(cp); \ + *t_cp++ = (mwBYTE)(t_l >> 24); \ + *t_cp++ = (mwBYTE)(t_l >> 16); \ + *t_cp++ = (mwBYTE)(t_l >> 8); \ + *t_cp = (mwBYTE)t_l; \ +} + +/*********************************************************************** +** Typedefs & structures +***********************************************************************/ + +/* main data holding area, precedes actual allocation */ +typedef struct mwData_ mwData; +struct mwData_ { + mwData* prev; /* previous allocation in chain */ + mwData* next; /* next allocation in chain */ + const char* file; /* file name where allocated */ + long count; /* action count */ + long check; /* integrity check value */ +#if 0 + long crc; /* data crc value */ +#endif + size_t size; /* size of allocation */ + int line; /* line number where allocated */ + unsigned flag; /* flag word */ + }; + +/* statistics structure */ +typedef struct mwStat_ mwStat; +struct mwStat_ { + mwStat* next; /* next statistic buffer */ + const char* file; + long total; /* total bytes allocated */ + long num; /* total number of allocations */ + long max; /* max allocated at one time */ + long curr; /* current allocations */ + int line; + }; + +/* grabbing structure, 1K in size */ +typedef struct mwGrabData_ mwGrabData; +struct mwGrabData_ { + mwGrabData* next; + int type; + char blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ]; + }; + +typedef struct mwMarker_ mwMarker; +struct mwMarker_ { + void *host; + char *text; + mwMarker *next; + int level; + }; + +/*********************************************************************** +** Static variables +***********************************************************************/ + +static int mwInited = 0; +static int mwInfoWritten = 0; +static int mwUseAtexit = 0; +static FILE* mwLog = NULL; +static int mwFlushing = 0; +static int mwStatLevel = MW_STAT_DEFAULT; +static int mwNML = MW_NML_DEFAULT; +static int mwFBI = 0; +static long mwAllocLimit = 0L; +static int mwUseLimit = 0; + +static long mwNumCurAlloc = 0L; +static mwData* mwHead = NULL; +static mwData* mwTail = NULL; + +static void (*mwOutFunction)(int) = NULL; +static int (*mwAriFunction)(const char*) = NULL; +static int mwAriAction = MW_ARI_ABORT; + +static char mwPrintBuf[MW_TRACE_BUFFER+8]; + +static unsigned long mwCounter = 0L; +static long mwErrors = 0L; + +static int mwTestFlags = 0; +static int mwTestAlways = 0; + +static FILE* mwLogB1 = NULL; +static int mwFlushingB1 = 0; + +static mwStat* mwStatList = NULL; +static long mwStatTotAlloc = 0L; +static long mwStatMaxAlloc = 0L; +static long mwStatNumAlloc = 0L; +static long mwStatCurAlloc = 0L; +static long mwNmlNumAlloc = 0L; +static long mwNmlCurAlloc = 0L; + +static mwGrabData* mwGrabList = NULL; +static long mwGrabSize = 0L; + +static void * mwLastFree[MW_FREE_LIST]; +static const char *mwLFfile[MW_FREE_LIST]; +static int mwLFline[MW_FREE_LIST]; +static int mwLFcur = 0; + +static mwMarker* mwFirstMark = NULL; + +static FILE* mwLogB2 = NULL; +static int mwFlushingB2 = 0; + +/*********************************************************************** +** Static function declarations +***********************************************************************/ + +static void mwAutoInit( void ); +static FILE* mwLogR( void ); +static void mwLogW( FILE* ); +static int mwFlushR( void ); +static void mwFlushW( int ); +static void mwFlush( void ); +static void mwIncErr( void ); +static void mwUnlink( mwData*, const char* file, int line ); +static int mwRelink( mwData*, const char* file, int line ); +static int mwIsHeapOK( mwData *mw ); +static int mwIsOwned( mwData* mw, const char* file, int line ); +static int mwTestBuf( mwData* mw, const char* file, int line ); +static void mwDefaultOutFunc( int ); +static void mwWrite( const char* format, ... ); +static void mwLogFile( const char* name ); +static size_t mwFreeUp( size_t, int ); +static const void *mwTestMem( const void *, unsigned, int ); +static int mwStrCmpI( const char *s1, const char *s2 ); +static int mwTestNow( const char *file, int line, int always_invoked ); +static void mwDropAll( void ); +static const char *mwGrabType( int type ); +static unsigned mwGrab_( unsigned kb, int type, int silent ); +static unsigned mwDrop_( unsigned kb, int type, int silent ); +static int mwARI( const char* text ); +static void mwStatReport( void ); +static mwStat* mwStatGet( const char*, int, int ); +static void mwStatAlloc( size_t, const char*, int ); +static void mwStatFree( size_t, const char*, int ); + +/*********************************************************************** +** System functions +***********************************************************************/ + +void mwInit( void ) { + time_t tid; + + if( mwInited++ > 0 ) return; + + /* start a log if none is running */ + if( mwLogR() == NULL ) mwLogFile( "memwatch.log" ); + if( mwLogR() == NULL ) { + int i; + char buf[32]; + /* oops, could not open it! */ + /* probably because it's already open */ + /* so we try some other names */ + for( i=1; i<100; i++ ) { + sprintf( buf, "memwat%02d.log", i ); + mwLogFile( buf ); + if( mwLogR() != NULL ) break; + } + } + + /* initialize the statistics */ + mwStatList = NULL; + mwStatTotAlloc = 0L; + mwStatCurAlloc = 0L; + mwStatMaxAlloc = 0L; + mwStatNumAlloc = 0L; + mwNmlCurAlloc = 0L; + mwNmlNumAlloc = 0L; + + /* write informational header if needed */ + if( !mwInfoWritten ) { + mwInfoWritten = 1; + (void) time( &tid ); + mwWrite( + "\n=============" + " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh " + "=============\n"); + mwWrite( "\nStarted at %s\n", ctime( &tid ) ); + +/**************************************************************** Generic */ +#ifdef mwNew + mwWrite( "C++ new/delete tracking enabled\n" ); +#endif /* mwNew */ +#ifdef __STDC__ + mwWrite( "Compiled as standard ANSI C\n" ); +#endif /* __STDC__ */ +/**************************************************************** Generic */ + +/************************************************************ Microsoft C */ +#ifdef _MSC_VER + mwWrite( "Compiled using Microsoft C" CPPTEXT + " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 ); +#endif /* _MSC_VER */ +/************************************************************ Microsoft C */ + +/************************************************************** Borland C */ +#ifdef __BORLANDC__ + mwWrite( "Compiled using Borland C" +#ifdef __cplusplus + "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 ); +#else + " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 ); +#endif /* __cplusplus */ +#endif /* __BORLANDC__ */ +/************************************************************** Borland C */ + +/************************************************************** Watcom C */ +#ifdef __WATCOMC__ + mwWrite( "Compiled using Watcom C %d.%02d ", + __WATCOMC__/100, __WATCOMC__%100 ); +#ifdef __FLAT__ + mwWrite( "(32-bit flat model)" ); +#endif /* __FLAT__ */ + mwWrite( "\n" ); +#endif /* __WATCOMC__ */ +/************************************************************** Watcom C */ + + mwWrite( "\n" ); + FLUSH(); + } + + if( mwUseAtexit ) (void) atexit( mwAbort ); + return; + } + +void mwAbort( void ) { + mwData *mw; + mwMarker *mrk; + char *data; + time_t tid; + int c, i, j; + int errors; + long chk; + + tid = time( NULL ); + mwWrite( "\nStopped at %s\n", ctime( &tid) ); + + if( !mwInited ) + mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" ); + + /* release the grab list */ + mwDropAll(); + + /* report mwMarked items */ + while( mwFirstMark ) { + mrk = mwFirstMark->next; + mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text ); + free( mwFirstMark->text ); + free( mwFirstMark ); + mwFirstMark = mrk; + mwErrors ++; + } + + /* release all still allocated memory */ + errors = 0; + while( mwHead != NULL && errors < 3 ) { + if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) { + if( errors < 3 ) + { + errors ++; + mwWrite( "internal: NML/unfreed scan restarting\n" ); + FLUSH(); + mwHead = mwHead; + continue; + } + mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" ); + FLUSH(); + break; + } + mwFlushW(0); + if( !(mwHead->flag & MW_NML) ) { + mwErrors++; + data = ((char*)(mwHead+1)); + mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ", + mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+sizeof(long) ); + GETDWORD( chk, data ); + if( chk != PRECHK ) { + mwWrite( "[underflowed] "); + FLUSH(); + } + GETDWORD( chk, (data+sizeof(long)+mwHead->size) ); + if( chk != POSTCHK ) { + mwWrite( "[overflowed] "); + FLUSH(); + } + mwWrite( " \t{" ); + j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size; + for( i=0;i<16;i++ ) { + if( i 126 ) c = '.'; + mwWrite( "%c", c ); + } + mwWrite( "}\n" ); + mw = mwHead; + mwUnlink( mw, __FILE__, __LINE__ ); + free( mw ); + } + else { + data = ((char*)(mwHead+1)) + sizeof(long); + if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) { + mwErrors++; + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mwHead->count, data + sizeof(long), mwHead->file, mwHead->line ); + FLUSH(); + } + mwNmlNumAlloc --; + mwNmlCurAlloc -= mwHead->size; + mw = mwHead; + mwUnlink( mw, __FILE__, __LINE__ ); + free( mw ); + } + } + + if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc ); + if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc ); + + /* report statistics */ + mwStatReport(); + FLUSH(); + + mwInited = 0; + mwHead = mwTail = NULL; + if( mwErrors ) + fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors); + mwLogFile( NULL ); + mwErrors = 0; + } + +void mwTerm( void ) { + if( mwInited == 1 ) + { + mwAbort(); + return; + } + if( !mwInited ) + mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n"); + else + mwInited --; + } + +void mwStatistics( int level ) +{ + mwAutoInit(); + if( level<0 ) level=0; + if( mwStatLevel != level ) + { + mwWrite( "statistics: now collecting on a %s basis\n", + level<1?"global":(level<2?"module":"line") ); + mwStatLevel = level; + } +} + +void mwAutoCheck( int onoff ) { + mwAutoInit(); + mwTestAlways = onoff; + if( onoff ) mwTestFlags = MW_TEST_ALL; + } + +void mwSetOutFunc( void (*func)(int) ) { + mwAutoInit(); + mwOutFunction = func; + } + +int mwTest( const char *file, int line, int items ) { + mwAutoInit(); + mwTestFlags = items; + return mwTestNow( file, line, 0 ); + } + +/* +** Returns zero if there are no errors. +** Returns nonzero if there are errors. +*/ +int mwTestBuffer( const char *file, int line, void *p ) { + mwData* mw; + + mwAutoInit(); + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + + if( mwIsOwned( mw, file, line ) ) { + return mwTestBuf( mw, file, line ); + } + return 1; + } + +void mwBreakOut( const char* cause ) { + fprintf(mwSTDERR, "breakout: %s\n", cause); + mwWrite("breakout: %s\n", cause ); + return; + } + +/* +** 981217 JLI: is it possible that ->next is not always set? +*/ +void * mwMark( void *p, const char *desc, const char *file, unsigned line ) { + mwMarker *mrk; + unsigned n, isnew; + char *buf; + int tot, oflow = 0; + char wherebuf[128]; + + mwAutoInit(); + TESTS(NULL,0); + + if( desc == NULL ) desc = "unknown"; + if( file == NULL ) file = "unknown"; + + tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line ); + if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; } + + if( p == NULL ) { + mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc ); + return p; + } + + if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) ) + { + mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n", + file, line, mwFirstMark, desc ); + return p; + } + + for( mrk=mwFirstMark; mrk; mrk=mrk->next ) + { + if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) ) + { + mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n", + file, line, mrk, mrk->next, desc ); + return p; + } + if( mrk->host == p ) break; + } + + if( mrk == NULL ) { + isnew = 1; + mrk = (mwMarker*) malloc( sizeof( mwMarker ) ); + if( mrk == NULL ) { + mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); + return p; + } + mrk->next = NULL; + n = 0; + } + else { + isnew = 0; + n = strlen( mrk->text ); + } + + n += strlen( wherebuf ); + buf = (char*) malloc( n+3 ); + if( buf == NULL ) { + if( isnew ) free( mrk ); + mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); + return p; + } + + if( isnew ) { + memcpy( buf, wherebuf, n+1 ); + mrk->next = mwFirstMark; + mrk->host = p; + mrk->text = buf; + mrk->level = 1; + mwFirstMark = mrk; + } + else { + strcpy( buf, mrk->text ); + strcat( buf, ", " ); + strcat( buf, wherebuf ); + free( mrk->text ); + mrk->text = buf; + mrk->level ++; + } + + if( oflow ) { + mwIncErr(); + mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); + } + return p; + } + +void* mwUnmark( void *p, const char *file, unsigned line ) { + mwMarker *mrk, *prv; + mrk = mwFirstMark; + prv = NULL; + while( mrk ) { + if( mrk->host == p ) { + if( mrk->level < 2 ) { + if( prv ) prv->next = mrk->next; + else mwFirstMark = mrk->next; + free( mrk->text ); + free( mrk ); + return p; + } + mrk->level --; + return p; + } + prv = mrk; + mrk = mrk->next; + } + mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p ); + return p; + } + +/*********************************************************************** +** Safe memory checkers +** +** Using ifdefs, implement the operating-system specific mechanism +** of identifying a piece of memory as legal to access with read +** and write priviliges. Default: return nonzero for non-NULL pointers. +***********************************************************************/ + +static char mwDummy( char c ) +{ + return c; +} + +#ifndef MW_SAFEADDR +#ifdef WIN32 +#define MW_SAFEADDR +#define WIN32_LEAN_AND_MEAN +#include +int mwIsReadAddr( const void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( IsBadReadPtr(p,len) ) return 0; + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + /* NOTE: For some reason, under Win95 the IsBad... */ + /* can return false for invalid pointers. */ + if( p == NULL ) return 0; + if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0; + return 1; +} +#endif /* WIN32 */ +#endif /* MW_SAFEADDR */ + +#ifndef MW_SAFEADDR +#ifdef SIGSEGV +#define MW_SAFEADDR + +typedef void (*mwSignalHandlerPtr)( int ); +mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0; +jmp_buf mwSIGSEGVjump; +static void mwSIGSEGV( int n ); + +static void mwSIGSEGV( int n ) +{ + longjmp( mwSIGSEGVjump, 1 ); +} + +int mwIsReadAddr( const void *p, unsigned len ) +{ + const char *ptr; + + if( p == NULL ) return 0; + if( !len ) return 1; + + /* set up to catch the SIGSEGV signal */ + mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); + + if( setjmp( mwSIGSEGVjump ) ) + { + signal( SIGSEGV, mwOldSIGSEGV ); + return 0; + } + + /* read all the bytes in the range */ + ptr = (const char *)p; + ptr += len; + + /* the reason for this rather strange construct is that */ + /* we want to keep the number of used parameters and locals */ + /* to a minimum. if we use len for a counter gcc will complain */ + /* it may get clobbered by longjmp() at high warning levels. */ + /* it's a harmless warning, but this way we don't have to see it. */ + do + { + ptr --; + if( *ptr == 0x7C ) (void) mwDummy( (char)0 ); + } while( ptr != p ); + + /* remove the handler */ + signal( SIGSEGV, mwOldSIGSEGV ); + + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + char *ptr; + + if( p == NULL ) return 0; + if( !len ) return 1; + + /* set up to catch the SIGSEGV signal */ + mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); + + if( setjmp( mwSIGSEGVjump ) ) + { + signal( SIGSEGV, mwOldSIGSEGV ); + return 0; + } + + /* read and write-back all the bytes in the range */ + ptr = (char *)p; + ptr += len; + + /* the reason for this rather strange construct is that */ + /* we want to keep the number of used parameters and locals */ + /* to a minimum. if we use len for a counter gcc will complain */ + /* it may get clobbered by longjmp() at high warning levels. */ + /* it's a harmless warning, but this way we don't have to see it. */ + do + { + ptr --; + *ptr = mwDummy( *ptr ); + } while( ptr != p ); + + /* remove the handler */ + signal( SIGSEGV, mwOldSIGSEGV ); + + return 1; +} +#endif /* SIGSEGV */ +#endif /* MW_SAFEADDR */ + +#ifndef MW_SAFEADDR +int mwIsReadAddr( const void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( len == 0 ) return 1; + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( len == 0 ) return 1; + return 1; +} +#endif + +/*********************************************************************** +** Abort/Retry/Ignore handlers +***********************************************************************/ + +static int mwARI( const char *estr ) { + char inbuf[81]; + int c; + fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr); + (void) fgets(inbuf,sizeof(inbuf),stdin); + for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ; + c = inbuf[c]; + if( c == 'R' || c == 'r' ) { + mwBreakOut( estr ); + return MW_ARI_RETRY; + } + if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE; + return MW_ARI_ABORT; + } + +/* standard ARI handler (exported) */ +int mwAriHandler( const char *estr ) { + mwAutoInit(); + return mwARI( estr ); + } + +/* used to set the ARI function */ +void mwSetAriFunc( int (*func)(const char *) ) { + mwAutoInit(); + mwAriFunction = func; + } + +/*********************************************************************** +** Allocation handlers +***********************************************************************/ + +void* mwMalloc( size_t size, const char* file, int line) { + size_t needed; + mwData *mw; + char *ptr; + void *p; + + mwAutoInit(); + + TESTS(file,line); + + mwCounter ++; + needed = sizeof(mwData) + sizeof(long) + sizeof(long) + size; + + /* if this allocation would violate the limit, fail it */ + if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) { + mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", + mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + + mw = (mwData*) malloc( needed ); + if( mw == NULL ) { + if( mwFreeUp(needed,0) >= needed ) { + mw = (mwData*) malloc(needed); + if( mw == NULL ) { + mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed ); + mwIncErr(); + FLUSH(); + } + } + if( mw == NULL ) { + mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n", + mwCounter, file, line, (long)size, mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + } + + mw->count = mwCounter; + mw->prev = NULL; + mw->next = mwHead; + mw->file = file; + mw->size = size; + mw->line = line; + mw->flag = 0; + mw->check = CHKVAL(mw); + + if( mwHead ) mwHead->prev = mw; + mwHead = mw; + if( mwTail == NULL ) mwTail = mw; + + ptr = (char*)(void*)(mw+1); + PUTDWORD( PRECHK, ptr ); /* '*(long*)ptr = PRECHK;' */ + ptr += sizeof(long); + p = ptr; + memset( ptr, MW_VAL_NEW, size ); + ptr += size; + PUTDWORD( POSTCHK, ptr ); /* '*(long*)ptr = POSTCHK;' */ + + mwNumCurAlloc ++; + mwStatCurAlloc += (long) size; + mwStatTotAlloc += (long) size; + if( mwStatCurAlloc > mwStatMaxAlloc ) + mwStatMaxAlloc = mwStatCurAlloc; + mwStatNumAlloc ++; + + if( mwStatLevel ) mwStatAlloc( size, file, line ); + + return p; + } + +void* mwRealloc( void *p, size_t size, const char* file, int line) { + int oldUseLimit, i; + mwData *mw; + char *ptr; + + mwAutoInit(); + + if( p == NULL ) return mwMalloc( size, file, line ); + if( size == 0 ) { mwFree( p, file, line ); return NULL; } + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + if( mwIsOwned( mw, file, line ) ) { + + /* if the buffer is an NML, treat this as a double-free */ + if( mw->flag & MW_NML ) + { + mwIncErr(); + if( *((unsigned char*)(mw+1)+sizeof(long)) != MW_VAL_NML ) + { + mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", + mwCounter, file, line, mw ); + } + goto check_dbl_free; + } + + /* if this allocation would violate the limit, fail it */ + if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) { + TESTS(file,line); + mwCounter ++; + mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", + mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + + /* fake realloc operation */ + oldUseLimit = mwUseLimit; + mwUseLimit = 0; + ptr = (char*) mwMalloc( size, file, line ); + if( ptr != NULL ) { + if( size < mw->size ) + memcpy( ptr, p, size ); + else + memcpy( ptr, p, mw->size ); + mwFree( p, file, line ); + } + mwUseLimit = oldUseLimit; + return (void*) ptr; + } + + /* Unknown pointer! */ + + /* using free'd pointer? */ +check_dbl_free: + for(i=0;i %s(%d), %p was" + " freed from %s(%d)\n", + mwCounter, file, line, p, + mwLFfile[i], mwLFline[i] ); + FLUSH(); + return NULL; + } + } + + /* some weird pointer */ + mwIncErr(); + mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n", + mwCounter, file, line, p ); + FLUSH(); + return NULL; + } + +char *mwStrdup( char* str, const char* file, int line ) { + size_t len; + char *newstring; + if( str == NULL ) { + mwIncErr(); + mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n", + mwCounter, file, line ); + FLUSH(); + return NULL; + } + len = strlen( str ) + 1; + newstring = (char*) mwMalloc( len, file, line ); + if( newstring != NULL ) memcpy( newstring, str, len ); + return newstring; + } + +void mwFree( void* p, const char* file, int line ) { + int i; + mwData* mw; + char buffer[ sizeof(mwData) + sizeof(long) + 64 ]; + + TESTS(file,line); + + /* this code is in support of C++ delete */ + if( file == NULL ) { + mwFree_( p ); + return; + } + + mwAutoInit(); + mwCounter ++; + + /* on NULL free, write a warning and return */ + if( p == NULL ) { + mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n", + mwCounter, file, line ); + FLUSH(); + return; + } + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + + if( mwIsOwned( mw, file, line ) ) { + (void) mwTestBuf( mw, file, line ); + + /* if the buffer is an NML, treat this as a double-free */ + if( mw->flag & MW_NML ) + { + if( *((unsigned char*)(mw+1)+sizeof(long)) != MW_VAL_NML ) + { + mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", + mwCounter, file, line, mw ); + } + goto check_dbl_free; + } + + /* update the statistics */ + mwNumCurAlloc --; + mwStatCurAlloc -= (long) mw->size; + if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line ); + + /* we should either free the allocation or keep it as NML */ + if( mwNML ) { + mw->flag |= MW_NML; + mwNmlNumAlloc ++; + mwNmlCurAlloc += (long) mw->size; + memset( (char*)(mw+1)+sizeof(long), MW_VAL_NML, mw->size ); + } + else { + /* unlink the allocation, and enter the post-free data */ + mwUnlink( mw, file, line ); + memset( mw, MW_VAL_DEL, + mw->size + sizeof(mwData)+sizeof(long)+sizeof(long) ); + if( mwFBI ) { + memset( mw, '.', sizeof(mwData) + sizeof(long) ); + sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line ); + strncpy( (char*)(void*)mw, buffer, sizeof(mwData) + sizeof(long) ); + } + free( mw ); + } + + /* add the pointer to the last-free track */ + mwLFfile[ mwLFcur ] = file; + mwLFline[ mwLFcur ] = line; + mwLastFree[ mwLFcur++ ] = p; + if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0; + + return; + } + + /* check for double-freeing */ +check_dbl_free: + for(i=0;i %s(%d), %p was" + " freed from %s(%d)\n", + mwCounter, file, line, p, + mwLFfile[i], mwLFline[i] ); + FLUSH(); + return; + } + } + + /* some weird pointer... block the free */ + mwIncErr(); + mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n", + mwCounter, file, line, p ); + FLUSH(); + return; + } + +void* mwCalloc( size_t a, size_t b, const char *file, int line ) { + void *p; + size_t size = a * b; + p = mwMalloc( size, file, line ); + if( p == NULL ) return NULL; + memset( p, 0, size ); + return p; + } + +void mwFree_( void *p ) { + TESTS(NULL,0); + free(p); + } + +void* mwMalloc_( size_t size ) { + TESTS(NULL,0); + return malloc( size ); + } + +void* mwRealloc_( void *p, size_t size ) { + TESTS(NULL,0); + return realloc( p, size ); + } + +void* mwCalloc_( size_t a, size_t b ) { + TESTS(NULL,0); + return calloc( a, b ); + } + +void mwFlushNow( void ) { + if( mwLogR() ) fflush( mwLogR() ); + return; + } + +void mwDoFlush( int onoff ) { + mwFlushW( onoff<1?0:onoff ); + if( onoff ) if( mwLogR() ) fflush( mwLogR() ); + return; + } + +void mwLimit( long lim ) { + TESTS(NULL,0); + mwWrite("limit: old limit = "); + if( !mwAllocLimit ) mwWrite( "none" ); + else mwWrite( "%ld bytes", mwAllocLimit ); + mwWrite( ", new limit = "); + if( !lim ) { + mwWrite( "none\n" ); + mwUseLimit = 0; + } + else { + mwWrite( "%ld bytes\n", lim ); + mwUseLimit = 1; + } + mwAllocLimit = lim; + FLUSH(); + } + +void mwSetAriAction( int action ) { + TESTS(NULL,0); + mwAriAction = action; + return; + } + +int mwAssert( int exp, const char *exps, const char *fn, int ln ) { + int i; + char buffer[MW_TRACE_BUFFER+8]; + TESTS(fn,ln); + if( exp ) return 0; + mwAutoInit(); + mwIncErr(); + mwCounter++; + mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); + if( mwAriFunction != NULL ) { + sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps ); + i = (*mwAriFunction)(buffer); + switch( i ) { + case MW_ARI_IGNORE: + mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter ); + return 0; + case MW_ARI_RETRY: + mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter ); + return 1; + } + } + else { + if( mwAriAction & MW_ARI_IGNORE ) { + mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); + return 0; + } + fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps ); + } + + FLUSH(); + (void) mwTestNow( fn, ln, 1 ); + FLUSH(); + + if( mwAriAction & MW_ARI_NULLREAD ) { + /* This is made in an attempt to kick in */ + /* any debuggers or OS stack traces */ + FLUSH(); + /*lint -save -e413 */ + i = *((int*)NULL); + mwDummy( (char)i ); + /*lint -restore */ + } + + exit(255); + /* NOT REACHED - the return statement is in to keep */ + /* stupid compilers from squeaking about differing return modes. */ + /* Smart compilers instead say 'code unreachable...' */ + /*lint -save -e527 */ + return 0; + /*lint -restore */ + } + +int mwVerify( int exp, const char *exps, const char *fn, int ln ) { + int i; + char buffer[MW_TRACE_BUFFER+8]; + TESTS(fn,ln); + if( exp ) return 0; + mwAutoInit(); + mwIncErr(); + mwCounter++; + mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); + if( mwAriFunction != NULL ) { + sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps ); + i = (*mwAriFunction)(buffer); + if( i == 0 ) { + mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter ); + return 0; + } + if( i == 1 ) { + mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter ); + return 1; + } + } + else { + if( mwAriAction & MW_ARI_NULLREAD ) { + /* This is made in an attempt to kick in */ + /* any debuggers or OS stack traces */ + FLUSH(); + /*lint -save -e413 */ + i = *((int*)NULL); + mwDummy( (char)i ); + /*lint -restore */ + } + if( mwAriAction & MW_ARI_IGNORE ) { + mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); + return 0; + } + fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps ); + } + FLUSH(); + (void) mwTestNow( fn, ln, 1 ); + FLUSH(); + exit(255); + /* NOT REACHED - the return statement is in to keep */ + /* stupid compilers from squeaking about differing return modes. */ + /* Smart compilers instead say 'code unreachable...' */ + /*lint -save -e527 */ + return 0; + /*lint -restore */ + } + +void mwTrace( const char *format, ... ) { + int tot, oflow = 0; + va_list mark; + + mwAutoInit(); + TESTS(NULL,0); + if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; + + va_start( mark, format ); + tot = vsprintf( mwPrintBuf, format, mark ); + va_end( mark ); + if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } + for(tot=0;mwPrintBuf[tot];tot++) + (*mwOutFunction)( mwPrintBuf[tot] ); + if( oflow ) { + mwIncErr(); + mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); + } + + FLUSH(); + } + + +/*********************************************************************** +** Grab & Drop +***********************************************************************/ + +unsigned mwGrab( unsigned kb ) { + TESTS(NULL,0); + return mwGrab_( kb, MW_VAL_GRB, 0 ); + } + +unsigned mwDrop( unsigned kb ) { + TESTS(NULL,0); + return mwDrop_( kb, MW_VAL_GRB, 0 ); + } + +static void mwDropAll() { + TESTS(NULL,0); + (void) mwDrop_( 0, MW_VAL_GRB, 0 ); + (void) mwDrop_( 0, MW_VAL_NML, 0 ); + if( mwGrabList != NULL ) + mwWrite( "internal: the grab list is not empty after mwDropAll()\n"); + } + +static const char *mwGrabType( int type ) { + switch( type ) { + case MW_VAL_GRB: + return "grabbed"; + case MW_VAL_NML: + return "no-mans-land"; + default: + /* do nothing */ + ; + } + return ""; + } + +static unsigned mwGrab_( unsigned kb, int type, int silent ) { + unsigned i = kb; + mwGrabData *gd; + if( !kb ) i = kb = 65000U; + + for(;kb;kb--) { + if( mwUseLimit && + (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) { + if( !silent ) { + mwWrite("grabbed: all allowed memory to %s (%u kb)\n", + mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + gd = (mwGrabData*) malloc( sizeof(mwGrabData) ); + if( gd == NULL ) { + if( !silent ) { + mwWrite("grabbed: all available memory to %s (%u kb)\n", + mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + mwGrabSize += (long) sizeof(mwGrabData); + gd->next = mwGrabList; + memset( gd->blob, type, sizeof(gd->blob) ); + gd->type = type; + mwGrabList = gd; + } + if( !silent ) { + mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) ); + FLUSH(); + } + return i; + } + +static unsigned mwDrop_( unsigned kb, int type, int silent ) { + unsigned i = kb; + mwGrabData *gd,*tmp,*pr; + const void *p; + + if( mwGrabList == NULL && kb == 0 ) return 0; + if( !kb ) i = kb = 60000U; + + pr = NULL; + gd = mwGrabList; + for(;kb;) { + if( gd == NULL ) { + if( i-kb > 0 && !silent ) { + mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + if( gd->type == type ) { + if( pr ) pr->next = gd->next; + kb --; + tmp = gd; + if( mwGrabList == gd ) mwGrabList = gd->next; + gd = gd->next; + p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type ); + if( p != NULL ) { + mwWrite( "wild pointer: <%ld> %s memory hit at %p\n", + mwCounter, mwGrabType(type), p ); + FLUSH(); + } + mwGrabSize -= (long) sizeof(mwGrabData); + free( tmp ); + } + else { + pr = gd; + gd = gd->next; + } + } + if( !silent ) { + mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) ); + FLUSH(); + } + return i; + } + +/*********************************************************************** +** No-Mans-Land +***********************************************************************/ + +void mwNoMansLand( int level ) { + mwAutoInit(); + TESTS(NULL,0); + switch( level ) { + case MW_NML_NONE: + (void) mwDrop_( 0, MW_VAL_NML, 0 ); + break; + case MW_NML_FREE: + break; + case MW_NML_ALL: + (void) mwGrab_( 0, MW_VAL_NML, 0 ); + break; + default: + return; + } + mwNML = level; + } + +/*********************************************************************** +** Static functions +***********************************************************************/ + +static void mwAutoInit( void ) +{ + if( mwInited ) return; + mwUseAtexit = 1; + mwInit(); + return; +} + +static FILE *mwLogR() { + if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog; + if( mwLog == mwLogB1 ) mwLogB2 = mwLog; + if( mwLog == mwLogB2 ) mwLogB1 = mwLog; + if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1; + if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) { + mwWrite("internal: log file handle damaged and recovered\n"); + FLUSH(); + return mwLog; + } + fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" ); + mwLog = mwLogB1 = mwLogB2 = mwSTDERR; + return mwSTDERR; + } + +static void mwLogW( FILE *p ) { + mwLog = mwLogB1 = mwLogB2 = p; + } + +static int mwFlushR() { + if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing; + if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing; + if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing; + if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1; + if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) { + mwWrite("internal: flushing flag damaged and recovered\n"); + FLUSH(); + return mwFlushing; + } + mwWrite("internal: flushing flag destroyed, so set to true\n"); + mwFlushing = mwFlushingB1 = mwFlushingB2 = 1; + return 1; + } + +static void mwFlushW( int n ) { + mwFlushing = mwFlushingB1 = mwFlushingB2 = n; + } + +static void mwIncErr() { + mwErrors++; + mwFlushW( mwFlushR()+1 ); + FLUSH(); + } + +static void mwFlush() { + if( mwLogR() == NULL ) return; +#ifdef MW_FLUSH + fflush( mwLogR() ); +#else + if( mwFlushR() ) fflush( mwLogR() ); +#endif + return; + } + +static void mwUnlink( mwData* mw, const char* file, int line ) { + if( mw->prev == NULL ) { + if( mwHead != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n", + mwCounter, file, line, mw ); + mwHead = mw->next; + } + else { + if( mw->prev->next != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n", + mwCounter, file, line, mw ); + else mw->prev->next = mw->next; + } + if( mw->next == NULL ) { + if( mwTail != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n", + mwCounter, file, line, mw ); + mwTail = mw->prev; + } + else { + if( mw->next->prev != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n", + mwCounter, file, line, mw ); + else mw->next->prev = mw->prev; + } + } + +/* +** Relinking tries to repair a damaged mw block. +** Returns nonzero if it thinks it successfully +** repaired the heap chain. +*/ +static int mwRelink( mwData* mw, const char* file, int line ) { + int fails; + mwData *mw1, *mw2; + long count, size; + mwStat *ms; + + if( file == NULL ) file = "unknown"; + + if( mw == NULL ) { + mwWrite("relink: cannot repair MW at NULL\n"); + FLUSH(); + goto emergency; + } + + if( !mwIsSafeAddr(mw, sizeof(mwData)) ) { + mwWrite("relink: MW-%p is a garbage pointer\n"); + FLUSH(); + goto emergency; + } + + mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw ); + FLUSH(); + fails = 0; + + /* Repair from head */ + if( mwHead != mw ) { + if( !mwIsSafeAddr( mwHead, sizeof(mwData) ) ) { + mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw ); + FLUSH(); + goto emergency; + } + for( mw1=mwHead; mw1; mw1=mw1->next ) { + if( mw1->next == mw ) { + mw->prev = mw1; + break; + } + if( mw1->next && + ( !mwIsSafeAddr(mw1->next, sizeof(mwData)) || mw1->next->prev != mw1) ) { + mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next ); + FLUSH(); + goto emergency; + } + } + if( mw1 == NULL ) { + mwWrite("relink: MW-%p not found in forward chain search\n", mw ); + FLUSH(); + fails ++; + } + } + else + { + mwWrite( "relink: MW-%p is the head (first) allocation\n", mw ); + if( mw->prev != NULL ) + { + mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw ); + mw->prev = NULL; + } + } + + /* Repair from tail */ + if( mwTail != mw ) { + if( !mwIsSafeAddr( mwTail, sizeof(mwData) ) ) { + mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw ); + FLUSH(); + goto emergency; + } + for( mw1=mwTail; mw1; mw1=mw1->prev ) { + if( mw1->prev == mw ) { + mw->next = mw1; + break; + } + if( mw1->prev && (!mwIsSafeAddr(mw1->prev, sizeof(mwData)) || mw1->prev->next != mw1) ) { + mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev ); + FLUSH(); + goto emergency; + } + } + if( mw1 == NULL ) { + mwWrite("relink: MW-%p not found in reverse chain search\n", mw ); + FLUSH(); + fails ++; + } + } + else + { + mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw ); + if( mw->next != NULL ) + { + mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw ); + mw->next = NULL; + } + } + + if( fails > 1 ) { + mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw ); + FLUSH(); + goto verifyok; + } + + /* restore MW info where possible */ + if( mwIsReadAddr( mw->file, 1 ) ) { + ms = mwStatGet( mw->file, -1, 0 ); + if( ms == NULL ) mw->file = ""; + } + mw->check = CHKVAL(mw); + goto verifyok; + + /* Emergency repair */ + emergency: + + if( mwHead == NULL && mwTail == NULL ) + { + if( mwStatCurAlloc == 0 ) + mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line ); + else + mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line ); + FLUSH(); + return 0; + } + + mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line ); + FLUSH(); + + if( mwHead == NULL || mwTail == NULL ) + { + if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail ); + else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead ); + } + + mw1=NULL; + if( mwHead != NULL ) + { + if( !mwIsReadAddr(mwHead,sizeof(mwData)) || mwHead->check != CHKVAL(mwHead) ) + { + mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead ); + mwHead = NULL; + goto scan_reverse; + } + if( mwHead->prev != NULL ) + { + mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev ); + } + for( mw1=mwHead; mw1; mw1=mw1->next ) + { + if( mw1->next ) + { + if( !mwIsReadAddr(mw1->next,sizeof(mwData)) || + !mw1->next->check != CHKVAL(mw1) || + mw1->next->prev != mw1 ) + { + mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line ); + if( mwIsReadAddr(mw1->next,sizeof(mwData) ) ) + { + mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", + mwIsReadAddr(mw1->file,16)?mw1->file:"", mw1->line ); + } + else + { + mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n", + mw1->next ); + } + break; + } + } + } + } + + +scan_reverse: + mw2=NULL; + if( mwTail != NULL ) + { + if( !mwIsReadAddr(mwTail,sizeof(mwData)) || mwTail->check != CHKVAL(mwTail) ) + { + mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail ); + mwTail = NULL; + goto analyze; + } + if( mwTail->next != NULL ) + { + mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next ); + } + for( mw2=mwTail; mw2; mw2=mw2->prev ) + { + if( mw2->prev ) + { + if( !mwIsReadAddr(mw2->prev,sizeof(mwData)) || + !mw2->prev->check != CHKVAL(mw2) || + mw2->prev->next != mw2 ) + { + mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line ); + if( mwIsReadAddr(mw2->prev,sizeof(mwData) ) ) + { + mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", + mwIsReadAddr(mw2->file,16)?mw2->file:"", mw2->line ); + } + else + { + mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n", + mw2->prev ); + } + break; + } + } + } + } + +analyze: + if( mwHead == NULL && mwTail == NULL ) + { + mwWrite("relink: both head and tail pointers damaged, aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + if( mwHead == NULL ) + { + mwHead = mw2; + mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 ); + mw2->prev = NULL; + mw1 = mw2 = NULL; + } + if( mwTail == NULL ) + { + mwTail = mw1; + mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 ); + mw1->next = NULL; + mw1 = mw2 = NULL; + } + if( mw1 == NULL && mw2 == NULL && + mwHead->prev == NULL && mwTail->next == NULL ) { + mwWrite("relink: verifying heap integrity...\n" ); + FLUSH(); + goto verifyok; + } + if( mw1 && mw2 && mw1 != mw2 ) { + mw1->next = mw2; + mw2->prev = mw1; + mwWrite("relink: emergency repairs successful, assessing damage...\n"); + FLUSH(); + } + else { + mwWrite("relink: heap totally destroyed, aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + + /* Verify by checking that the number of active allocations */ + /* match the number of entries in the chain */ +verifyok: + if( !mwIsHeapOK( NULL ) ) { + mwWrite("relink: heap verification FAILS - aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) { + count ++; + size += (long) mw1->size; + } + if( count == mwNumCurAlloc ) { + mwWrite("relink: successful, "); + if( size == mwStatCurAlloc ) { + mwWrite("no allocations lost\n"); + } + else { + if( mw != NULL ) { + mwWrite("size information lost for MW-%p\n", mw); + mw->size = 0; + } + } + } + else { + mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n", + mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size ); + return 0; + } + + return 1; + } + +/* +** If mwData* is NULL: +** Returns 0 if heap chain is broken. +** Returns 1 if heap chain is intact. +** If mwData* is not NULL: +** Returns 0 if mwData* is missing or if chain is broken. +** Returns 1 if chain is intact and mwData* is found. +*/ +static int mwIsHeapOK( mwData *includes_mw ) { + int found = 0; + mwData *mw; + + for( mw = mwHead; mw; mw=mw->next ) { + if( includes_mw == mw ) found++; + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) return 0; + if( mw->prev ) { + if( !mwIsSafeAddr( mw->prev, sizeof(mwData) ) ) return 0; + if( mw==mwHead || mw->prev->next != mw ) return 0; + } + if( mw->next ) { + if( !mwIsSafeAddr( mw->next, sizeof(mwData) ) ) return 0; + if( mw==mwTail || mw->next->prev != mw ) return 0; + } + else if( mw!=mwTail ) return 0; + } + + if( includes_mw != NULL && !found ) return 0; + + return 1; + } + +static int mwIsOwned( mwData* mw, const char *file, int line ) { + int retv; + mwStat *ms; + + /* see if the address is legal according to OS */ + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) return 0; + + /* make sure we have _anything_ allocated */ + if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 ) + return 0; + + /* calculate checksum */ + if( mw->check != CHKVAL(mw) ) { + /* may be damaged checksum, see if block is in heap */ + if( mwIsHeapOK( mw ) ) { + /* damaged checksum, repair it */ + mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n", + mwCounter, file, line, mw ); + mwIncErr(); + if( mwIsReadAddr( mw->file, 1 ) ) { + ms = mwStatGet( mw->file, -1, 0 ); + if( ms == NULL ) mw->file = ""; + } + else mw->file = ""; + mw->check = CHKVAL(mw); + return 1; + } + /* no, it's just some garbage data */ + return 0; + } + + /* check that the non-NULL pointers are safe */ + if( mw->prev && !mwIsSafeAddr( mw->prev, sizeof(mwData) ) ) mwRelink( mw, file, line ); + if( mw->next && !mwIsSafeAddr( mw->next, sizeof(mwData) ) ) mwRelink( mw, file, line ); + + /* safe address, checksum OK, proceed with heap checks */ + + /* see if the block is in the heap */ + retv = 0; + if( mw->prev ) { if( mw->prev->next == mw ) retv ++; } + else { if( mwHead == mw ) retv++; } + if( mw->next ) { if( mw->next->prev == mw ) retv ++; } + else { if( mwTail == mw ) retv++; } + if( mw->check == CHKVAL(mw) ) retv ++; + if( retv > 2 ) return 1; + + /* block not in heap, check heap for corruption */ + + if( !mwIsHeapOK( mw ) ) { + if( mwRelink( mw, file, line ) ) + return 1; + } + + /* unable to repair */ + mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n", + mwCounter, file, line, mw ); + mwIncErr(); + + return 0; + } + +/* +** mwTestBuf: +** Checks a buffers links and pre/postfixes. +** Writes errors found to the log. +** Returns zero if no errors found. +*/ +static int mwTestBuf( mwData* mw, const char* file, int line ) { + int retv = 0; + char *p; + long chk; + + if( file == NULL ) file = "unknown"; + + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) { + mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n", + mwCounter, file, line, mw ); + mwIncErr(); + return 2; + } + + if( mw->check != CHKVAL(mw) ) { + mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n", + mwCounter, file, line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) return 2; + } + + if( mw->prev && mw->prev->next != mw ) { + mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) retv = 2; + } + if( mw->next && mw->next->prev != mw ) { + mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) retv = 2; + } + + p = (char*)(mw+1); + GETDWORD( chk, p ); + if( chk != PRECHK ) { + mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + retv = 1; + } + p += mw->size + sizeof(long); + GETDWORD( chk, p ); + if( chk != POSTCHK ) { + mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + retv = 1; + } + + return retv; + } + +static void mwDefaultOutFunc( int c ) { + if( mwLogR() ) fputc( c, mwLogR() ); + } + +static void mwWrite( const char *format, ... ) { + int tot, oflow = 0; + va_list mark; + mwAutoInit(); + if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; + va_start( mark, format ); + tot = vsprintf( mwPrintBuf, format, mark ); + va_end( mark ); + if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } + for(tot=0;mwPrintBuf[tot];tot++) + (*mwOutFunction)( mwPrintBuf[tot] ); + if( oflow ) { + mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 ); + FLUSH(); + } + return; + } + +static void mwLogFile( const char *name ) { + time_t tid; + (void) time( &tid ); + if( mwLogR() != NULL ) { + fclose( mwLogR() ); + mwLogW( NULL ); + } + if( name == NULL ) return; + mwLogW( fopen( name, "a" COMMIT ) ); + if( mwLogR() == NULL ) + mwWrite( "logfile: failed to open/create file '%s'\n", name ); + } + +/* +** Try to free NML memory until a contiguous allocation of +** 'needed' bytes can be satisfied. If this is not enough +** and the 'urgent' parameter is nonzero, grabbed memory is +** also freed. +*/ +static size_t mwFreeUp( size_t needed, int urgent ) { + void *p; + mwData *mw, *mw2; + char *data; + + /* free grabbed NML memory */ + for(;;) { + if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + + /* free normal NML memory */ + mw = mwHead; + while( mw != NULL ) { + if( !(mw->flag & MW_NML) ) mw = mw->next; + else { + data = ((char*)(mw+1)) + sizeof(long); + if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { + mwIncErr(); + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mw->count, data + sizeof(long), mw->file, mw->line ); + } + mw2 = mw->next; + mwUnlink( mw, "mwFreeUp", 0 ); + free( mw ); + mw = mw2; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + } + + /* if not urgent (for internal purposes), fail */ + if( !urgent ) return 0; + + /* free grabbed memory */ + for(;;) { + if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + + return 0; + } + +static const void * mwTestMem( const void *p, unsigned len, int c ) { + const unsigned char *ptr; + ptr = (const unsigned char *) p; + while( len-- ) { + if( *ptr != (unsigned char)c ) return (const void*)ptr; + ptr ++; + } + return NULL; + } + +static int mwStrCmpI( const char *s1, const char *s2 ) { + if( s1 == NULL || s2 == NULL ) return 0; + while( *s1 ) { + if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; } + return 1; + } + return 0; + } + +#define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; } + +static int mwTestNow( const char *file, int line, int always_invoked ) { + int retv = 0; + mwData *mw; + char *data; + + if( file && !always_invoked ) + mwWrite("check: <%ld> %s(%d), checking %s%s%s\n", + mwCounter, file, line, + (mwTestFlags & MW_TEST_CHAIN) ? "chain ": "", + (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "", + (mwTestFlags & MW_TEST_NML) ? "nomansland ": "" + ); + + if( mwTestFlags & MW_TEST_CHAIN ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( !mwIsSafeAddr(mw, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw->prev ) { + if( !mwIsSafeAddr(mw->prev, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw==mwHead || mw->prev->next != mw ) { + AIPH(); + mwWrite("check: heap chain broken, prev link incorrect\n"); + mwIncErr(); + retv ++; + } + } + if( mw->next ) { + if( !mwIsSafeAddr(mw->next, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw==mwTail || mw->next->prev != mw ) { + AIPH(); + mwWrite("check: heap chain broken, next link incorrect\n"); + mwIncErr(); + retv ++; + } + } + else if( mw!=mwTail ) { + AIPH(); + mwWrite("check: heap chain broken, tail incorrect\n"); + mwIncErr(); + retv ++; + } + } + } + if( mwTestFlags & MW_TEST_ALLOC ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( mwTestBuf( mw, file, line ) ) retv ++; + } + } + if( mwTestFlags & MW_TEST_NML ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( (mw->flag & MW_NML) ) { + data = ((char*)(mw+1)) + sizeof(long); + if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { + mwIncErr(); + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mw->count, data + sizeof(long), mw->file, mw->line ); + } + } + } + } + + + if( file && !always_invoked && !retv ) + mwWrite("check: <%ld> %s(%d), complete; no errors\n", + mwCounter, file, line ); + return retv; + } + +/********************************************************************** +** Statistics +**********************************************************************/ + +static void mwStatReport() +{ + mwStat* ms, *ms2; + const char *modname; + int modnamelen; + + /* global statistics report */ + mwWrite( "\nMemory usage statistics (global):\n" ); + mwWrite( " N)umber of allocations made: %ld\n", mwStatNumAlloc ); + mwWrite( " L)argest memory usage : %ld\n", mwStatMaxAlloc ); + mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc ); + mwWrite( " U)nfreed bytes totals : %ld\n", mwStatCurAlloc ); + FLUSH(); + + if( mwStatLevel < 1 ) return; + + /* on a per-module basis */ + mwWrite( "\nMemory usage statistics (detailed):\n"); + mwWrite( " Module/Line Number Largest Total Unfreed \n"); + for( ms=mwStatList; ms; ms=ms->next ) + { + if( ms->line == -1 ) + { + if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = ""; + else modname = ms->file; + modnamelen = strlen(modname); + if( modnamelen > 42 ) + { + modname = modname + modnamelen - 42; + } + + mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n", + modname, ms->num, ms->max, ms->total, ms->curr ); + if( ms->file && mwStatLevel > 1 ) + { + for( ms2=mwStatList; ms2; ms2=ms2->next ) + { + if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) ) + { + mwWrite( " %-8d %-8ld %-8ld %-8ld %-8ld\n", + ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr ); + } + } + } + } + } +} + +static mwStat* mwStatGet( const char *file, int line, int makenew ) { + mwStat* ms; + + if( mwStatLevel < 2 ) line = -1; + + for( ms=mwStatList; ms!=NULL; ms=ms->next ) { + if( line != ms->line ) continue; + if( file==NULL ) { + if( ms->file == NULL ) break; + continue; + } + if( ms->file == NULL ) continue; + if( !strcmp( ms->file, file ) ) break; + } + + if( ms != NULL ) return ms; + + if( !makenew ) return NULL; + + ms = (mwStat*) malloc( sizeof(mwStat) ); + if( ms == NULL ) { + if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) || + (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) { + mwWrite("internal: memory low, statistics incomplete for '%s'\n", file ); + return NULL; + } + } + ms->file = file; + ms->line = line; + ms->total = 0L; + ms->max = 0L; + ms->num = 0L; + ms->curr = 0L; + ms->next = mwStatList; + mwStatList = ms; + return ms; + } + +static void mwStatAlloc( size_t size, const char* file, int line ) { + mwStat* ms; + + /* update the module statistics */ + ms = mwStatGet( file, -1, 1 ); + if( ms != NULL ) { + ms->total += (long) size; + ms->curr += (long) size; + ms->num ++; + if( ms->curr > ms->max ) ms->max = ms->curr; + } + + /* update the line statistics */ + if( mwStatLevel > 1 && line != -1 && file ) { + ms = mwStatGet( file, line, 1 ); + if( ms != NULL ) { + ms->total += (long) size; + ms->curr += (long) size; + ms->num ++; + if( ms->curr > ms->max ) ms->max = ms->curr; + } + } + + } + +static void mwStatFree( size_t size, const char* file, int line ) { + mwStat* ms; + + /* update the module statistics */ + ms = mwStatGet( file, -1, 1 ); + if( ms != NULL ) ms->curr -= (long) size; + + /* update the line statistics */ + if( mwStatLevel > 1 && line != -1 && file ) { + ms = mwStatGet( file, line, 1 ); + if( ms != NULL ) ms->curr -= (long) size; + } + } + +#if 0 /* 980317: disabled C++ */ + +/********************************************************************** +** C++ new & delete +**********************************************************************/ + +#ifdef __cplusplus +#ifndef MEMWATCH_NOCPP + +int mwNCur = 0; +const char *mwNFile = NULL; +int mwNLine = 0; + +class MemWatch { +public: + MemWatch(); + ~MemWatch(); + }; + +MemWatch::MemWatch() { + if( mwInited ) return; + mwUseAtexit = 0; + mwInit(); + } + +MemWatch::~MemWatch() { + if( mwUseAtexit ) return; + mwTerm(); + } + +/* +** This global new will catch all 'new' calls where MEMWATCH is +** not active. +*/ +void* operator new( unsigned size ) { + mwNCur = 0; + return mwMalloc( size, "", 0 ); + } + +/* +** This is the new operator that's called when a module uses mwNew. +*/ +void* operator new( unsigned size, const char *file, int line ) { + mwNCur = 0; + return mwMalloc( size, file, line ); + } + +/* +** Since this delete operator will recieve ALL delete's +** even those from within libraries, we must accept +** delete's before we've been initialized. Nor can we +** reliably check for wild free's if the mwNCur variable +** is not set. +*/ +void operator delete( void *p ) { + if( p == NULL ) return; + if( !mwInited ) { + free( p ); + return; + } + if( mwNCur ) { + mwFree( p, mwNFile, mwNLine ); + mwNCur = 0; + return; + } + mwFree_( p ); + } + +#endif /* MEMWATCH_NOCPP */ +#endif /* __cplusplus */ + +#endif /* 980317: disabled C++ */ + +/* MEMWATCH.C */ \ No newline at end of file diff --git a/lib/memwatch.h b/lib/memwatch.h new file mode 100644 index 00000000..4ef003fa --- /dev/null +++ b/lib/memwatch.h @@ -0,0 +1,701 @@ +/* +** MEMWATCH.H +** Nonintrusive ANSI C memory leak / overwrite detection +** Copyright (C) 1992-99 Johan Lindh +** All rights reserved. +** Version 2.62 +** +************************************************************************ +** +** PURPOSE: +** +** MEMWATCH has been written to allow guys and gals that like to +** program in C a public-domain memory error control product. +** I hope you'll find it's as advanced as most commercial packages. +** The idea is that you use it during the development phase and +** then remove the MEMWATCH define to produce your final product. +** MEMWATCH is distributed in source code form in order to allow +** you to compile it for your platform with your own compiler. +** It's aim is to be 100% ANSI C, but some compilers are more stingy +** than others. If it doesn't compile without warnings, please mail +** me the configuration of operating system and compiler you are using +** along with a description of how to modify the source, and the version +** number of MEMWATCH that you are using. +** +************************************************************************ +** +** And now for some legalese... +** +** LICENSE: +** +** You are granted a non-exclusive right to use MEMWATCH in your +** programs, provided that you agree to the following terms: +** +** 1. Johan Lindh retains the full copyright of MEMWATCH, and owns +** all rights to it. This means you can't sell it yourself, or +** ship it as part of another product, or as part of a package. +** 2. If you modify any of the files, you must not give them to +** anyone else. But please send me a copy of the changes, +** along with a text as to why they should be implemented. +** 3. You read and agree to the DISCLAIMER, below. +** +** DISCLAIMER: +** +** THIS SOFTWARE IS PROVIDED FREE OF CHARGE 'AS IS' AND JOHAN LINDH MAKES +** NO EXPRESS OR IMPLIED WARRANTIES WITH RESPECT TO IT. JOHAN LINDH WILL +** NOT BE LIABLE FOR ANY DAMAGES, DIRECT OR INDIRECT, ARISING FROM THE +** USAGE OR HANDLING OF THIS SOFTWARE. +** +************************************************************************ +** +** REVISION HISTORY: +** +** 920810 JLI [1.00] +** 920830 JLI [1.10 double-free detection] +** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit] +** 921022 JLI [1.20 ASSERT and VERIFY] +** 921105 JLI [1.30 C++ support and TRACE] +** 921116 JLI [1.40 mwSetOutFunc] +** 930215 JLI [1.50 modified ASSERT/VERIFY] +** 930327 JLI [1.51 better auto-init & PC-lint support] +** 930506 JLI [1.55 MemWatch class, improved C++ support] +** 930507 JLI [1.60 mwTest & CHECK()] +** 930809 JLI [1.65 Abort/Retry/Ignore] +** 930820 JLI [1.70 data dump when unfreed] +** 931016 JLI [1.72 modified C++ new/delete handling] +** 931108 JLI [1.77 mwSetAssertAction() & some small changes] +** 940110 JLI [1.80 no-mans-land alloc/checking] +** 940328 JLI [2.00 version 2.0 rewrite] +** Improved NML (no-mans-land) support. +** Improved performance (especially for free()ing!). +** Support for 'read-only' buffers (checksums) +** ^^ NOTE: I never did this... maybe I should? +** FBI (free'd block info) tagged before freed blocks +** Exporting of the mwCounter variable +** mwBreakOut() localizes debugger support +** Allocation statistics (global, per-module, per-line) +** Self-repair ability with relinking +** 950913 JLI [2.10 improved garbage handling] +** 951201 JLI [2.11 improved auto-free in emergencies] +** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()] +** 960514 JLI [2.12 undefining of existing macros] +** 960515 JLI [2.13 possibility to use default new() & delete()] +** 960516 JLI [2.20 suppression of file flushing on unfreed msgs] +** 960516 JLI [2.21 better support for using MEMWATCH with DLL's] +** 960710 JLI [X.02 multiple logs and mwFlushNow()] +** 960801 JLI [2.22 merged X.01 version with current] +** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's] +** 960805 JLI [2.31 merged X.02 version with current] +** 961002 JLI [2.32 support for realloc() + fixed STDERR bug] +** 961222 JLI [2.40 added mwMark() & mwUnmark()] +** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY] +** 970113 JLI [2.42 added support for PC-Lint 7.00g] +** 970207 JLI [2.43 added support for strdup()] +** 970209 JLI [2.44 changed default filename to lowercase] +** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers] +** 970723 JLI [2.46 added MW_ARI_NULLREAD flag] +** 970813 JLI [2.47 stabilized marker handling] +** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway] +** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support] +** 980417 JLI [2.51 more checks for invalid addresses] +** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting] +** 990112 JLI [2.53 added check for empty heap to mwIsOwned] +** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML] +** 990224 JLI [2.56 changed ordering of members in structures] +** 990303 JLI [2.57 first maybe-fixit-for-hpux test] +** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit] +** 990517 JLI [2.59 fixed some high-sensitivity warnings] +** 990610 JLI [2.60 fixed some more high-sensitivity warnings] +** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names] +** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()] +** +** To use, simply include 'MEMWATCH.H' as a header file, +** and add MEMWATCH.C to your list of files, and define the macro +** 'MEMWATCH'. If this is not defined, MEMWATCH will disable itself. +** +** To call the standard C malloc / realloc / calloc / free; use mwMalloc_(), +** mwCalloc_() and mwFree_(). Note that mwFree_() will correctly +** free both malloc()'d memory as well as mwMalloc()'d. +** +** 980317: C++ support has been disabled. +** The code remains, but is not compiled. +** +** For use with C++, which allows use of inlining in header files +** and class specific new/delete, you must also define 'new' as +** 'mwNew' and 'delete' as 'mwDelete'. Do this *after* you include +** C++ header files from libraries, otherwise you can mess up their +** class definitions. If you don't define these, the C++ allocations +** will not have source file and line number information. Also note, +** most C++ class libraries implement their own C++ memory management, +** and don't allow anyone to override them. MFC belongs to this crew. +** In these cases, the only thing to do is to use MEMWATCH_NOCPP. +** +** You can capture output from MEMWATCH using mwSetOutFunc(). +** Just give it the adress of a "void myOutFunc(int c)" function, +** and all characters to be output will be redirected there. +** +** A failing ASSERT() or VERIFY() will normally always abort your +** program. This can be changed using mwSetAriFunc(). Give it a +** pointer to a "int myAriFunc(const char *)" function. Your function +** must ask the user whether to Abort, Retry or Ignore the trap. +** Return 2 to Abort, 1 to Retry or 0 to Ignore. Beware retry; it +** causes the expression to be evaluated again! MEMWATCH has a +** default ARI handler. It's disabled by default, but you can enable +** it by calling 'mwDefaultAri()'. Note that this will STILL abort +** your program unless you define MEMWATCH_STDIO to allow MEMWATCH +** to use the standard C I/O streams. Also, setting the ARI function +** will cause MEMWATCH *NOT* to write the ARI error to stderr. The +** error string is passed to the ARI function instead, as the +** 'const char *' parameter. +** +** You can disable MEMWATCH's ASSERT/VERIFY and/or TRACE implementations. +** This can be useful if you're using a debug terminal or smart debugger. +** Disable them by defining MW_NOASSERT, MW_NOVERIFY or MW_NOTRACE. +** +** MEMWATCH fills all allocated memory with the byte 0xFE, so if +** you're looking at erroneous data which are all 0xFE:s, the +** data probably was not initialized by you. The exception is +** calloc(), which will fill with zero's. All freed buffers are +** zapped with 0xFD. If this is what you look at, you're using +** data that has been freed. If this is the case, be aware that +** MEMWATCH places a 'free'd block info' structure immediately +** before the freed data. This block contains info about where +** the block was freed. The information is in readable text, +** in the format "FBIfilename(line)", for example: +** "FBI<267>test.c(12)". Using FBI's slows down free(), so it's +** disabled by default. Use mwFreeBufferInfo(1) to enable it. +** +** To aid in tracking down wild pointer writes, MEMWATCH can perform +** no-mans-land allocations. No-mans-land will contain the byte 0xFC. +** MEMWATCH will, when this is enabled, convert recently free'd memory +** into NML allocations. +** +** MEMWATCH protects it's own data buffers with checksums. If you +** get an internal error, it means you're overwriting wildly, +** or using an uninitialized pointer. +** +************************************************************************ +** +** Note when compiling with Microsoft C: +** - MSC ignores fflush() by default. This is overridden, so that +** the disk log will always be current. +** +** This utility has been tested with: +** PC-lint 7.0k, passed as 100% ANSI C compatible +** Microsoft Visual C++ on Win16 and Win32 +** Microsoft C on DOS +** SAS C on an Amiga 500 +** Gnu C on a PC running Red Hat Linux +** ...and using an (to me) unknown compiler on an Atari machine. +** +************************************************************************ +** +** Format of error messages in MEMWATCH.LOG: +** message: filename(linenumber), information +** +** Errors caught by MemWatch, when they are detected, and any +** actions taken besides writing to the log file MEMWATCH.LOG: +** +** Double-freeing: +** A pointer that was recently freed and has not since been +** reused was freed again. The place where the previous free() +** was executed is displayed. +** Detect: delete or free() using the offending pointer. +** Action: The delete or free() is cancelled, execution continues. +** Underflow: +** You have written just ahead of the allocated memory. +** The size and place of the allocation is displayed. +** Detect: delete or free() of the damaged buffer. +** Action: The buffer is freed, but there may be secondary damage. +** Overflow: +** Like underflow, but you've written after the end of the buffer. +** Detect: see Underflow. +** Action: see Underflow. +** WILD free: +** An unrecognized pointer was passed to delete or free(). +** The pointer may have been returned from a library function; +** in that case, use mwFree_() to force free() of it. +** Also, this may be a double-free, but the previous free was +** too long ago, causing MEMWATCH to 'forget' it. +** Detect: delete or free() of the offending pointer. +** Action: The delete or free() is cancelled, execution continues. +** NULL free: +** It's unclear to me whether or not freeing of NULL pointers +** is legal in ANSI C, therefore a warning is written to the log file, +** but the error counter remains the same. This is legal using C++, +** so the warning does not appear with delete. +** Detect: When you free(NULL). +** Action: The free() is cancelled. +** Failed: +** A request to allocate memory failed. If the allocation is +** small, this may be due to memory depletion, but is more likely +** to be memory fragmentation problems. The amount of memory +** allocated so far is displayed also. +** Detect: When you new, malloc(), realloc() or calloc() memory. +** Action: NULL is returned. +** Realloc: +** A request to re-allocate a memory buffer failed for reasons +** other than out-of-memory. The specific reason is shown. +** Detect: When you realloc() +** Action: realloc() is cancelled, NULL is returned +** Limit fail: +** A request to allocate memory failed since it would violate +** the limit set using mwLimit(). mwLimit() is used to stress-test +** your code under simulated low memory conditions. +** Detect: At new, malloc(), realloc() or calloc(). +** Action: NULL is returned. +** Assert trap: +** An ASSERT() failed. The ASSERT() macro works like C's assert() +** macro/function, except that it's interactive. See your C manual. +** Detect: On the ASSERT(). +** Action: Program ends with an advisory message to stderr, OR +** Program writes the ASSERT to the log and continues, OR +** Program asks Abort/Retry/Ignore? and takes that action. +** Verify trap: +** A VERIFY() failed. The VERIFY() macro works like ASSERT(), +** but if MEMWATCH is not defined, it still evaluates the +** expression, but it does not act upon the result. +** Detect: On the VERIFY(). +** Action: Program ends with an advisory message to stderr, OR +** Program writes the VERIFY to the log and continues, OR +** Program asks Abort/Retry/Ignore? and takes that action. +** Wild pointer: +** A no-mans-land buffer has been written into. MEMWATCH can +** allocate and distribute chunks of memory solely for the +** purpose of trying to catch random writes into memory. +** Detect: Always on CHECK(), but can be detected in several places. +** Action: The error is logged, and if an ARI handler is installed, +** it is executed, otherwise, execution continues. +** Unfreed: +** A memory buffer you allocated has not been freed. +** You are informed where it was allocated, and whether any +** over or underflow has occured. MemWatch also displays up to +** 16 bytes of the data, as much as it can, in hex and text. +** Detect: When MemWatch terminates. +** Action: The buffer is freed. +** Check: +** An error was detected during a CHECK() operation. +** The associated pointer is displayed along with +** the file and line where the CHECK() was executed. +** Followed immediately by a normal error message. +** Detect: When you CHECK() +** Action: Depends on the error +** Relink: +** After a MEMWATCH internal control block has been trashed, +** MEMWATCH tries to repair the damage. If successful, program +** execution will continue instead of aborting. Some information +** about the block may be gone permanently, though. +** Detect: N/A +** Action: Relink successful: program continues. +** Relink fails: program aborts. +** Internal: +** An internal error is flagged by MEMWATCH when it's control +** structures have been damaged. You are likely using an uninitialized +** pointer somewhere in your program, or are zapping memory all over. +** The message may give you additional diagnostic information. +** If possible, MEMWATCH will recover and continue execution. +** Detect: Various actions. +** Action: Whatever is needed +** Mark: +** The program terminated without umarking all marked pointers. Marking +** can be used to track resources other than memory. mwMark(pointer,text,...) +** when the resource is allocated, and mwUnmark(pointer) when it's freed. +** The 'text' is displayed for still marked pointers when the program +** ends. +** Detect: When MemWatch terminates. +** Action: The error is logged. +** +** +************************************************************************ +** +** The author may be reached by e-mail at the address below. If you +** mail me about source code changes in MEMWATCH, remember to include +** MW's version number. +** +** Johan Lindh +** johan@link-data.com +** +** The latest version of MEMWATCH may be downloaded from +** http://www.link-data.com/ +*/ + +#ifdef MEMWATCH + +#ifndef __MEMWATCH_H +#define __MEMWATCH_H + +/* Make sure that malloc(), realloc(), calloc() and free() are declared. */ +/*lint -save -e537 */ +#include +/*lint -restore */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +** Constants used +** All MEMWATCH constants start with the prefix MW_, followed by +** a short mnemonic which indicates where the constant is used, +** followed by a descriptive text about it. +*/ + +#define MW_ARI_NULLREAD 0x10 /* Null read (to start debugger) */ +#define MW_ARI_ABORT 0x04 /* ARI handler says: abort program! */ +#define MW_ARI_RETRY 0x02 /* ARI handler says: retry action! */ +#define MW_ARI_IGNORE 0x01 /* ARI handler says: ignore error! */ + +#define MW_VAL_NEW 0xFE /* value in newly allocated memory */ +#define MW_VAL_DEL 0xFD /* value in newly deleted memory */ +#define MW_VAL_NML 0xFC /* value in no-mans-land */ +#define MW_VAL_GRB 0xFB /* value in grabbed memory */ + +#define MW_TEST_ALL 0xFFFF /* perform all tests */ +#define MW_TEST_CHAIN 0x0001 /* walk the heap chain */ +#define MW_TEST_ALLOC 0x0002 /* test allocations & NML guards */ +#define MW_TEST_NML 0x0004 /* test all-NML areas for modifications */ + +#define MW_NML_NONE 0 /* no NML */ +#define MW_NML_FREE 1 /* turn FREE'd memory into NML */ +#define MW_NML_ALL 2 /* all unused memory is NML */ +#define MW_NML_DEFAULT 0 /* the default NML setting */ + +#define MW_STAT_GLOBAL 0 /* only global statistics collected */ +#define MW_STAT_MODULE 1 /* collect statistics on a module basis */ +#define MW_STAT_LINE 2 /* collect statistics on a line basis */ +#define MW_STAT_DEFAULT 0 /* the default statistics setting */ + +/* +** MemWatch internal constants +** You may change these and recompile MemWatch to change the limits +** of some parameters. Respect the recommended minimums! +*/ +#define MW_TRACE_BUFFER 256 /* (min 160) size of TRACE()'s output buffer */ +#define MW_FREE_LIST 64 /* (min 4) number of free()'s to track */ + +/* +** Exported variables +** In case you have to remove the 'const' keyword because your compiler +** doesn't support it, be aware that changing the values may cause +** unpredictable behaviour. +** - mwCounter contains the current action count. You can use this to +** place breakpoints using a debugger, if you want. +*/ +#ifndef __MEMWATCH_C +extern const unsigned long mwCounter; +#endif + +/* +** System functions +** Normally, it is not nessecary to call any of these. MEMWATCH will +** automatically initialize itself on the first MEMWATCH function call, +** and set up a call to mwAbort() using atexit(). Some C++ implementations +** run the atexit() chain before the program has terminated, so you +** may have to use mwInit() or the MemWatch C++ class to get good +** behaviour. +** - mwInit() can be called to disable the atexit() usage. If mwInit() +** is called directly, you must call mwTerm() to end MemWatch, or +** mwAbort(). +** - mwTerm() is usually not nessecary to call; but if called, it will +** call mwAbort() if it finds that it is cancelling the 'topmost' +** mwInit() call. +** - mwAbort() cleans up after MEMWATCH, reports unfreed buffers, etc. +*/ +void mwInit( void ); +void mwTerm( void ); +void mwAbort( void ); + +/* +** Setup functions +** These functions control the operation of MEMWATCH's protective features. +** - mwFlushNow() causes MEMWATCH to flush it's buffers. +** - mwDoFlush() controls whether MEMWATCH flushes the disk buffers after +** writes. The default is smart flushing: MEMWATCH will not flush buffers +** explicitly until memory errors are detected. Then, all writes are +** flushed until program end or mwDoFlush(0) is called. +** - mwLimit() sets the allocation limit, an arbitrary limit on how much +** memory your program may allocate in bytes. Used to stress-test app. +** Also, in virtual-memory or multitasking environs, puts a limit on +** how much MW_NML_ALL can eat up. +** - mwGrab() grabs up X kilobytes of memory. Allocates actual memory, +** can be used to stress test app & OS both. +** - mwDrop() drops X kilobytes of grabbed memory. +** - mwNoMansLand() sets the behaviour of the NML logic. See the +** MW_NML_xxx for more information. The default is MW_NML_DEFAULT. +** - mwStatistics() sets the behaviour of the statistics collector. See +** the MW_STAT_xxx defines for more information. Default MW_STAT_DEFAULT. +** - mwFreeBufferInfo() enables or disables the tagging of free'd buffers +** with freeing information. This information is written in text form, +** using sprintf(), so it's pretty slow. Disabled by default. +** - mwAutoCheck() performs a CHECK() operation whenever a MemWatch function +** is used. Slows down performance, of course. +** - mwCalcCheck() calculates checksums for all data buffers. Slow! +** - mwDumpCheck() logs buffers where stored & calc'd checksums differ. Slow!! +** - mwMark() sets a generic marker. Returns the pointer given. +** - mwUnmark() removes a generic marker. If, at the end of execution, some +** markers are still in existence, these will be reported as leakage. +** returns the pointer given. +*/ +void mwFlushNow( void ); +void mwDoFlush( int onoff ); +void mwLimit( long bytes ); +unsigned mwGrab( unsigned kilobytes ); +unsigned mwDrop( unsigned kilobytes ); +void mwNoMansLand( int mw_nml_level ); +void mwStatistics( int level ); +void mwFreeBufferInfo( int onoff ); +void mwAutoCheck( int onoff ); +void mwCalcCheck( void ); +void mwDumpCheck( void ); +void * mwMark( void *p, const char *description, const char *file, unsigned line ); +void * mwUnmark( void *p, const char *file, unsigned line ); + +/* +** Testing/verification/tracing +** All of these macros except VERIFY() evaluates to a null statement +** if MEMWATCH is not defined during compilation. +** - mwIsReadAddr() checks a memory area for read privilige. +** - mwIsSafeAddr() checks a memory area for both read & write privilige. +** This function and mwIsReadAddr() is highly system-specific and +** may not be implemented. If this is the case, they will default +** to returning nonzero for any non-NULL pointer. +** - CHECK() does a complete memory integrity test. Slow! +** - CHECK_THIS() checks only selected components. +** - CHECK_BUFFER() checks the indicated buffer for errors. +** - mwASSERT() or ASSERT() If the expression evaluates to nonzero, execution continues. +** Otherwise, the ARI handler is called, if present. If not present, +** the default ARI action is taken (set with mwSetAriAction()). +** ASSERT() can be disabled by defining MW_NOASSERT. +** - mwVERIFY() or VERIFY() works just like ASSERT(), but when compiling without +** MEMWATCH the macro evaluates to the expression. +** VERIFY() can be disabled by defining MW_NOVERIFY. +** - mwTRACE() or TRACE() writes some text and data to the log. Use like printf(). +** Note: there is a limit to the maximum resulting string length that +** can be written. This defaults to MW_TRACE_BUFFER characters. +** TRACE() can be disabled by defining MW_NOTRACE. +*/ +int mwIsReadAddr( const void *p, unsigned len ); +int mwIsSafeAddr( void *p, unsigned len ); +int mwTest( const char *file, int line, int mw_test_flags ); +int mwTestBuffer( const char *file, int line, void *p ); +int mwAssert( int, const char*, const char*, int ); +int mwVerify( int, const char*, const char*, int ); + +/* +** User I/O functions +** - mwTrace() works like printf(), but dumps output either to the +** function specified with mwSetOutFunc(), or the log file. +** - mwPuts() works like puts(), dumps output like mwTrace(). +** - mwSetOutFunc() allows you to give the adress of a function +** where all user output will go. (exeption: see mwSetAriFunc) +** Specifying NULL will direct output to the log file. +** - mwSetAriFunc() gives MEMWATCH the adress of a function to call +** when an 'Abort, Retry, Ignore' question is called for. The +** actual error message is NOT printed when you've set this adress, +** but instead it is passed as an argument. If you call with NULL +** for an argument, the ARI handler is disabled again. When the +** handler is disabled, MEMWATCH will automatically take the +** action specified by mwSetAriAction(). +** - mwSetAriAction() sets the default ARI return value MEMWATCH should +** use if no ARI handler is specified. Defaults to MW_ARI_ABORT. +** - mwAriHandler() is an ANSI ARI handler you can use if you like. It +** dumps output to stderr, and expects input from stdin. +** - mwBreakOut() is called in certain cases when MEMWATCH feels it would +** be nice to break into a debugger. If you feel like MEMWATCH, place +** an execution breakpoint on this function. +*/ +void mwTrace( const char* format_string, ... ); +void mwPuts( const char* text ); +void mwSetOutFunc( void (*func)(int) ); +void mwSetAriFunc( int (*func)(const char*) ); +void mwSetAriAction( int mw_ari_value ); +int mwAriHandler( const char* cause ); +void mwBreakOut( const char* cause ); + +/* +** Allocation/deallocation functions +** These functions are the ones actually to perform allocations +** when running MEMWATCH, for both C and C++ calls. +** - mwMalloc() debugging allocator +** - mwMalloc_() always resolves to a clean call of malloc() +** - mwRealloc() debugging re-allocator +** - mwRealloc_() always resolves to a clean call of realloc() +** - mwCalloc() debugging allocator, fills with zeros +** - mwCalloc_() always resolves to a clean call of calloc() +** - mwFree() debugging free. Can only free memory which has +** been allocated by MEMWATCH. +** - mwFree_() resolves to a) normal free() or b) debugging free. +** Can free memory allocated by MEMWATCH and malloc() both. +** Does not generate any runtime errors. +*/ +void* mwMalloc( size_t, const char*, int ); +void* mwMalloc_( size_t ); +void* mwRealloc( void *, size_t, const char*, int ); +void* mwRealloc_( void *, size_t ); +void* mwCalloc( size_t, size_t, const char*, int ); +void* mwCalloc_( size_t, size_t ); +void mwFree( void*, const char*, int ); +void mwFree_( void* ); +char* mwStrdup( char *, const char*, int ); + +/* +** Enable/disable precompiler block +** This block of defines and if(n)defs make sure that references +** to MEMWATCH is completely removed from the code if the MEMWATCH +** manifest constant is not defined. +*/ +#ifndef __MEMWATCH_C +#ifdef MEMWATCH + +#define mwASSERT(exp) while(mwAssert((int)(exp),#exp,__FILE__,__LINE__)) +#ifndef MW_NOASSERT +#ifndef ASSERT +#define ASSERT mwASSERT +#endif /* !ASSERT */ +#endif /* !MW_NOASSERT */ +#define mwVERIFY(exp) while(mwVerify((int)(exp),#exp,__FILE__,__LINE__)) +#ifndef MW_NOVERIFY +#ifndef VERIFY +#define VERIFY mwVERIFY +#endif /* !VERIFY */ +#endif /* !MW_NOVERIFY */ +#define mwTRACE mwTrace +#ifndef MW_NOTRACE +#ifndef TRACE +#define TRACE mwTRACE +#endif /* !TRACE */ +#endif /* !MW_NOTRACE */ + +#define malloc(n) mwMalloc(n,__FILE__,__LINE__) +#ifdef strdup +#undef strdup +#endif +#define strdup(p) mwStrdup(p,__FILE__,__LINE__) +#define realloc(p,n) mwRealloc(p,n,__FILE__,__LINE__) +#define calloc(n,m) mwCalloc(n,m,__FILE__,__LINE__) +#define free(p) mwFree(p,__FILE__,__LINE__) +#define CHECK() mwTest(__FILE__,__LINE__,MW_TEST_ALL) +#define CHECK_THIS(n) mwTest(__FILE__,__LINE__,n) +#define CHECK_BUFFER(b) mwTestBuffer(__FILE__,__LINE__,b) +#define MARK(p) mwMark(p,#p,__FILE__,__LINE__) +#define UNMARK(p) mwUnmark(p,__FILE__,__LINE__) + +#else /* MEMWATCH */ + +#define mwASSERT(exp) +#ifndef MW_NOASSERT +#ifndef ASSERT +#define ASSERT mwASSERT +#endif /* !ASSERT */ +#endif /* !MW_NOASSERT */ + +#define mwVERIFY(exp) exp +#ifndef MW_NOVERIFY +#ifndef VERIFY +#define VERIFY mwVERIFY +#endif /* !VERIFY */ +#endif /* !MW_NOVERIFY */ + +/*lint -esym(773,mwTRACE) */ +#define mwTRACE /*lint -save -e506 */ 1?(void)0:mwDummyTraceFunction /*lint -restore */ +#ifndef MW_NOTRACE +#ifndef TRACE +/*lint -esym(773,TRACE) */ +#define TRACE mwTRACE +#endif /* !TRACE */ +#endif /* !MW_NOTRACE */ + +extern void mwDummyTraceFunction(const char *,...); +/*lint -save -e652 */ +#define mwDoFlush(n) +#define mwPuts(s) +#define mwInit() +#define mwGrab(n) +#define mwDrop(n) +#define mwLimit(n) +#define mwTest(f,l) +#define mwSetOutFunc(f) +#define mwSetAriFunc(f) +#define mwDefaultAri() +#define mwNomansland() +#define mwStatistics(f) +#define mwMark(p,t,f,n) (p) +#define mwUnmark(p,f,n) (p) +#define mwMalloc(n,f,l) malloc(n) +#define mwStrdup(p,f,l) strdup(p) +#define mwRealloc(p,n,f,l) realloc(p,n) +#define mwCalloc(n,m,f,l) calloc(n,m) +#define mwFree(p) free(p) +#define mwMalloc_(n) malloc(n) +#define mwRealloc_(p,n) realloc(p,n) +#define mwCalloc_(n,m) calloc(n,m) +#define mwFree_(p) free(p) +#define mwAssert(e,es,f,l) +#define mwVerify(e,es,f,l) (e) +#define mwTrace mwDummyTrace +#define mwTestBuffer(f,l,b) (0) +#define CHECK() +#define CHECK_THIS(n) +#define CHECK_BUFFER(b) +#define MARK(p) (p) +#define UNMARK(p) (p) +/*lint -restore */ + +#endif /* MEMWATCH */ +#endif /* !__MEMWATCH_C */ + +#ifdef __cplusplus + } +#endif + +#if 0 /* 980317: disabled C++ */ + +/* +** C++ support section +** Implements the C++ support. Please note that in order to avoid +** messing up library classes, C++ support is disabled by default. +** You must NOT enable it until AFTER the inclusion of all header +** files belonging to code that are not compiled with MEMWATCH, and +** possibly for some that are! The reason for this is that a C++ +** class may implement it's own new() function, and the preprocessor +** would substitute this crucial declaration for MEMWATCH new(). +** You can forcibly deny C++ support by defining MEMWATCH_NOCPP. +** To enble C++ support, you must be compiling C++, MEMWATCH must +** be defined, MEMWATCH_NOCPP must not be defined, and finally, +** you must define 'new' to be 'mwNew', and 'delete' to be 'mwDelete'. +** Unlike C, C++ code can begin executing *way* before main(), for +** example if a global variable is created. For this reason, you can +** declare a global variable of the class 'MemWatch'. If this is +** is the first variable created, it will then check ALL C++ allocations +** and deallocations. Unfortunately, this evaluation order is not +** guaranteed by C++, though the compilers I've tried evaluates them +** in the order encountered. +*/ +#ifdef __cplusplus +#ifndef __MEMWATCH_C +#ifdef MEMWATCH +#ifndef MEMWATCH_NOCPP +extern int mwNCur; +extern const char *mwNFile; +extern int mwNLine; +class MemWatch { +public: + MemWatch(); + ~MemWatch(); + }; +void * operator new(size_t); +void * operator new(size_t,const char *,int); +void operator delete(void *); +#define mwNew new(__FILE__,__LINE__) +#define mwDelete (mwNCur=1,mwNFile=__FILE__,mwNLine=__LINE__),delete +#endif /* MEMWATCH_NOCPP */ +#endif /* MEMWATCH */ +#endif /* !__MEMWATCH_C */ +#endif /* __cplusplus */ + +#endif /* 980317: disabled C++ */ + +#endif /* __MEMWATCH_H */ + +#endif /* EOF MEMWATCH.H */ diff --git a/lib/mime.c b/lib/mime.c new file mode 100644 index 00000000..462e4fe2 --- /dev/null +++ b/lib/mime.c @@ -0,0 +1,266 @@ +/***************************************************************************** + * + * File ..................: mime.c + * Purpose ...............: Common library + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +/* QP-Decode code by T.Tanaka */ +/* QP-Encode inspired from sendmail code of Berkley */ + +/* XD() converts hexadecimal digit to decimal */ +#define XD(c) ( (((c) >= '0') && ((c) <= '9')) ? (c) - '0' : \ + (((c) >= 'A') && ((c) <= 'F')) ? (c) - 'A' + 10 : \ + (((c) >= 'a') && ((c) <= 'f')) ? (c) - 'a' + 10 : 0) + +/* chars to be converted in qp_encode() */ +char badchars[] = "\001\002\003\004\005\006\007" \ + "\010\011\012\013\014\015\016\017" \ + "\020\021\022\023\024\025\026\027" \ + "\030\031\032\033\034\035\036\037" \ + "\177" \ + "\200\201\202\203\204\205\206\207" \ + "\210\211\212\213\214\215\216\217" \ + "\220\221\222\223\224\225\226\227" \ + "\230\231\232\233\234\235\236\237" \ + "\240\241\242\243\244\245\246\247" \ + "\250\251\252\253\254\255\256\257" \ + "\260\261\262\263\264\265\266\267" \ + "\270\271\272\273\274\275\276\277" \ + "\300\301\302\303\304\305\306\307" \ + "\310\311\312\313\314\315\316\317" \ + "\320\321\322\323\324\325\326\327" \ + "\330\331\332\333\334\335\336\337" \ + "\340\341\342\343\344\345\346\347" \ + "\350\351\352\353\354\355\356\357" \ + "\360\361\362\363\364\365\366\367" \ + "\370\371\372\373\374\375\376\377"; +char badchars2[] = "!\"#$@[\\]^`{|}~()<>,;:/_"; + +char Base16Code[] = "0123456789ABCDEF"; +char Base64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* returns numeric value from a Base64Code[] digit */ +static int index_hex[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1,0x3e, -1, -1, -1,0x3f, + 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b, + 0x3c,0x3d, -1, -1, -1, -1, -1, -1, + -1,0x00,0x01,0x02,0x03,0x04,0x05,0x06, + 0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16, + 0x17,0x18,0x19, -1, -1, -1, -1, -1, + -1,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20, + 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30, + 0x31,0x32,0x33, -1, -1, -1, -1, -1 +}; + + + +char *qp_decode(char *s) +{ + static char *buf; + char *p, *q; + + if (buf) + free(buf); + if ((buf = malloc(strlen(s) + 1 * sizeof(char))) == NULL) { + WriteError("qp_decode: out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + if (*p == '=') { + ++p; + if (*p == '\0') { /* ends with "=(null)" */ + *q++ = '='; + break; + } else if (*p == '\n') + break; + else if (isxdigit(*p) && isxdigit(*(p + 1))) { + *q++ = 16 * XD(*p) + XD(*(p + 1)); + ++p; + ++p; + } else { /* "=1x" "=5(null)" "=G\n" "=0=" etc. */ + *q++ = '='; + *q++ = *p++; + } + } else + *q++ = *p++; + } + *q = '\0'; + + return buf; +} + + + +char *qp_encode(char *s, int mode) +{ + static char *buf; + char *p, *q; + int linelen = 0; + + if (buf) + free(buf); + if ((buf = malloc(3 * strlen(s) + 1 * sizeof(char))) == NULL) { + WriteError("qp_encode: out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + if (*p == '\n') { + *q++ = *p++; + linelen = 0; + } else if ((mode == 1) && (*p == ' ')) { + *q++ = '_'; + p++; + linelen += 1; + } else if (*p == ' ' || *p == '\t') { + if ((linelen > 72) && (*(p+1) != '\n')) { + *q++ = *p++; + *q++ = '='; + *q++ = '\n'; + linelen = 0; + } else if (*(p+1) == '\n') { + *q++ = *p++; + *q++ = '='; + *q++ = *p++; + linelen = 0; + } else { + *q++ = *p++; + linelen += 1; + } + } else if ((strchr(badchars,*p)) || (*p == '=') || ((mode==1) && (strchr(badchars2,*p)))) { + if (linelen > 72) { + *q++ = '\n'; + linelen = 0; + } + *q++ = '='; + *q++ = Base16Code[(*p >> 4) & 0x0f]; + *q++ = Base16Code[*p & 0x0f]; + linelen += 3; + p++; + } else { + *q++ = *p++; + linelen++; + } + } + *q = '\0'; + + return buf; +} + + + +/* + * Base64 stores 3 bytes of 8bits into 4 bytes of six bits (the 2 remaining + * bits are left to 0). + * + * AAAAAAAA BBBBBBBB CCCCCCCC --> 00AAAAAA 00AABBBB 00BBBBCC 00CCCCCC + * + */ + +char *b64_decode(char *s) +{ + static char *buf; + static char buf2[4]; + char *p, *q; + int i,t; + + if (buf) + free(buf); + if ((buf = malloc(3 * strlen(s) + 1 * sizeof(char))) == NULL) { + WriteError("b64_decode:out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + for (i = 0; i < 4; i++) + buf2[i]=0x40; + for (i = 0;((i < 4) && (*p != '\0'));) { + t = (index_hex[(unsigned int)*p]); + if (*p == '=') + buf2[i++]=0x40; + else if (t != -1) + buf2[i++]=(char)t; + p++; + } + if ((buf2[0] < 0x40) && (buf2[1] < 0x40)) + *q++=(((buf2[0] & 0x3f) << 2) | ((buf2[1] >> 4) & 0x03)); + if ((buf2[1] < 0x40) && (buf2[2] < 0x40)) + *q++=(((buf2[1] & 0x0f) << 4) | ((buf2[2] >> 2) & 0x0f)); + if ((buf2[2] < 0x40) && (buf2[3] < 0x40)) + *q++=(((buf2[2] & 0x03) << 6) | (buf2[3] & 0x3f)); + } + *q = '\0'; + + return buf; +} + + + +char *b64_encode(char *s) +{ + static char *buf; + static char buf2[3]; + char *p, *q; + int i; + + if (buf) + free(buf); + if ((buf = malloc(3 * strlen(s) + 1 * sizeof(char))) == NULL) { + WriteError("b64_encode:out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + for (i = 0; ((i < 3) && (*p != '\0')); ) + buf2[i++] = *p++; + *q++=Base64Code[((buf2[0] >> 2) & 0x3f)]; + *q++=Base64Code[(((buf2[0] & 0x03) << 4) | ((buf2[1] >> 4) & 0x0f))]; + if (i<2) + *q++='='; + else + *q++=Base64Code[(((buf2[1] & 0x0f) << 2) | ((buf2[2] >> 6) & 0x03))]; + if (i<3) + *q++='='; + else + *q++=Base64Code[(buf2[2] & 0x3f)]; + } + *q = '\0'; + + return buf; +} + diff --git a/lib/mkprod.awk b/lib/mkprod.awk new file mode 100644 index 00000000..0ec556c4 --- /dev/null +++ b/lib/mkprod.awk @@ -0,0 +1,15 @@ +BEGIN { + print "#include \"libs.h\"" + print "#include \"structs.h\"" + print "#include \"common.h\"" + print "" + print "struct _ftscprod ftscprod[] = {" + } +/^[^;]/ { + if ($2 != "DROPPED") + print " {0x" $1 ",\(char \*\)\"" $2 "\"}," + } +END { + print " {0xff,(char*)0L}" + print "};" + } diff --git a/lib/msg.c b/lib/msg.c new file mode 100644 index 00000000..eb68ade5 --- /dev/null +++ b/lib/msg.c @@ -0,0 +1,321 @@ +/***************************************************************************** + * + * File ..................: msg.c + * Purpose ...............: Global message base functions + * Last modification date : 20-Dec-1998 + * + ***************************************************************************** + * Copyright (C) 1997-1998 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "msgtext.h" +#include "msg.h" +#include "jammsg.h" + + + +char *strlwr (char *s) +{ + char *p = s; + + while (*p != '\0') { + *p = (char)tolower (*p); + p++; + } + + return (s); +} + + + +char *strupr (char *s) +{ + char *p = s; + + while (*p != '\0') { + *p = (char)toupper (*p); + p++; + } + + return (s); +} + + + +long filelength(int fd) +{ + long retval = -1L; + struct stat buf; + + if (fd != -1) { + fstat(fd, &buf); + retval = buf.st_size; + } + + return (retval); +} + + + +long tell(int fd) +{ + long retval = -1L; + + if (fd != -1) + retval = lseek(fd, 0L, SEEK_CUR); + + return retval; +} + + + +/* + * Add a message + */ +int Msg_AddMsg() +{ + if (!MsgBase.Locked) + return FALSE; + + return JAM_AddMsg(); +} + + + +/* + * Close current message base + */ +void Msg_Close(void) +{ + if (MsgBase.Locked) + Msg_UnLock(); + + JAM_Close(); + MsgText_Clear(); + MsgBase.Open = FALSE; +} + + + +/* + * Delete message number + */ +int Msg_Delete(unsigned long ulMsg) +{ + if (!MsgBase.Locked) + return FALSE; + + return JAM_Delete(ulMsg); +} + + + +int Msg_GetLastRead(lastread *LR) +{ + return JAM_GetLastRead(LR); +} + + + +/* + * Get highest message number + */ +unsigned long Msg_Highest(void) +{ + return MsgBase.Highest = JAM_Highest(); +} + + + +int Msg_Lock(unsigned long ulTimeout) +{ + return MsgBase.Locked = JAM_Lock(ulTimeout); +} + + + +/* + * Get lowest message number + */ +unsigned long Msg_Lowest(void) +{ + return MsgBase.Lowest = JAM_Lowest(); +} + + + +void Msg_New(void) +{ + JAM_New(); +} + + + +int Msg_NewLastRead(lastread LR) +{ + return JAM_NewLastRead(LR); +} + + + +int Msg_Next(unsigned long * ulMsg) +{ + return JAM_Next(ulMsg); +} + + + +/* + * Return number of messages + */ +unsigned long Msg_Number(void) +{ + return MsgBase.Total = JAM_Number(); +} + + + +/* + * Open specified message base + */ +int Msg_Open(char *Base) +{ + int RetVal = FALSE; + + if (MsgBase.Open) { + if (strcmp(MsgBase.Path, Base) != 0) + Msg_Close(); + else + return TRUE; + } + + RetVal = JAM_Open(Base); + + MsgBase.Open = RetVal; + + strcpy(MsgBase.Path, Base); + return RetVal; +} + + + +/* + * Pack deleted messages from the message base. + */ +void Msg_Pack(void) +{ + if (!MsgBase.Locked) + return; + + JAM_Pack(); +} + + + +int Msg_Previous (unsigned long * ulMsg) +{ + return JAM_Previous(ulMsg); +} + + + +int Msg_ReadHeader (unsigned long ulMsg) +{ + return JAM_ReadHeader(ulMsg); +} + + + +/* + * Read message + */ +int Msg_Read(unsigned long ulMsg, int nWidth) +{ + return JAM_Read(ulMsg, nWidth); +} + + + +int Msg_SetLastRead(lastread LR) +{ + if (!MsgBase.Locked) + return FALSE; + + return JAM_SetLastRead(LR); +} + + + +/* + * Unlock the message base + */ +void Msg_UnLock(void) +{ + JAM_UnLock(); + MsgBase.Locked = FALSE; +} + + + +/* + * Write message header + */ +int Msg_WriteHeader (unsigned long ulMsg) +{ + if (!MsgBase.Locked) + return FALSE; + + return JAM_WriteHeader(ulMsg); +} + + + +/* + * Write messagetext from file, strip linefeeds. + */ +void Msg_Write(FILE *fp) +{ + char *Buf; + int i; + + Buf = calloc(2049, sizeof(char)); + while ((fgets(Buf, 2048, fp)) != NULL) { + + for (i = 0; i < strlen(Buf); i++) { + if (*(Buf + i) == '\0') + break; + if (*(Buf + i) == '\n') + *(Buf + i) = '\0'; + if (*(Buf + i) == '\r') + *(Buf + i) = '\0'; + } + + MsgText_Add2(Buf); + } + + free(Buf); +} + + diff --git a/lib/msg.h b/lib/msg.h new file mode 100644 index 00000000..f5c4a0bb --- /dev/null +++ b/lib/msg.h @@ -0,0 +1,140 @@ +#ifndef _MSG_H +#define _MSG_H + +#define MAX_LINE_LENGTH 512 + + +/* + * Global message buffer + */ +typedef struct _msgbuf { + unsigned long Id; + unsigned long Current; + char From[101]; /* From name */ + char To[101]; /* To name */ + char Subject[101]; /* Message subject */ + unsigned Local : 1; /* Message is local */ + unsigned Intransit : 1; /* Message is in transit */ + unsigned Private : 1; /* Message is private */ + unsigned Received : 1; /* Message is received */ + unsigned Sent : 1; /* Message is sent */ + unsigned KillSent : 1; /* Kill after sent */ + unsigned ArchiveSent : 1; /* Archive after sent */ + unsigned Hold : 1; /* Hold message */ + unsigned Crash : 1; /* Crash flag */ + unsigned Immediate : 1; /* Immediate mail */ + unsigned Direct : 1; /* Direct flag */ + unsigned Gate : 1; /* Send via gateway */ + unsigned FileRequest : 1; /* File request */ + unsigned FileAttach : 1; /* File attached */ + unsigned TruncFile : 1; /* Trunc file after sent */ + unsigned KillFile : 1; /* Kill file after sent */ + unsigned ReceiptRequest : 1; /* Return receipt request */ + unsigned ConfirmRequest : 1; /* Confirm receipt request */ + unsigned Orphan : 1; /* Orphaned message */ + unsigned Encrypt : 1; /* Encrypted message */ + unsigned Compressed : 1; /* Compressed message */ + unsigned Escaped : 1; /* Msg is 7bit ASCII */ + unsigned ForcePU : 1; /* Force PickUp */ + unsigned Localmail : 1; /* Local use only */ + unsigned Echomail : 1; /* Echomail flag */ + unsigned Netmail : 1; /* Netmail flag */ + unsigned News : 1; /* News article */ + unsigned Email : 1; /* e-mail message */ + unsigned Nntp : 1; /* Offer to NNTP server */ + unsigned Nodisplay : 1; /* No display to user */ + unsigned Locked : 1; /* Locked, no edit allowed */ + unsigned Deleted : 1; /* Msg is deleted */ + time_t Written; /* Date message is written */ + time_t Arrived; /* Date message arrived */ + time_t Read; /* Date message is received */ + char FromAddress[101]; /* From address */ + char ToAddress[101]; /* To address */ + unsigned long Reply; /* Message is reply to */ + unsigned long Original; /* Original message */ + unsigned long MsgIdCRC; /* Message Id CRC */ + unsigned long ReplyCRC; /* Reply CRC */ + char Msgid[81]; /* Msgid string */ + char Replyid[81]; /* Replyid string */ + char ReplyAddr[81]; /* Gated Reply Address */ + char ReplyTo[81]; /* Gated Reply To */ + long Size; /* Message size during write*/ +} msgbuf; + + + +/* + * Globale message area buffer + */ +typedef struct _msgbase { + char Path[PATH_MAX]; /* Path to message base */ + unsigned Open : 1; /* If base is open */ + unsigned Locked : 1; /* If base is locked */ + unsigned long LastNum; /* Lastread message number */ + unsigned long Lowest; /* Lowest message number */ + unsigned long Highest; /* Highest message number */ + unsigned long Total; /* Total number of msgs */ +} msgbase; + + + +/* + * LastRead structure + */ +typedef struct _lastread { + unsigned long UserCRC; /* CRC32 lowercase username */ + unsigned long UserID; /* Unique user-id */ + unsigned long LastReadMsg; /* Last Read message number */ + unsigned long HighReadMsg; /* Highes read message */ +} lastread; + + + +/* + * Global variables + */ +msgbuf Msg; /* Message buffer */ +msgbase MsgBase; /* Message Base buffer */ +msgbase EmailBase; /* Email Base buffer */ +lastread LastRead; /* LastRead pointer record */ +char szWrp[MAX_LINE_LENGTH + 1]; + + + +/* + * Common function prototypes. + */ +char *strlwr(char *); +char *strupr(char *); +long filelength(int); +long tell(int); + + + +/* + * Message Base Prototypes + */ +int Msg_AddMsg(void); +void Msg_Close(void); +int Msg_Delete(unsigned long); +int Msg_GetLastRead(lastread *); +unsigned long Msg_Highest(void); +int Msg_Lock(unsigned long); +unsigned long Msg_Lowest(void); +void Msg_New(void); +int Msg_NewLastRead(lastread); +int Msg_Next(unsigned long *); +unsigned long Msg_Number(void); +int Msg_Open(char *); +void Msg_Pack(void); +int Msg_Previous(unsigned long *); +int Msg_ReadHeader(unsigned long); +int Msg_Read(unsigned long, int); +int Msg_SetLastRead(lastread); +void Msg_UnLock(void); +int Msg_WriteHeader(unsigned long); +void Msg_Write(FILE *); + + +#endif + diff --git a/lib/msgflags.c b/lib/msgflags.c new file mode 100644 index 00000000..01b047fb --- /dev/null +++ b/lib/msgflags.c @@ -0,0 +1,144 @@ +/***************************************************************************** + * + * File ..................: msgflags.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 06-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +static char *flnm[] = { + (char *)"PVT",(char *)"CRS",(char *)"RCV",(char *)"SNT", + (char *)"ATT",(char *)"TRN",(char *)"ORP",(char *)"K/S", + (char *)"LOC",(char *)"HLD",(char *)"RSV",(char *)"FRQ", + (char *)"RRQ",(char *)"RRC",(char *)"ARQ",(char *)"FUP" +}; + + + +int flagset(char *s) +{ + char *buf,*p; + int i; + int fl=0; + + Syslog('M', "setting flags from string \"%s\"",MBSE_SS(s)); + buf=xstrcpy(s); + for (p=strtok(buf," ,\t\n"); p; p=strtok(NULL," ,\t\n")) { + for (i=0;i<16;i++) + if (!strcasecmp(p,flnm[i])) { + Syslog('M', "setting flag bit %d for \"%s\"", i,MBSE_SS(p)); + fl |= (1 << i); + } + } + free(buf); + Syslog('M', "set flags 0x%04x",fl); + return fl; +} + + + +char *compose_flags(int flags, char *fkludge) +{ + int i; + char *buf = NULL, *p; + + if ((fkludge == NULL) && (!flags)) + return buf; + + Syslog('M', "composing flag string from binary 0x%04x and string \"%s\"", flags,MBSE_SS(fkludge)); + if (fkludge) { + if (!isspace(fkludge[0])) + buf=xstrcpy((char *)" "); + buf=xstrcat(buf,fkludge); + p=buf+strlen(buf)-1; + while (isspace(*p)) + *p--='\0'; + } + + for (i = 0; i < 16; i++) + if ((flags & (1 << i)) && (!flag_on(flnm[i],buf))) { + buf=xstrcat(buf,(char *)" "); + buf=xstrcat(buf,flnm[i]); + Syslog('m', "adding \"%s\"",flnm[i]); + } + Syslog('M', "resulting string is \"%s\"",buf); + return buf; +} + + + +char *strip_flags(char *flags) +{ + char *p,*q=NULL,*tok; + int canonic,i; + + if (flags == NULL) + return NULL; + + Syslog('M', "stripping official flags from \"%s\"",MBSE_SS(flags)); + p=xstrcpy(flags); + for (tok=strtok(flags,", \t\n");tok;tok=strtok(NULL,", \t\n")) { + canonic=0; + for (i=0;i<16;i++) + if (strcasecmp(tok,flnm[i]) == 0) + canonic=1; + if (!canonic) { + q=xstrcat(q,(char *)" "); + q=xstrcat(q,tok); + } + } + free(p); + Syslog('M', "stripped string is \"%s\"",q); + return q; +} + + + +int flag_on(char *flag, char *flags) +{ + char *p,*tok; + int up=0; + + Syslog('M', "checking flag \"%s\" in string \"%s\"",MBSE_SS(flag),MBSE_SS(flags)); + if (flags == NULL) + return 0; + p=xstrcpy(flags); + for (tok = strtok(p, ", \t\n"); tok; tok = strtok(NULL, ", \t\n")) { + if (strcasecmp(flag, tok) == 0) + up = 1; + } + free(p); + Syslog('M', "flag%s present",up?"":" not"); + return up; +} + + diff --git a/lib/msgtext.c b/lib/msgtext.c new file mode 100644 index 00000000..67f68024 --- /dev/null +++ b/lib/msgtext.c @@ -0,0 +1,335 @@ +/***************************************************************************** + * + * File ..................: msgtext.c + * Purpose ...............: Message text memory storage. + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "msgtext.h" +#include "msg.h" + + +LDATA *List; + + + + +unsigned short MsgText_Add1(void * lpData) +{ + unsigned short RetVal = 0; + LDATA *New; + + if ((New = (LDATA *)malloc (sizeof (LDATA))) != NULL) { + memset (New, 0, sizeof (LDATA)); + New->Value = (void *)lpData; + + if (List != NULL) { + while (List->Next != NULL) + List = List->Next; + + New->Previous = List; + New->Next = List->Next; + if (New->Next != NULL) + New->Next->Previous = New; + List->Next = New; + } + + Elements++; + Msg.Size += sizeof((void *)lpData); + List = New; + RetVal = 1; + } + + return (RetVal); +} + + + +unsigned short MsgText_Add2(char * lpData) +{ + return (MsgText_Add3((void *)lpData, (unsigned short)(strlen (lpData) + 1))); +} + + + +unsigned short MsgText_Add3(void * lpData, unsigned short usSize) +{ + unsigned short RetVal = 0; + LDATA *New; + + if ((New = (LDATA *)malloc(sizeof (LDATA) + usSize)) != NULL) { + memset (New, 0, sizeof (LDATA) + usSize); + memcpy (New->Data, lpData, usSize); + New->Value = (void *)New->Data; + + if (List != NULL) { + while (List->Next != NULL) + List = List->Next; + + New->Previous = List; + New->Next = List->Next; + if (New->Next != NULL) + New->Next->Previous = New; + List->Next = New; + } + + Elements++; + Msg.Size += usSize; + List = New; + RetVal = 1; + } + + return (RetVal); +} + + + +void MsgText_Clear (void) +{ + while (List != NULL) + MsgText_Remove(); + Elements = 0; +} + + + +void *MsgText_First (void) +{ + void *RetVal = NULL; + + if (List != NULL) { + while (List->Previous != NULL) + List = List->Previous; + RetVal = List->Value; + } + + return RetVal; +} + + + +unsigned short MsgText_Insert1(void * lpData) +{ + unsigned short RetVal = 0; + LDATA *New; + + if ((New = (LDATA *)malloc (sizeof (LDATA))) != NULL) { + memset (New, 0, sizeof (LDATA)); + New->Value = (void *)lpData; + + if (List != NULL) { + New->Previous = List; + New->Next = List->Next; + if (New->Next != NULL) + New->Next->Previous = New; + List->Next = New; + } + + Elements++; + List = New; + RetVal = 1; + } + + return (RetVal); +} + + + +unsigned short MsgText_Insert2(char * lpData) +{ + return (MsgText_Insert3(lpData, (unsigned short)(strlen (lpData) + 1))); +} + + + +unsigned short MsgText_Insert3(void * lpData, unsigned short usSize) +{ + unsigned short RetVal = 0; + LDATA *New; + + if ((New = (LDATA *)malloc (sizeof (LDATA) + usSize)) != NULL) { + memset (New, 0, sizeof (LDATA) + usSize); + memcpy (New->Data, lpData, usSize); + New->Value = (void *)New->Data; + + if (List != NULL) { + New->Previous = List; + New->Next = List->Next; + if (New->Next != NULL) + New->Next->Previous = New; + List->Next = New; + } + + Elements++; + List = New; + RetVal = 1; + } + + return (RetVal); +} + + + +void * MsgText_Last(void) +{ + void * RetVal = NULL; + + if (List != NULL) { + while (List->Next != NULL) + List = List->Next; + RetVal = List->Value; + } + + return (RetVal); +} + + + +void * MsgText_Next (void) +{ + void * RetVal = NULL; + + if (List != NULL) { + if (List->Next != NULL) { + List = List->Next; + RetVal = List->Value; + } + } + + return (RetVal); +} + + + +void * MsgText_Previous (void) +{ + void * RetVal = NULL; + + if (List != NULL) { + if (List->Previous != NULL) { + List = List->Previous; + RetVal = List->Value; + } + } + + return (RetVal); +} + + + +void MsgText_Remove(void) +{ + LDATA *Temp; + + if (List != NULL) { + if (List->Previous != NULL) + List->Previous->Next = List->Next; + if (List->Next != NULL) + List->Next->Previous = List->Previous; + Temp = List; + if (List->Next != NULL) + List = List->Next; + else if (List->Previous != NULL) + List = List->Previous; + else + List = NULL; + free (Temp); + Elements--; + } +} + + + +unsigned short MsgText_Replace1(void * lpData) +{ + unsigned short RetVal = 0; + LDATA *New; + + if (List != NULL) { + if ((New = (LDATA *)malloc (sizeof (LDATA))) != NULL) { + memset (New, 0, sizeof (LDATA)); + New->Value = (void *)lpData; + New->Next = List->Next; + New->Previous = List->Previous; + + if (New->Next != NULL) + New->Next->Previous = New; + if (New->Previous != NULL) + New->Previous->Next = New; + + free (List); + List = New; + RetVal = 1; + } + } + + return (RetVal); +} + + + +unsigned short MsgText_Replace2(char * lpData) +{ + return (MsgText_Replace3(lpData, (unsigned short)(strlen (lpData) + 1))); +} + + + +unsigned short MsgText_Replace3(void * lpData, unsigned short usSize) +{ + unsigned short RetVal = 0; + LDATA *New; + + if (List != NULL) { + if ((New = (LDATA *)malloc (sizeof (LDATA) + usSize)) != NULL) { + memset (New, 0, sizeof (LDATA) + usSize); + memcpy (New->Data, lpData, usSize); + New->Value = (void *)New->Data; + New->Next = List->Next; + New->Previous = List->Previous; + + if (New->Next != NULL) + New->Next->Previous = New; + if (New->Previous != NULL) + New->Previous->Next = New; + free (List); + List = New; + RetVal = 1; + } + } + + return (RetVal); +} + + + +void * MsgText_Value(void) +{ + return ((List == NULL) ? NULL : List->Value); +} + diff --git a/lib/msgtext.h b/lib/msgtext.h new file mode 100644 index 00000000..d82adc93 --- /dev/null +++ b/lib/msgtext.h @@ -0,0 +1,34 @@ +#ifndef _MSGTEXT_H +#define _MSGTEXT_H + +typedef struct _lData { + struct _lData *Previous; + struct _lData *Next; + void * Value; + char Data[1]; +} LDATA; + + + +unsigned short Elements; + +unsigned short MsgText_Add1(void * lpData); +unsigned short MsgText_Add2(char * lpData); +unsigned short MsgText_Add3(void * lpData, unsigned short usSize); +void MsgText_Clear(void); +void * MsgText_First(void); +unsigned short MsgText_Insert1(void * lpData); +unsigned short MsgText_Insert2(char * lpData); +unsigned short MsgText_Insert3(void * lpData, unsigned short usSize); +void * MsgText_Last(void); +void * MsgText_Next(void); +void * MsgText_Previous(void); +void MsgText_Remove(void); +unsigned short MsgText_Replace1(void * lpData); +unsigned short MsgText_Replace2(char * lpData); +unsigned short MsgText_Replace3(void * lpData, unsigned short usSize); +void * MsgText_Value(void); + + +#endif + diff --git a/lib/nntp.c b/lib/nntp.c new file mode 100644 index 00000000..334f6e21 --- /dev/null +++ b/lib/nntp.c @@ -0,0 +1,294 @@ +/***************************************************************************** + * + * File ..................: nntp.c + * Purpose ...............: MBSE BBS Internet Library + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "mbinet.h" + + +static int nntpsock = -1; /* TCP/IP socket */ +struct hostent *nhp; /* Host info remote */ +struct servent *nsp; /* Service information */ +struct sockaddr_in nntp_loc; /* For local socket address */ +struct sockaddr_in nntp_rem; /* For remote socket address */ + + +int nntp_auth(void); + + +int nntp_connect(void) +{ + int addrlen; + char *p; + + if (nntpsock != -1) + return nntpsock; + + if (!strlen(CFG.nntpnode)) { + WriteError("NNTP: host not configured"); + return -1; + } + + Syslog('+', "NNTP: connecting host: %s", CFG.nntpnode); + memset(&nntp_loc, 0, sizeof(struct sockaddr_in)); + memset(&nntp_rem, 0, sizeof(struct sockaddr_in)); + + nntp_rem.sin_family = AF_INET; + + if ((nhp = gethostbyname(CFG.nntpnode)) == NULL) { + WriteError("$NNTP: can't find host %s", CFG.nntpnode); + return -1; + } + + nntp_rem.sin_addr.s_addr = ((struct in_addr *)(nhp->h_addr))->s_addr; + + if ((nsp = getservbyname("nntp", "tcp")) == NULL) { + WriteError("$NNTP: can't find service port for nntp/tcp"); + return -1; + } + nntp_rem.sin_port = nsp->s_port; + + if ((nntpsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + WriteError("$NNTP: unable to create tcp socket"); + return -1; + } + + if (connect(nntpsock, (struct sockaddr *)&nntp_rem, sizeof(struct sockaddr_in)) == -1) { + WriteError("$NNTP: cannot connect tcp socket"); + return -1; + } + + addrlen = sizeof(struct sockaddr_in); + + if (getsockname(nntpsock, (struct sockaddr *)&nntp_loc, &addrlen) == -1) { + WriteError("$NNTP: unable to read socket address"); + return -1; + } + + p = nntp_receive(); + if (strlen(p) == 0) { + WriteError("NNTP: no response"); + nntp_close(); + return -1; + } + Syslog('+', "NNTP: %s", p); + + if (strncmp(p, "480", 3) == 0) { + /* + * Must login with username and password + */ + if (nntp_auth() == FALSE) { + WriteError("Authorisation failure"); + nntp_close(); + return -1; + } + } else if (strncmp(p, "200", 3)) { + WriteError("NNTP: bad response: %s", p); + nntp_close(); + return -1; + } + + if (CFG.modereader) { + Syslog('+', "NNTP: setting mode reader"); + nntp_send((char *)"MODE READER\r\n"); + p = nntp_receive(); + Syslog('+', "NNTP: %s", p); + if (strncmp(p, "480", 3) == 0) { + /* + * Must login with username and password + */ + Syslog('+', "NNTP: %s", p); + if (nntp_auth() == FALSE) { + WriteError("NNTP: authorisation failure"); + nntp_close(); + return -1; + } + } else if (strncmp(p, "200", 3)) { + WriteError("NNTP: bad response: %s", p); + nntp_close(); + return -1; + } + } + return nntpsock; +} + + + +int nntp_send(char *buf) +{ + if (nntpsock == -1) + return -1; + + if (send(nntpsock, buf, strlen(buf), 0) != strlen(buf)) { + WriteError("$NNTP: socket send failed"); + if (errno == ENOTCONN || errno == EPIPE) { + WriteError("NNTP: closing local side"); + nntpsock = -1; + } + return -1; + } + return 0; +} + + + +/* + * Return empty buffer if something went wrong, else the complete + * dataline is returned + */ +char *nntp_receive(void) +{ + static char buf[SS_BUFSIZE]; + int i = 0, j; + + if (nntpsock == -1) + return NULL; + + memset((char *)&buf, 0, SS_BUFSIZE); + while (TRUE) { + j = recv(nntpsock, &buf[i], 1, 0); + if (j == -1) { + WriteError("$NNTP: error reading socket"); + memset((char *)&buf, 0, SS_BUFSIZE); + if (errno == ENOTCONN || errno == EPIPE) { + WriteError("NNTP: closing local side"); + nntpsock = -1; + } + return buf; + } + if (buf[i] == '\n') + break; + i += j; + } + + for (i = 0; i < strlen(buf); i++) { + if (buf[i] == '\n') + buf[i] = '\0'; + if (buf[i] == '\r') + buf[i] = '\0'; + } + + return buf; +} + + + +int nntp_close(void) +{ + if (nntpsock == -1) + return 0; + + nntp_cmd((char *)"QUIT\r\n", 205); + + if (shutdown(nntpsock, 1) == -1) { + WriteError("$NNTP: can't close socket"); + return -1; + } + + nntpsock = -1; + Syslog('+', "NNTP: closed"); + return 0; +} + + + +/* + * Send NNTP command, check response code. + * If the code not matches, the value is returned, else zer. + */ +int nntp_cmd(char *cmd, int resp) +{ + char *p, rsp[6]; + + if (nntp_send(cmd) == -1) + return -1; + + sprintf(rsp, "%d", resp); + p = nntp_receive(); + + if (strncmp(p, "480", 3) == 0) { + /* + * Must login with username and password + */ + Syslog('+', "NNTP: %s", p); + if (nntp_auth() == FALSE) { + WriteError("Authorisation failure"); + nntp_close(); + return -1; + } + /* + * Now send command again, we are now authorized. + */ + if (nntp_send(cmd) == -1) + return -1; + p = nntp_receive(); + } + + if (strncmp(p, rsp, strlen(rsp))) { + WriteError("NNTP> %s", cmd); + WriteError("NNTP< %s", p); + memset(&resp, 0, sizeof(rsp)); + strncpy(rsp, p, 3); + return atoi(rsp); + } + return 0; +} + + + +int nntp_auth(void) +{ + char *cmd; + + if (!(strlen(CFG.nntpuser) && strlen(CFG.nntppass))) { + WriteError("NNTP: password required but not configured"); + return FALSE; + } + cmd = calloc(128, sizeof(char)); + + sprintf(cmd, "AUTHINFO USER %s\r\n", CFG.nntpuser); + if (nntp_cmd(cmd, 381)) + return FALSE; + + sprintf(cmd, "AUTHINFO PASS %s\r\n", CFG.nntppass); + if (nntp_cmd(cmd, 281) == 0) { + free(cmd); + Syslog('+', "NNTP: logged in"); + return TRUE; + } else { + free(cmd); + return FALSE; + } +} + + diff --git a/lib/nodelist.c b/lib/nodelist.c new file mode 100644 index 00000000..4aa5b9e3 --- /dev/null +++ b/lib/nodelist.c @@ -0,0 +1,607 @@ +/***************************************************************************** + * + * File ..................: nodelist.c + * Purpose ...............: Read nodelists information + * Last modification date : 06-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +#define NULLDOMAIN "nulldomain" + + +struct _pkey pkey[] = { + {(char *)"Down", NL_NODE, NL_DOWN}, + {(char *)"Hold", NL_NODE, NL_HOLD}, + {(char *)"Region", NL_REGION, NL_REGION}, + {(char *)"Host", NL_HOST, NL_HOST}, + {(char *)"Hub", NL_HUB, NL_HUB}, + {(char *)"Point", NL_POINT, NL_POINT}, + {(char *)"Pvt", NL_NODE, NL_NODE}, + {NULL, 0, 0} +}; + + + +struct _okey okey[] = { + {(char *)"CM", OL_CM}, + {(char *)"MO", OL_MO}, + {(char *)"LO", OL_LO}, + {(char *)"MN", OL_MN}, + {NULL, 0} +}; + +struct _fkey fkey[] = { + {(char *)"V22", NL_V22}, + {(char *)"V29", NL_V29}, + {(char *)"V32", NL_V32}, + {(char *)"V32B",NL_V32B | NL_V32}, + {(char *)"V34", NL_V34}, + {(char *)"V42", NL_V42 | NL_MNP}, + {(char *)"V42B",NL_V42B | NL_V42 | NL_MNP}, + {(char *)"MNP", NL_MNP}, + {(char *)"H96", NL_H96}, + {(char *)"HST", NL_HST | NL_MNP}, + {(char *)"H14", NL_H14 | NL_HST | NL_MNP}, + {(char *)"H16", NL_H16 | NL_H14 | NL_HST | NL_MNP | NL_V42 | NL_V42B}, + {(char *)"MAX", NL_MAX}, + {(char *)"PEP", NL_PEP}, + {(char *)"CSP", NL_CSP}, + {(char *)"V32T",NL_V32T | NL_V32B | NL_V32}, + {(char *)"VFC", NL_VFC}, + {(char *)"ZYX", NL_ZYX | NL_V32B | NL_V32 | NL_V42B | NL_V42 | NL_MNP}, + {(char *)"X2C", NL_X2C | NL_X2S | NL_V34}, + {(char *)"X2S", NL_X2S | NL_V34}, + {(char *)"V90C",NL_V90C | NL_V90S | NL_V34}, + {(char *)"V90S",NL_V90S | NL_V34}, + {(char *)"Z19", NL_Z19 | NL_V32B | NL_V32 | NL_V42B | NL_V42 | NL_MNP | NL_ZYX}, + {NULL, 0} +}; + +struct _xkey xkey [] = { + {(char *)"XA", RQ_XA}, + {(char *)"XB", RQ_XB}, + {(char *)"XC", RQ_XC}, + {(char *)"XP", RQ_XP}, + {(char *)"XR", RQ_XR}, + {(char *)"XW", RQ_XW}, + {(char *)"XX", RQ_XX}, + {NULL, 0} +}; + +struct _dkey dkey [] = { + {(char *)"V110L", ND_V110L}, + {(char *)"V110H", ND_V110H}, + {(char *)"V120L", ND_V120L}, + {(char *)"V120H", ND_V120H}, + {(char *)"X75", ND_X75}, + {NULL, 0} +}; + +struct _ikey ikey [] = { + {(char *)"IBN", IP_IBN}, + {(char *)"IFC", IP_IFC}, + {(char *)"ITN", IP_ITN}, + {(char *)"IVM", IP_IVM}, + {(char *)"IP", IP_IP}, + {(char *)"IFT", IP_IFT}, + {NULL, 0} +}; + + + +int initnl(void) +{ + int rc = 0; + FILE *dbf, *fp; + char *filexnm, *path; + struct _nlfil fdx; + + filexnm = xstrcpy(CFG.nodelists); + filexnm = xstrcat(filexnm,(char *)"/node.files"); + + if ((dbf = fopen(filexnm, "r")) == NULL) { + WriteError("$Can't open %s", filexnm); + rc = 101; + } else { + path = calloc(128, sizeof(char)); + + while (fread(&fdx, sizeof(fdx), 1, dbf) == 1) { + sprintf(path, "%s/%s", CFG.nodelists, fdx.filename); + if ((fp = fopen(path, "r")) == NULL) { + WriteError("$Can't open %s", path); + rc = 101; + } else { + fclose(fp); + } + } + + fclose(dbf); + free(path); + } + + free(filexnm); + return rc; +} + + + +int comp_node(struct _nlidx, struct _ixentry); +int comp_node(struct _nlidx fap1, struct _ixentry fap2) +{ + if (fap1.zone != fap2.zone) + return (fap1.zone - fap2.zone); + else if (fap1.net != fap2.net) + return (fap1.net - fap2.net); + else if (fap1.node != fap2.node) + return (fap1.node - fap2.node); + else + return (fap1.point - fap2.point); +} + + + +node *getnlent(faddr *addr) +{ + FILE *fp; + static node nodebuf; + static char buf[256], *p, *q; + struct _ixentry xaddr; + int i, j, Found = FALSE; + int ixflag, stdflag; + char *mydomain, *path; + struct _nlfil fdx; + struct _nlidx ndx; + long lowest, highest, current; + + Syslog('s', "getnlent: %s", ascfnode(addr,0xff)); + + mydomain = xstrcpy(CFG.aka[0].domain); + if (mydomain == NULL) + mydomain = (char *)NULLDOMAIN; + + nodebuf.addr.domain = NULL; + nodebuf.addr.zone = 0; + nodebuf.addr.net = 0; + nodebuf.addr.node = 0; + nodebuf.addr.point = 0; + nodebuf.addr.name = NULL; + nodebuf.upnet = 0; + nodebuf.upnode = 0; + nodebuf.region = 0; + nodebuf.type = 0; + nodebuf.pflag = 0; + nodebuf.name = NULL; + nodebuf.location = NULL; + nodebuf.sysop = NULL; + nodebuf.phone = NULL; + nodebuf.speed = 0; + nodebuf.mflags = 0L; + nodebuf.oflags = 0L; + nodebuf.xflags = 0L; + nodebuf.iflags = 0L; + nodebuf.dflags = 0L; + nodebuf.uflags[0] = NULL; + + if (addr == NULL) + goto retdummy; + + if (addr->zone == 0) + addr->zone = CFG.aka[0].zone; + xaddr.zone = addr->zone; + nodebuf.addr.zone = addr->zone; + xaddr.net = addr->net; + nodebuf.addr.net = addr->net; + xaddr.node = addr->node; + nodebuf.addr.node = addr->node; + xaddr.point = addr->point; + nodebuf.addr.point = addr->point; + + if (initnl()) + goto retdummy; + + /* + * First, lookup node in index. NOTE -- NOT 5D YET + */ + path = calloc(128, sizeof(char)); + sprintf(path, "%s/%s", CFG.nodelists, "node.index"); + if ((fp = fopen(path, "r")) == NULL) { + WriteError("$Can't open %s", path); + free(path); + goto retdummy; + } + + fseek(fp, 0, SEEK_END); + highest = ftell(fp) / sizeof(ndx); + lowest = 0; + + while (TRUE) { + current = ((highest - lowest) / 2) + lowest; + fseek(fp, current * sizeof(ndx), SEEK_SET); + if (fread(&ndx, sizeof(ndx), 1, fp) != 1) + break; + + if (comp_node(ndx, xaddr) == 0) { + Found = TRUE; + break; + } + if (comp_node(ndx, xaddr) < 0) + lowest = current; + else + highest = current; + if ((highest - lowest) <= 1) + break; + } + + fclose(fp); + + if (!Found) { + free(path); + goto retdummy; + } + + sprintf(path, "%s/%s", CFG.nodelists, "node.files"); + if ((fp = fopen(path, "r")) == NULL) { + WriteError("$Can't open %s", path); + free(path); + goto retdummy; + } + + /* + * Get filename from node.files + */ + for (i = 0; i < (ndx.fileno +1); i++) + fread(&fdx, sizeof(fdx), 1, fp); + fclose(fp); + + /* CHECK DOMAIN HERE */ + + /* + * Open and read in real nodelist + */ + sprintf(path, "%s/%s", CFG.nodelists, fdx.filename); + if ((fp = fopen(path, "r")) == NULL) { + WriteError("$Can't open %s", path); + free(path); + goto retdummy; + } + free(path); + + if (fseek(fp, ndx.offset, SEEK_SET) != 0) { + WriteError("$Seek failed for nodelist entry"); + fclose(fp); + goto retdummy; + } + + if (fgets(buf, sizeof(buf)-1, fp) == NULL) { + WriteError("$fgets failed for nodelist entry"); + fclose(fp); + goto retdummy; + } + fclose(fp); + + nodebuf.type = ndx.type; + nodebuf.pflag = ndx.pflag; + + if (*(p = buf + strlen(buf) -1) == '\n') + *p = '\0'; + if (*(p = buf + strlen(buf) -1) == '\r') + *p = '\0'; + for (p = buf; *p; p++) + if (*p == '_') + *p = ' '; + + p = buf; + + if ((q = strchr(p,','))) + *q++ = '\0'; + + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.name = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.location = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.sysop = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + if (strcasecmp(p, "-Unpublished-") == 0) + nodebuf.phone = NULL; + else + nodebuf.phone = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.speed = atoi(p); + + /* + * Process the nodelist flags. + */ + ixflag = 0; + stdflag = TRUE; + for (p = q; p; p = q) { + if ((q = strchr(p, ','))) + *q++ = '\0'; + if ((strncasecmp(p, "U", 1) == 0) && (strlen(p) == 1)) { + stdflag = FALSE; + } else { + /* + * Experimental: process authorized flags and + * User flags both as authorized. + */ + for (j = 0; fkey[j].key; j++) + if (strcasecmp(p, fkey[j].key) == 0) + nodebuf.mflags |= fkey[j].flag; + for (j = 0; okey[j].key; j++) + if (strcasecmp(p, okey[j].key) == 0) + nodebuf.oflags |= okey[j].flag; + for (j = 0; dkey[j].key; j++) + if (strcasecmp(p, dkey[j].key) == 0) + nodebuf.dflags |= dkey[j].flag; + for (j = 0; ikey[j].key; j++) + if (strncasecmp(p, ikey[j].key, strlen(ikey[j].key)) == 0) + nodebuf.iflags |= ikey[j].flag; + for (j = 0; xkey[j].key; j++) + if (strcasecmp(p, xkey[j].key) == 0) + nodebuf.xflags |= xkey[j].flag; + if (!stdflag) { + if (ixflag < MAXUFLAGS) { + nodebuf.uflags[ixflag++] = p; + if (ixflag < MAXUFLAGS) + nodebuf.uflags[ixflag] = NULL; + } + } + } + } + + nodebuf.addr.name = nodebuf.sysop; + nodebuf.addr.domain = xstrcpy(fdx.domain); + nodebuf.upnet = ndx.upnet; + nodebuf.upnode = ndx.upnode; + nodebuf.region = ndx.region; + if (addr->domain == NULL) + addr->domain = xstrcpy(nodebuf.addr.domain); + + Syslog('s', "getnlent: system %s, %s", nodebuf.name, nodebuf.location); + Syslog('s', "getnlent: sysop %s, %s", nodebuf.sysop, nodebuf.phone); + if (nodebuf.mflags) + Syslog('S', "getnlent: mflags 0x%08lx", nodebuf.mflags); + if (nodebuf.oflags) + Syslog('S', "getnlent: oflags 0x%08lx", nodebuf.oflags); + if (nodebuf.dflags) + Syslog('S', "getnlent: dflags 0x%08lx", nodebuf.dflags); + if (nodebuf.iflags) + Syslog('S', "getnlent: iflags 0x%08lx", nodebuf.iflags); + if (nodebuf.xflags) + Syslog('S', "getnlent: xflags 0x%08lx", nodebuf.xflags); + for (j = 0; nodebuf.uflags[j]; j++) + Syslog('S', "getnlent: uflag %s", nodebuf.uflags[j]); + + moflags(nodebuf.mflags); + diflags(nodebuf.dflags); + ipflags(nodebuf.iflags); + olflags(nodebuf.oflags); + rqflags(nodebuf.xflags); + free(mydomain); + + return &nodebuf; + +badsyntax: + WriteError("nodelist %d offset +%lu: bad syntax in line \"%s\"", + ndx.fileno, (unsigned long)ndx.offset, buf); + /* fallthrough */ + +retdummy: + memset(&nodebuf, 0, sizeof(nodebuf)); + nodebuf.pflag = NL_DUMMY; + nodebuf.name = (char *)"Unknown"; + nodebuf.location = (char *)"Nowhere"; + nodebuf.sysop = (char *)"Sysop"; + nodebuf.phone = NULL; + nodebuf.speed = 2400; + free(mydomain); + + return &nodebuf; +} + + + +void olflags(unsigned long flags) +{ + char *t; + + t = xstrcpy((char *)"Mailer flags :"); + if (flags & OL_CM) + t = xstrcat(t, (char *)" CM"); + if (flags & OL_MO) + t = xstrcat(t, (char *)" MO"); + if (flags & OL_LO) + t = xstrcat(t, (char *)" LO"); + if (flags & OL_MN) + t = xstrcat(t, (char *)" MN"); + Syslog('s', "%s", t); + free(t); +} + + + +void rqflags(unsigned long flags) +{ + char *t; + + t = xstrcpy((char *)"Request flags:"); + if (flags & RQ_RQ_BR) + t = xstrcat(t, (char *)" RQ_BR"); + if (flags & RQ_RQ_BU) + t = xstrcat(t, (char *)" RQ_BU"); + if (flags & RQ_RQ_WR) + t = xstrcat(t, (char *)" RQ_WR"); + if (flags & RQ_RQ_WU) + t = xstrcat(t, (char *)" RQ_WU"); + Syslog('s', "%s", t); + free(t); +} + + + +void moflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + t = xstrcpy((char *)"Modem flags :"); + if (flags & NL_V22) + t = xstrcat(t, (char *)" V22"); + if (flags & NL_V29) + t = xstrcat(t, (char *)" V29"); + if (flags & NL_V32) + t = xstrcat(t, (char *)" V32"); + if (flags & NL_V32B) + t = xstrcat(t, (char *)" V32B"); + if (flags & NL_V34) + t = xstrcat(t, (char *)" V34"); + if (flags & NL_V42) + t = xstrcat(t, (char *)" V42"); + if (flags & NL_V42B) + t = xstrcat(t, (char *)" V42B"); + if (flags & NL_MNP) + t = xstrcat(t, (char *)" MNP"); + if (flags & NL_H96) + t = xstrcat(t, (char *)" H96"); + if (flags & NL_HST) + t = xstrcat(t, (char *)" HST"); + if (flags & NL_H14) + t = xstrcat(t, (char *)" H14"); + if (flags & NL_H16) + t = xstrcat(t, (char *)" H16"); + if (flags & NL_MAX) + t = xstrcat(t, (char *)" MAX"); + if (flags & NL_PEP) + t = xstrcat(t, (char *)" PEP"); + if (flags & NL_CSP) + t = xstrcat(t, (char *)" CSP"); + if (flags & NL_V32T) + t = xstrcat(t, (char *)" V32T"); + if (flags & NL_VFC) + t = xstrcat(t, (char *)" VFC"); + if (flags & NL_ZYX) + t = xstrcat(t, (char *)" ZYX"); + if (flags & NL_X2C) + t = xstrcat(t, (char *)" X2C"); + if (flags & NL_X2S) + t = xstrcat(t, (char *)" X2S"); + if (flags & NL_V90C) + t = xstrcat(t, (char *)" V90C"); + if (flags & NL_V90S) + t = xstrcat(t, (char *)" V90S"); + Syslog('s', "%s", t); + free(t); +} + + + +void diflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + + t = xstrcpy((char *)"ISDN flags :"); + if (flags & ND_V110L) + t = xstrcat(t, (char *)" V110L"); + if (flags & ND_V110H) + t = xstrcat(t, (char *)" V110H"); + if (flags & ND_V120L) + t = xstrcat(t, (char *)" V120L"); + if (flags & ND_V120H) + t = xstrcat(t, (char *)" V120H"); + if (flags & ND_X75) + t = xstrcat(t, (char *)" X75"); + Syslog('s', "%s", t); + free(t); +} + + + +void ipflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + + t = xstrcpy((char *)"TCP/IP flags :"); + if (flags & IP_IBN) + t = xstrcat(t, (char *)" IBN"); + if (flags & IP_IFC) + t = xstrcat(t, (char *)" IFC"); + if (flags & IP_ITN) + t = xstrcat(t, (char *)" ITN"); + if (flags & IP_IVM) + t = xstrcat(t, (char *)" IVM"); + if (flags & IP_IP) + t = xstrcat(t, (char *)" IP"); + Syslog('s', "%s", t); + free(t); +} + + + diff --git a/lib/nodelock.c b/lib/nodelock.c new file mode 100644 index 00000000..cc6014b1 --- /dev/null +++ b/lib/nodelock.c @@ -0,0 +1,157 @@ +/***************************************************************************** + * + * File ..................: nodelock.c + * Purpose ...............: Node locking + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + + +int nodelock(faddr *addr) +{ + char *fn,*tfn,*p; + char tmp[16]; + FILE *fp; + pid_t pid,mypid; + int tmppid,sverr; + + fn = bsyname(addr); + tfn = xstrcpy(fn); + if ((p=strrchr(tfn,'/'))) + *++p='\0'; + mypid = getpid(); + sprintf(tmp, "aa%d", mypid); + tfn = xstrcat(tfn, tmp); + mkdirs(tfn); + + if ((fp = fopen(tfn,"w")) == NULL) { + WriteError("$Can't open tmp file for bsy lock (%s) \"%s\"",ascfnode(addr, 0x1f), tfn); + free(tfn); + return 1; + } + + fprintf(fp,"%10d\n", mypid); + fclose(fp); + chmod(tfn, 0444); + if (link(tfn, fn) == 0) { + unlink(tfn); + free(tfn); + return 0; + } else { + sverr=errno; + } + + if (sverr != EEXIST) { + WriteError("$Could not link \"%s\" to \"%s\"",tfn,fn); + WriteError("Locking %s failed", ascfnode(addr, 0x1f)); + unlink(tfn); + free(tfn); + return 1; + } + + if ((fp=fopen(fn,"r")) == NULL) { + WriteError("$Could not open existing lock file \"%s\"",fn); + WriteError("Locking %s failed", ascfnode(addr, 0x1f)); + unlink(tfn); + free(tfn); + return 1; + } + + /* + * Lock exists, check owner + */ + fscanf(fp, "%d", &tmppid); + pid = tmppid; + fclose(fp); + + /* + * If lock is our own lock, then it's ok and we are ready. + */ + if (getpid() == pid) { + unlink(tfn); + free(tfn); + return 0; + } + + if (kill(pid, 0) && (errno == ESRCH)) { + Syslog('+', "Found stale bsy file for %s, unlink", ascfnode(addr,0x1f)); + unlink(fn); + } else { + Syslog('+', "Node %s is locked by pid %d", ascfnode(addr, 0x1f), pid); + unlink(tfn); + free(tfn); + return 1; + } + + if (link(tfn,fn) == 0) { + unlink(tfn); + free(tfn); + return 0; + } else { + WriteError("$Could not link \"%s\" to \"%s\"",tfn,fn); + WriteError("Locking %s failed", ascfnode(addr, 0x1f)); + unlink(tfn); + free(tfn); + return 1; + } +} + + + +int nodeulock(faddr *addr) +{ + char *fn; + FILE *fp; + pid_t pid,mypid; + int tmppid; + + fn = bsyname(addr); + if ((fp = fopen(fn, "r")) == NULL) { + WriteError("$Can't open lock file (%s) \"%s\"", ascfnode(addr, 0x1f), fn); + return 1; + } + + fscanf(fp, "%d", &tmppid); + pid = tmppid; + fclose(fp); + mypid = getpid(); + + if (pid == mypid) { + unlink(fn); + return 0; + } else { + WriteError("Unlock (%s) file failed for process %u, we are %u", ascfnode(addr, 0x1f), pid,mypid); + return 1; + } +} + + diff --git a/lib/noderecord.c b/lib/noderecord.c new file mode 100644 index 00000000..1ad29705 --- /dev/null +++ b/lib/noderecord.c @@ -0,0 +1,58 @@ +/***************************************************************************** + * + * File ..................: noderecord.c + * Purpose ...............: Load noderecord + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "dbnode.h" +#include "common.h" + + + +int noderecord(faddr *addr) +{ + fidoaddr fa; + + memset(&fa, 0, sizeof(fa)); + fa.zone = addr->zone; + fa.net = addr->net; + fa.node = addr->node; + fa.point = addr->point; + + if (!(TestNode(fa))) + if (!SearchNode(fa)) { + return FALSE; + } + + return TRUE; +} + + diff --git a/lib/packet.c b/lib/packet.c new file mode 100644 index 00000000..3b79307c --- /dev/null +++ b/lib/packet.c @@ -0,0 +1,190 @@ +/***************************************************************************** + * + * File ..................: packet.c + * Purpose ...............: Fidonet mailer + * Last modification date : 06-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" +#include "dbnode.h" + + + +static FILE *pktfp=NULL; +static faddr pktroute = +{ + NULL,0,0,0,0,NULL +}; + + + +FILE *openpkt(FILE *pkt, faddr *addr, char flavor) +{ + off_t pos; + struct flock fl; + struct stat st; + char *Name; + struct tm *ptm; + time_t t; + int i; + faddr *bestaka; + unsigned char buffer[0x3a]; + char str[9]; + + if (pkt == NULL) { + if (pktfp) { + Syslog('P', "packet opened, check address"); + if (metric(addr,&pktroute) == 0) { + if ((CFG.maxpktsize == 0L) || + ((fstat(fileno(pktfp),&st) == 0) && + (st.st_size < CFG.maxpktsize))) { + Syslog('P', "return existing fp"); + return pktfp; + } + Syslog('P', "packet too big, open new"); + closepkt(); + } else { + Syslog('P', "address changed, closing fp"); + closepkt(); + } + } + + Syslog('P', "open new packet file"); + pktroute.zone = addr->zone; + pktroute.net = addr->net; + pktroute.node = addr->node; + pktroute.point = addr->point; + pktroute.domain = xstrcpy(addr->domain); + pktroute.name = NULL; + Name = pktname(addr,flavor); + mkdirs(Name); + + if ((pktfp = fopen(Name, "r+")) == NULL) + pktfp = fopen(Name,"w"); + if (pktfp == NULL) { + WriteError("$Unable to open packet %s",MBSE_SS(Name)); + return NULL; + } + + fl.l_type = F_WRLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + if (fcntl(fileno(pktfp), F_SETLKW, &fl) < 0) { + WriteError("$Unable to lock packet %s", MBSE_SS(Name)); + fclose(pktfp); + return NULL; + } + + pkt = pktfp; + pos = fseek(pkt, -2L, SEEK_END); + } + + pos = ftell(pkt); + if (pos <= 0L) { + Syslog('P', "creating new .pkt"); + + memset(&buffer, 0, sizeof(buffer)); + time(&t); + ptm = localtime(&t); + if (ptm->tm_sec > 59) + ptm->tm_sec = 59; + + bestaka = bestaka_s(addr); + buffer[0x00] = (bestaka->node & 0x00ff); + buffer[0x01] = (bestaka->node & 0xff00) >> 8; + buffer[0x02] = (addr->node & 0x00ff); + buffer[0x03] = (addr->node & 0xff00) >> 8; + buffer[0x04] = ((ptm->tm_year + 1900) & 0x00ff); + buffer[0x05] = ((ptm->tm_year + 1900) & 0xff00) >> 8; + buffer[0x06] = ptm->tm_mon; + buffer[0x08] = ptm->tm_mday; + buffer[0x0a] = ptm->tm_hour; + buffer[0x0c] = ptm->tm_min; + buffer[0x0e] = ptm->tm_sec; + buffer[0x12] = 2; + buffer[0x14] = (bestaka->net & 0x00ff); + buffer[0x15] = (bestaka->net & 0xff00) >> 8; + buffer[0x16] = (addr->net & 0x00ff); + buffer[0x17] = (addr->net & 0xff00) >> 8; + buffer[0x18] = 0xfe; + + memset(&str, 0, 8); + if (noderecord(addr) && strlen(nodes.Epasswd)) + sprintf(str, "%s", nodes.Epasswd); + for (i = 0; i < 8; i++) + buffer[0x1a + i] = str[i]; + + buffer[0x22] = (bestaka->zone & 0x00ff); + buffer[0x23] = (bestaka->zone & 0xff00) >> 8; + buffer[0x24] = (addr->zone & 0x00ff); + buffer[0x25] = (addr->zone & 0xff00) >> 8; + buffer[0x29] = 1; + buffer[0x2c] = 1; + buffer[0x2e] = buffer[0x22]; + buffer[0x2f] = buffer[0x23]; + buffer[0x30] = buffer[0x24]; + buffer[0x31] = buffer[0x25]; + buffer[0x32] = (bestaka->point & 0x00ff); + buffer[0x33] = (bestaka->point & 0xff00) >> 8; + buffer[0x34] = (addr->point & 0x00ff); + buffer[0x35] = (addr->point & 0xff00) >> 8; + buffer[0x36] = 'm'; + buffer[0x37] = 'b'; + buffer[0x38] = 's'; + buffer[0x39] = 'e'; + + fseek(pkt, 0L, SEEK_SET); + fwrite(buffer, 1, 0x3a, pkt); + } + + return pkt; +} + + + +void closepkt(void) +{ + unsigned char buffer[2]; + + Syslog('P', "closepkt entered"); + memset(&buffer, 0, sizeof(buffer)); + + if (pktfp) { + fwrite(buffer, 1, 2, pktfp); + fclose(pktfp); /* close also discards lock */ + } + pktfp = NULL; + if (pktroute.domain) + free(pktroute.domain); +} + + diff --git a/lib/parsedate.c b/lib/parsedate.c new file mode 100644 index 00000000..ce58b0c3 --- /dev/null +++ b/lib/parsedate.c @@ -0,0 +1,1780 @@ +/* $Revision$ +** +** Originally written by Steven M. Bellovin while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** and Jim Berets in August, 1990. +** Further revised (removed obsolete constructs and cleaned up timezone +** names) in August, 1991, by Rich. Paul Eggert +** helped in September, 1992. +** +** This grammar has six shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ +/* SUPPRESS 530 *//* Empty body for statement */ +/* SUPPRESS 593 on yyerrlab *//* Label was not used */ +/* SUPPRESS 593 on yynewstate *//* Label was not used */ +/* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + + +#if !defined(HAVE_TM_ZONE) && !defined(_TIMEZONE) && !defined(HAVE_DECLARED_TIMEZONE) +extern time_t timezone; +#endif + +#define yylhs date_yylhs +#define yylen date_yylen +#define yydefred date_yydefred +#define yydgoto date_yydgoto +#define yysindex date_yysindex +#define yyrindex date_yyrindex +#define yygindex date_yygindex +#define yytable date_yytable +#define yycheck date_yycheck +#define yyparse date_parse +#define yylex date_lex +#define yyerror date_error + +static int date_lex(void); + + /* See the LeapYears table in Convert. */ +#define EPOCH 1970 +#define END_OF_TIME 2038 + /* Constants for general time calculations. */ +#define DST_OFFSET 1 +#define SECSPERDAY (24L * 60L * 60L) + /* Readability for TABLE stuff. */ +#define HOUR(x) (x * 60) + +#define LPAREN '(' +#define RPAREN ')' +#define IS7BIT(x) ((unsigned int)(x) < 0200) + +/* +** Get the number of elements in a fixed-size array, or a pointer just +** past the end of it. +*/ +#define SIZEOF(array) ((int)(sizeof array / sizeof array[0])) +#define ENDOF(array) (&array[SIZEOF(array)]) +#define CTYPE(isXXXXX, c) ((isascii((c)) && isXXXXX((c)))) + + +typedef char const *STRING; +typedef char * const CSTRING; + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + STRING name; + int type; + time_t value; +} TABLE; + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + + +/* +** Global variables. We could get rid of most of them by using a yacc +** union, but this is more efficient. (This routine predates the +** yacc %union construct.) +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static int yyHaveDate; +static int yyHaveRel; +static int yyHaveTime; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + + + +static void date_error(char *); + + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 44 +#define YYFLAG -32768 +#define YYNTBASE 15 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 265 ? yytranslate[x] : 23) + +static const 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, 14, 2, 2, 13, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 12, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 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, 3, 4, 5, 6, + 7, 8, 9, 10, 11 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 1, 4, 6, 9, 11, 13, 16, 21, 26, + 33, 40, 42, 44, 47, 49, 51, 55, 61, 64, + 69, 72, 76, 82, 85, 88, 91, 94, 95 +}; + +static const short yyrhs[] = { -1, + 15, 16, 0, 17, 0, 17, 18, 0, 20, 0, + 21, 0, 10, 22, 0, 10, 12, 10, 22, 0, + 10, 12, 10, 19, 0, 10, 12, 10, 12, 10, + 22, 0, 10, 12, 10, 12, 10, 19, 0, 11, + 0, 4, 0, 11, 19, 0, 19, 0, 9, 0, + 10, 13, 10, 0, 10, 13, 10, 13, 10, 0, + 6, 10, 0, 6, 10, 14, 10, 0, 10, 6, + 0, 10, 6, 10, 0, 3, 14, 10, 6, 10, + 0, 9, 8, 0, 10, 8, 0, 9, 7, 0, + 10, 7, 0, 0, 5, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 160, 161, 164, 173, 177, 180, 185, 197, 203, 210, + 216, 226, 230, 234, 242, 248, 269, 273, 293, 297, + 308, 312, 323, 336, 339, 342, 345, 350, 353 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const yytname[] = { "$","error","$undefined.","tDAY","tDAYZONE", +"tMERIDIAN","tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tZONE", +"':'","'/'","','","spec","item","time","zone","numzone","date","rel","o_merid", NULL +}; +#endif + +static const short yyr1[] = { 0, + 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, + 17, 18, 18, 18, 18, 19, 20, 20, 20, 20, + 20, 20, 20, 21, 21, 21, 21, 22, 22 +}; + +static const short yyr2[] = { 0, + 0, 2, 1, 2, 1, 1, 2, 4, 4, 6, + 6, 1, 1, 2, 1, 1, 3, 5, 2, 4, + 2, 3, 5, 2, 2, 2, 2, 0, 1 +}; + +static const short yydefact[] = { 1, + 0, 0, 0, 0, 28, 2, 3, 5, 6, 0, + 19, 26, 24, 29, 21, 27, 25, 0, 0, 7, + 13, 16, 12, 4, 15, 0, 0, 22, 28, 17, + 14, 0, 20, 0, 9, 8, 0, 23, 28, 18, + 11, 10, 0, 0 +}; + +static const short yydefgoto[] = { 1, + 6, 7, 24, 25, 8, 9, 20 +}; + +static const short yypact[] = {-32768, + 1, -11, 11, 20, 12,-32768, 4,-32768,-32768, 13, + 16,-32768,-32768,-32768, 21,-32768,-32768, 22, 23,-32768, +-32768,-32768, 5,-32768,-32768, 28, 25,-32768, 17, 24, +-32768, 26,-32768, 29,-32768,-32768, 30,-32768, 0,-32768, +-32768,-32768, 38,-32768 +}; + +static const short yypgoto[] = {-32768, +-32768,-32768,-32768, -23,-32768,-32768, -27 +}; + + +#define YYLAST 40 + + +static const short yytable[] = { 31, + 43, 36, 10, 2, 14, 35, 3, 21, 22, 4, + 5, 42, 22, 22, 23, 41, 14, 15, 16, 17, + 11, 14, 26, 18, 19, 22, 12, 13, 34, 27, + 28, 29, 30, 32, 33, 38, 37, 44, 39, 40 +}; + +static const short yycheck[] = { 23, + 0, 29, 14, 3, 5, 29, 6, 4, 9, 9, + 10, 39, 9, 9, 11, 39, 5, 6, 7, 8, + 10, 5, 10, 12, 13, 9, 7, 8, 12, 14, + 10, 10, 10, 6, 10, 10, 13, 0, 10, 10 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +// #line 3 "/usr/local/share/bison.simple" +/* This file comes from bison-1.28. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 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. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +#ifndef YYSTACK_USE_ALLOCA +#ifdef alloca +#define YYSTACK_USE_ALLOCA +#else /* alloca not defined */ +#ifdef __GNUC__ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) +#define YYSTACK_USE_ALLOCA +#include +#else /* not sparc */ +/* We think this test detects Watcom and Microsoft C. */ +/* This used to test MSDOS, but that is a bad idea + since that symbol is in the user namespace. */ +#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) +#if 0 /* No need for malloc.h, which pollutes the namespace; + instead, just don't use alloca. */ +#include +#endif +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +/* I don't know what this was needed for, but it pollutes the namespace. + So I turned it off. rms, 2 May 1997. */ +/* #include */ + #pragma alloca +#define YYSTACK_USE_ALLOCA +#else /* not MSDOS, or __TURBOC__, or _AIX */ +#if 0 +#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, + and on HPUX 10. Eventually we can turn this on. */ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#endif /* __hpux */ +#endif +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc */ +#endif /* not GNU C */ +#endif /* alloca not defined */ +#endif /* YYSTACK_USE_ALLOCA not defined */ + +#ifdef YYSTACK_USE_ALLOCA +#define YYSTACK_ALLOC alloca +#else +#define YYSTACK_ALLOC malloc +#endif + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#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), cyylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&cyylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&cyylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&cyylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&cyylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +CYYSTYPE cyylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Define __yy_memcpy. Note that the size argument + should be passed with type unsigned int, because that is what the non-GCC + definitions require. With GCC, __builtin_memcpy takes an arg + of type size_t, but it can handle unsigned int. */ + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + unsigned int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, unsigned int count) +{ + register char *t = to; + register char *f = from; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +#ifdef YYPARSE_PARAM +int yyparse (void *); +#else +int yyparse (void); +#endif +#endif + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register CYYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + CYYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + CYYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + int yyfree_stacks = 0; + +#ifdef YYPURE + int yychar; + CYYSTYPE cyylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + CYYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + 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 - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + CYYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* 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, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror((char *)"parser stack overflow"); + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; +#ifndef YYSTACK_USE_ALLOCA + yyfree_stacks = 1; +#endif + yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, + size * (unsigned int) sizeof (*yyssp)); + yyvs = (CYYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, + size * (unsigned int) sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, + size * (unsigned int) sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto 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 == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, cyylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = cyylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 3: +{ + yyHaveTime++; +#if defined(lint) + /* I am compulsive about lint natterings... */ + if (yyHaveTime == -1) { + YYERROR; + } +#endif /* defined(lint) */ + ; + break;} +case 4: +{ + yyHaveTime++; + yyTimezone = yyvsp[0].Number; + ; + break;} +case 5: +{ + yyHaveDate++; + ; + break;} +case 6: +{ + yyHaveRel = 1; + ; + break;} +case 7: +{ + if (yyvsp[-1].Number < 100) { + yyHour = yyvsp[-1].Number; + yyMinutes = 0; + } + else { + yyHour = yyvsp[-1].Number / 100; + yyMinutes = yyvsp[-1].Number % 100; + } + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + ; + break;} +case 8: +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + ; + break;} +case 9: +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yyTimezone = yyvsp[0].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + ; + break;} +case 10: +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyMeridian = yyvsp[0].Meridian; + ; + break;} +case 11: +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyTimezone = yyvsp[0].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + ; + break;} +case 12: +{ + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSToff; + ; + break;} +case 13: +{ + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSTon; + ; + break;} +case 14: +{ + /* Only allow "GMT+300" and "GMT-0800" */ + if (yyvsp[-1].Number != 0) { + YYABORT; + } + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSToff; + ; + break;} +case 15: +{ + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSToff; + ; + break;} +case 16: +{ + int i; + + /* Unix and GMT and numeric timezones -- a little confusing. */ + if (yyvsp[0].Number < 0) { + /* Don't work with negative modulus. */ + yyvsp[0].Number = -yyvsp[0].Number; + if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) { + YYABORT; + } + yyval.Number = (yyvsp[0].Number / 100) * 60 + i; + } + else { + if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) { + YYABORT; + } + yyval.Number = -((yyvsp[0].Number / 100) * 60 + i); + } + ; + break;} +case 17: +{ + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + ; + break;} +case 18: +{ + if (yyvsp[-4].Number > 100) { + /* assume YYYY/MM/DD format, so need not to add 1900 */ + yyYear = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } + else { + /* assume MM/DD/YY* format */ + yyMonth = yyvsp[-4].Number; + yyDay = yyvsp[-2].Number; + if (yyvsp[0].Number > 100) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = yyvsp[0].Number; + } else { + /* assume year is YY format, so need to add 1900 */ + yyYear = yyvsp[0].Number + 1900; + } + } + ; + break;} +case 19: +{ + yyMonth = yyvsp[-1].Number; + yyDay = yyvsp[0].Number; + ; + break;} +case 20: +{ + yyMonth = yyvsp[-3].Number; + yyDay = yyvsp[-2].Number; + if (yyvsp[0].Number > 100) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = yyvsp[0].Number; + } else { + /* assume year is YY format, so need to add 1900 */ + yyYear = yyvsp[0].Number + 1900; + } + ; + break;} +case 21: +{ + yyDay = yyvsp[-1].Number; + yyMonth = yyvsp[0].Number; + ; + break;} +case 22: +{ + yyDay = yyvsp[-2].Number; + yyMonth = yyvsp[-1].Number; + if (yyvsp[0].Number > 100) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = yyvsp[0].Number; + } else { + /* assume year is YY format, so need to add 1900 */ + yyYear = yyvsp[0].Number + 1900; + } + ; + break;} +case 23: +{ + yyDay = yyvsp[-2].Number; + yyMonth = yyvsp[-1].Number; + if (yyvsp[0].Number > 100) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = yyvsp[0].Number; + } else { + /* assume year is YY format, so need to add 1900 */ + yyYear = yyvsp[0].Number + 1900; + } + ; + break;} +case 24: +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 25: +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 26: +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 27: +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 28: +{ + yyval.Meridian = MER24; + ; + break;} +case 29: +{ + yyval.Meridian = yyvsp[0].Meridian; + ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* 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 - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror((char *)"parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + 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) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = cyylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + yyacceptlab: + /* YYACCEPT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 0; + + yyabortlab: + /* YYABORT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 1; +} + + +/* Month and day table. */ +static TABLE MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + /* The value of the day isn't used... */ + { "sunday", tDAY, 0 }, + { "monday", tDAY, 0 }, + { "tuesday", tDAY, 0 }, + { "wednesday", tDAY, 0 }, + { "thursday", tDAY, 0 }, + { "friday", tDAY, 0 }, + { "saturday", tDAY, 0 }, +}; + +/* Time units table. */ +static TABLE UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "week", tSEC_UNIT, 7 * 24 * 60 * 60 }, + { "day", tSEC_UNIT, 1 * 24 * 60 * 60 }, + { "hour", tSEC_UNIT, 60 * 60 }, + { "minute", tSEC_UNIT, 60 }, + { "min", tSEC_UNIT, 60 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, +}; + +/* Timezone table. */ +static TABLE TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal */ + { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */ + { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */ + { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */ + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */ + { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */ + { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */ + { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "mez", tZONE, -HOUR(1) }, /* Middle European */ + { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */ + { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */ + { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */ + { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ + { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */ + { "cct", tZONE, -HOUR(8) }, /* China Coast */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard */ + { "kst", tZONE, -HOUR(9) }, /* Korean Standard */ + { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */ + { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */ + { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */ + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + + /* For completeness we include the following entries. */ +#if 0 + + /* Duplicate names. Either they conflict with a zone listed above + * (which is either more likely to be seen or just been in circulation + * longer), or they conflict with another zone in this section and + * we could not reasonably choose one over the other. */ + { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */ + { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */ + { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */ + { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */ + { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */ + { "cst", tZONE, HOUR( 5) }, /* Chile Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */ + { "ast", tZONE, HOUR( 5) }, /* Acre Standard */ + { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */ + { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */ + { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */ + { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */ + { "sst", tZONE, HOUR(11) }, /* Samoa Standard */ + { "ist", tZONE, -HOUR(2) }, /* Israel Standard */ + { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */ + { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */ + { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */ + { "cst", tZONE, -HOUR(8) }, /* China Standard */ + { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */ + { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */ + + /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ + { "wat", tZONE, -HOUR(1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard */ + { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad */ + { "it", tZONE, -(HOUR(3)+30) }, /* Iran */ + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ + { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */ + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ + { "nst", tZONE, -HOUR(7) }, /* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra */ + { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */ + { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */ + { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */ + { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */ +#endif /* 0 */ +}; + + + +/* ARGSUSED */ +static void +date_error(s) + char *s; +{ + /* NOTREACHED */ +} + +int GetTimeInfo(TIMEINFO *Now) +{ + static time_t NextHour; + static long LastTzone; + struct tm *tm; + int secondsUntilNextHour; +#if defined(HAVE_GETTIMEOFDAY) + struct timeval tv; +#endif /* defined(HAVE_GETTIMEOFDAY) */ +#if !defined(HAVE_TM_GMTOFF) + struct tm local; + struct tm gmt; +#endif /* !defined(HAVE_TM_GMTOFF) */ + + /* Get the basic time. */ +#if defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(&tv, (struct timezone *)NULL) == -1) + return -1; + Now->time = tv.tv_sec; + Now->usec = tv.tv_usec; +#else + /* Can't check for -1 since that might be a time, I guess. */ + (void)time(&Now->time); + Now->usec = 0; +#endif /* defined(HAVE_GETTIMEOFDAY) */ + + /* Now get the timezone if the last time < HH:00:00 <= now for some HH. */ + if (NextHour <= Now->time) { + if ((tm = localtime(&Now->time)) == NULL) + return -1; + secondsUntilNextHour = 60 * (60 - tm->tm_min) - tm->tm_sec; +#if !defined(HAVE_TM_GMTOFF) + /* To get the timezone, compare localtime with GMT. */ + local = *tm; + if ((tm = gmtime(&Now->time)) == NULL) + return -1; + gmt = *tm; + + /* Assume we are never more than 24 hours away. */ + LastTzone = gmt.tm_yday - local.tm_yday; + if (LastTzone > 1) + LastTzone = -24; + else if (LastTzone < -1) + LastTzone = 24; + else + LastTzone *= 24; + + /* Scale in the hours and minutes; ignore seconds. */ + LastTzone += gmt.tm_hour - local.tm_hour; + LastTzone *= 60; + LastTzone += gmt.tm_min - local.tm_min; +#else + LastTzone = (0 - tm->tm_gmtoff) / 60; +#endif /* defined(HAVE_TM_GMTOFF) */ + NextHour = Now->time + secondsUntilNextHour; + } + Now->tzone = LastTzone; + return 0; +} + + + +static time_t ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian) +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61) + return -1; + if (Meridian == MER24) { + if (Hours < 0 || Hours > 23) + return -1; + } + else { + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + if (Meridian == MERpm) + Hours += 12; + } + return (Hours * 60L + Minutes) * 60L + Seconds; +} + + +static time_t +Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian, DSTMODE dst) +{ + static int DaysNormal[13] = { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static int DaysLeap[13] = { + 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static int LeapYears[] = { + 1972, 1976, 1980, 1984, 1988, 1992, 1996, + 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036 + }; + int *yp; + int *mp; + time_t Julian; + int i; + time_t tod; + + /* Year should not be passed as a relative value, but absolute one. + so this should not happen, but just ensure it */ + if (Year < 0) + Year = -Year; + if (Year < 100) + Year += 1900; + if (Year < EPOCH) + Year += 100; + for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++) + if (Year == *yp) { + mp = DaysLeap; + break; + } + if (Year < EPOCH || Year > END_OF_TIME + || Month < 1 || Month > 12 + /* NOSTRICT *//* conversion from long may lose accuracy */ + || Day < 1 || Day > mp[(int)Month]) + return -1; + + Julian = Day - 1 + (Year - EPOCH) * 365; + for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++) + if (Year <= *yp) + break; + for (i = 1; i < Month; i++) + Julian += *++mp; + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) + return -1; + Julian += tod; + tod = Julian; + if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst)) + Julian -= DST_OFFSET * 60 * 60; + return Julian; +} + + +static time_t DSTcorrect(time_t Start, time_t Future) +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60; +} + + +static time_t RelativeMonth(time_t Start, time_t RelMonth) +{ + struct tm *tm; + time_t Month; + time_t Year; + + tm = localtime(&Start); + Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; + Year = Month / 12; + Year += 1900; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int LookupWord(char *buff, int length) +{ + char *p; + STRING q; + TABLE *tp; + int c; + + p = buff; + c = p[0]; + + /* See if we have an abbreviation for a month. */ + if (length == 3 || (length == 4 && p[3] == '.')) + for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) { + q = tp->name; + if (c == q[0] && p[1] == q[1] && p[2] == q[2]) { + cyylval.Number = tp->value; + return tp->type; + } + } + else + for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + cyylval.Number = tp->value; + return tp->type; + } + + /* Try for a timezone. */ + for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + cyylval.Number = tp->value; + return tp->type; + } + + /* Try the units table. */ + for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + cyylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + if (--length > 0 && p[length] == 's') { + p[length] = '\0'; + for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + p[length] = 's'; + cyylval.Number = tp->value; + return tp->type; + } + p[length] = 's'; + } + length++; + + /* Drop out any periods. */ + for (p = buff, q = (STRING)buff; *q; q++) + if (*q != '.') + *p++ = *q; + *p = '\0'; + + /* Try the meridians. */ + if (buff[1] == 'm' && buff[2] == '\0') { + if (buff[0] == 'a') { + cyylval.Meridian = MERam; + return tMERIDIAN; + } + if (buff[0] == 'p') { + cyylval.Meridian = MERpm; + return tMERIDIAN; + } + } + + /* If we saw any periods, try the timezones again. */ + if (p - buff != length) { + c = buff[0]; + for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + cyylval.Number = tp->value; + return tp->type; + } + } + + /* Unknown word -- assume GMT timezone. */ + cyylval.Number = 0; + return tZONE; +} + + +static int date_lex(void) +{ + char c; + char *p; + char buff[20]; + int sign; + int i; + int nesting; + + for ( ; ; ) { + /* Get first character after the whitespace. */ + for ( ; ; ) { + while (CTYPE(isspace, (int)*yyInput)) + yyInput++; + c = *yyInput; + + /* Ignore RFC 822 comments, typically time zone names. */ + if (c != LPAREN) + break; + for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; ) + if (c == LPAREN) + nesting++; + else if (!IS7BIT(c) || c == '\0' || c == '\r' + || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c)))) + /* Lexical error: bad comment. */ + return '?'; + yyInput++; + } + + /* A number? */ + if (CTYPE(isdigit, (int)c) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + yyInput++; + if (!CTYPE(isdigit, (int)*yyInput)) + /* Skip the plus or minus sign. */ + continue; + } + else + sign = 0; + for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, (int)c); ) + i = 10 * i + c - '0'; + yyInput--; + cyylval.Number = sign < 0 ? -i : i; + return sign ? tSNUMBER : tUNUMBER; + } + + /* A word? */ + if (CTYPE(isalpha, (int)c)) { + for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, (int)c); ) + if (p < &buff[sizeof buff - 1]) + *p++ = CTYPE(isupper, (int)c) ? tolower(c) : c; + *p = '\0'; + yyInput--; + return LookupWord(buff, p - buff); + } + + return *yyInput++; + } +} + + +time_t parsedate(char *p, TIMEINFO *now) +{ + struct tm *tm; + TIMEINFO ti; + time_t Start; + + yyInput = p; + if (now == NULL) { + now = &ti; + (void)GetTimeInfo(&ti); + } + + tm = localtime(&now->time); + yyYear = tm->tm_year + 1900; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; +#ifdef HAVE_TM_GMTOFF + yyTimezone = tm->tm_gmtoff/60; +#else + yyTimezone = timezone/60; +#endif + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveRel = 0; + yyHaveTime = 0; + + if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1) + return -1; + + if (yyHaveDate || yyHaveTime) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } + else { + Start = now->time; + if (!yyHaveRel) + Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec; + } + + Start += yyRelSeconds; + if (yyRelMonth) + Start += RelativeMonth(Start, yyRelMonth); + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} diff --git a/lib/pktname.c b/lib/pktname.c new file mode 100644 index 00000000..5cadc666 --- /dev/null +++ b/lib/pktname.c @@ -0,0 +1,286 @@ +/***************************************************************************** + * + * File ..................: pktname.c + * Purpose ...............: BinkleyTerm outbound naming + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + +#define ptyp "ut" +#define ftyp "lo" +#define ttyp "pk" +#define rtyp "req" +#define styp "spl" +#define btyp "bsy" +#define qtyp "sts" +#define ltyp "pol" + + +static char buf[PATH_MAX]; + + +char *prepbuf(faddr *addr) +{ + char *p, *domain=NULL; + char zpref[8]; + int i; + + sprintf(buf, "%s", CFG.outbound); + + if (CFG.addr4d) { + Syslog('o', "Use 4d addressing, zone is %d", addr->zone); + + if ((addr->zone == 0) || (addr->zone == CFG.aka[0].zone)) + zpref[0] = '\0'; + else + sprintf(zpref, ".%03x", addr->zone); + } else { + /* + * If we got a 5d address we use the given domain, if + * we got a 4d address, we look for a matching domain name. + */ + if (addr->domain) + domain = xstrcpy(addr->domain); + else + for (i = 0; i < 40; i++) + if (CFG.aka[i].zone == addr->zone) { + domain = xstrcpy(CFG.aka[i].domain); + break; + } + + if ((domain != NULL) && (strlen(CFG.aka[0].domain) != 0) && + (strcasecmp(domain,CFG.aka[0].domain) != 0)) { + if ((p = strrchr(buf,'/'))) + p++; + else + p = buf; + strcpy(p, domain); + for (; *p; p++) + *p = tolower(*p); + for (i = 0; i < 40; i++) + if ((strlen(CFG.aka[i].domain)) && + (strcasecmp(CFG.aka[i].domain, domain) == 0)) + break; + + /* + * The default zone must be the first one in the + * setup, other zones get the hexadecimal zone + * number appended. + */ + if (CFG.aka[i].zone == addr->zone) + zpref[0] = '\0'; + else + sprintf(zpref, ".%03x", addr->zone); + } else { + /* + * this is our primary domain + */ + if ((addr->zone == 0) || (addr->zone == CFG.aka[0].zone)) + zpref[0]='\0'; + else + sprintf(zpref,".%03x",addr->zone); + } + } + + p = buf + strlen(buf); + + if (addr->point) + sprintf(p,"%s/%04x%04x.pnt/%08x.", zpref,addr->net,addr->node,addr->point); + else + sprintf(p,"%s/%04x%04x.",zpref,addr->net,addr->node); + + p = buf + strlen(buf); + if (domain) + free(domain); + return p; +} + + + +char *pktname(faddr *addr, char flavor) +{ + char *p; + + p = prepbuf(addr); + if (flavor == 'f') + flavor = 'o'; + + sprintf(p, "%c%s", flavor, ptyp); + Syslog('O', "packet name is \"%s\"",buf); + return buf; +} + + + +char *floname(faddr *addr, char flavor) +{ + char *p; + + p = prepbuf(addr); + if (flavor == 'o') + flavor = 'f'; + sprintf(p, "%c%s", flavor, ftyp); + Syslog('O', "flo file name is \"%s\"",buf); + return buf; +} + + + +char *reqname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", rtyp); + Syslog('O', "req file name is \"%s\"",buf); + return buf; +} + + + +char *splname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", styp); + Syslog('O', "spl file name is \"%s\"",buf); + return buf; +} + + + +char *bsyname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", btyp); + Syslog('O', "bsy file name is \"%s\"",buf); + return buf; +} + + + +char *stsname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", qtyp); + Syslog('O', "sts file name is \"%s\"",buf); + return buf; +} + + + +char *polname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", ltyp); + Syslog('O', "pol file name is \"%s\"", buf); + return buf; +} + + + +static char *dow[] = {(char *)"su", (char *)"mo", (char *)"tu", (char *)"we", + (char *)"th", (char *)"fr", (char *)"sa"}; + +char *dayname(void) +{ + time_t tt; + struct tm *ptm; + + (void)time(&tt); + ptm = localtime(&tt); + sprintf(buf, "%s", dow[ptm->tm_wday]); + + return buf; +} + + + +char *arcname(faddr *addr, unsigned short Zone, int ARCmailCompat) +{ + char *p; + char *ext; + time_t tt; + struct tm *ptm; + faddr *bestaka; + + (void)time(&tt); + ptm = localtime(&tt); + ext = dow[ptm->tm_wday]; + + bestaka = bestaka_s(addr); + + (void)prepbuf(addr); + p = strrchr(buf, '/'); + + if (!ARCmailCompat && (Zone != addr->zone)) { + /* + * Generate ARCfile name from the CRC of the ASCII string + * of the node address. + */ + sprintf(p, "/%08lx.%s0", StringCRC32(ascfnode(addr, 0x1f)), ext); + } else { + if (addr->point) { + sprintf(p, "/%04x%04x.%s0", + ((bestaka->net) - (addr->net)) & 0xffff, + ((bestaka->node) - (addr->node) + (addr->point)) & 0xffff, + ext); + } else if (bestaka->point) { + /* + * Inserted the next code for if we are a point, + * I hope this is ARCmail 0.60 compliant. 21-May-1999 + */ + sprintf(p, "/%04x%04x.%s0", ((bestaka->net) - (addr->net)) & 0xffff, + ((bestaka->node) - (addr->node) - (bestaka->point)) & 0xffff, ext); + } else { + sprintf(p, "/%04x%04x.%s0", ((bestaka->net) - (addr->net)) & 0xffff, + ((bestaka->node) - (addr->node)) &0xffff, ext); + } + } + + Syslog('O', "Arc file name is \"%s\"", buf); + return buf; +} + + diff --git a/lib/pop3.c b/lib/pop3.c new file mode 100644 index 00000000..de904259 --- /dev/null +++ b/lib/pop3.c @@ -0,0 +1,202 @@ +/***************************************************************************** + * + * File ..................: pop3.c + * Purpose ...............: MBSE BBS Internet Library + * Last modification date : 12-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "mbinet.h" + + +static int pop3sock = -1; /* TCP/IP socket */ +struct hostent *php; /* Host info remote */ +struct servent *psp; /* Service information */ +struct sockaddr_in pop3_loc; /* For local socket address */ +struct sockaddr_in pop3_rem; /* For remote socket address */ + + + +int pop3_connect(void) +{ + int addrlen; + char *p; + + if (!strlen(CFG.popnode)) { + WriteError("POP3: host not configured"); + return -1; + } + + Syslog('+', "POP3: connecting host: %s", CFG.popnode); + memset(&pop3_loc, 0, sizeof(struct sockaddr_in)); + memset(&pop3_rem, 0, sizeof(struct sockaddr_in)); + + pop3_rem.sin_family = AF_INET; + + if ((php = gethostbyname(CFG.popnode)) == NULL) { + WriteError("$POP3: can't find host %s", CFG.popnode); + return -1; + } + + pop3_rem.sin_addr.s_addr = ((struct in_addr *)(php->h_addr))->s_addr; + + if ((psp = getservbyname("pop3", "tcp")) == NULL) { + /* + * RedHat doesn't follow IANA specs and uses pop-3 in /etc/services + */ + if ((psp = getservbyname("pop-3", "tcp")) == NULL) { + WriteError("$POP3: can't find service port for pop3/tcp"); + return -1; + } + } + pop3_rem.sin_port = psp->s_port; + + if ((pop3sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + WriteError("$POP3: unable to create tcp socket"); + return -1; + } + + if (connect(pop3sock, (struct sockaddr *)&pop3_rem, sizeof(struct sockaddr_in)) == -1) { + WriteError("$POP3: cannot connect tcp socket"); + return -1; + } + + addrlen = sizeof(struct sockaddr_in); + + if (getsockname(pop3sock, (struct sockaddr *)&pop3_loc, &addrlen) == -1) { + WriteError("$POP3: unable to read socket address"); + return -1; + } + + p = pop3_receive(); + if (strlen(p) == 0) { + WriteError("POP3: no response from server"); + pop3_close(); + return -1; + } + + if (strncmp(p, "+OK", 3)) { + WriteError("POP3: bad response: %s", p); + pop3_close(); + return -1; + } + + Syslog('+', "POP3: %s", p); + + return pop3sock; +} + + + +int pop3_send(char *buf) +{ + if (pop3sock == -1) + return -1; + + if (send(pop3sock, buf, strlen(buf), 0) != strlen(buf)) { + WriteError("$POP3: socket send failed"); + return -1; + } + return 0; +} + + + +/* + * Return empty buffer if something went wrong, else the complete + * dataline is returned + */ +char *pop3_receive(void) +{ + static char buf[SS_BUFSIZE]; + int i, j; + + memset((char *)&buf, 0, SS_BUFSIZE); + i = 0; + while (TRUE) { + j = recv(pop3sock, &buf[i], 1, 0); + if (j == -1) { + WriteError("$POP3: error reading socket"); + memset((char *)&buf, 0, SS_BUFSIZE); + return buf; + } + if (buf[i] == '\n') + break; + i += j; + } + + for (i = 0; i < strlen(buf); i++) { + if (buf[i] == '\n') + buf[i] = '\0'; + if (buf[i] == '\r') + buf[i] = '\0'; + } + + return buf; +} + + + +int pop3_close(void) +{ + if (pop3sock == -1) + return 0; + + if (shutdown(pop3sock, 1) == -1) { + WriteError("$POP3: can't close socket"); + return -1; + } + + pop3sock = -1; + Syslog('+', "POP3: closed"); + return 0; +} + + + +int pop3_cmd(char *cmd) +{ + char *p; + + if (pop3_send(cmd) == -1) + return -1; + + p = pop3_receive(); + + if (strncmp(p, "+OK", 3)) { + WriteError("POP3> %s", cmd); + WriteError("POP3< %s", p); + return -1; + } + return 0; +} + + + diff --git a/lib/rawio.c b/lib/rawio.c new file mode 100644 index 00000000..96f750eb --- /dev/null +++ b/lib/rawio.c @@ -0,0 +1,238 @@ +/***************************************************************************** + * + * File ..................: rawio.c + * Purpose ...............: Raw I/O routines. + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + +int rawset = FALSE; + + +/* + * Sets raw mode and saves the terminal setup + */ +void Setraw() +{ + if (ioctl(ttyfd, TCGETA, &tbuf) == -1) { + perror("TCGETA Failed"); + exit(1); /* ERROR - could not set get tty ioctl */ + } + + tbufsav = tbuf; + tbuf.c_iflag &= ~(INLCR | ICRNL | IUCLC | ISTRIP | IXON ); + /* + * Map CRNL modes strip control characters and flow control + */ + tbuf.c_oflag &= ~OPOST; /* Don't do ouput character translation */ + tbuf.c_lflag &= ~(ICANON | ECHO); /* No canonical input and no echo */ + tbuf.c_cc[VMIN] = 1; /* Receive 1 character at a time */ + tbuf.c_cc[VTIME] = 0; /* No time limit per character */ + + if (ioctl(ttyfd, TCSETAF, &tbuf) == -1) { + perror("TCSETAF failed"); + exit(1); /* ERROR - could not set tty ioctl */ + } + + rawset = TRUE; +} + + + +/* + * Unsets raw mode and returns state of terminal + */ +void Unsetraw() +{ + /* + * Only unset the mode if it is set to raw mode + */ + if (rawset == TRUE) { + if (ioctl(ttyfd, TCSETAF, &tbufsav) == -1) { + perror("TCSETAF Normal Failed"); + exit(1); /* ERROR - could not save original tty ioctl */ + } + } + rawset = FALSE; +} + + + +/* + * This function is used to get a single character from a user ie for a + * menu option + */ +unsigned char Getone() +{ + unsigned char c = 0; + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 8"); + exit(1); + } + Setraw(); + + c = Readkey(); + + Unsetraw(); + close(ttyfd); + return(c); +} + + + +/* + * Read the (locked) speed from the tty + */ +int Speed(void) +{ + int mspeed; + struct termio ttyhold; + + static int baud[16] = {0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400}; + + ioctl(0, TCGETA, &ttyhold); + mspeed = baud[ttyhold.c_cflag & 017]; + ioctl(0, TCSETAF, &ttyhold); + + return(mspeed); +} + + + +/* + * Wait for a character for a maximum of wtime * 10 mSec. + */ +int Waitchar(unsigned char *ch, int wtime) +{ + int i, rc = -1; + + for (i = 0; i < wtime; i++) { + rc = read(ttyfd, ch, 1); + if (rc == 1) + return rc; + usleep(10000); + } + return rc; +} + + + +int Escapechar(unsigned char *ch) +{ + int rc; + unsigned char c; + + /* + * Escape character, if nothing follows within + * 50 mSec, the user really pressed . + */ + if ((rc = Waitchar(ch, 5)) == -1) + return rc; + + if (*ch == '[') { + /* + * Start of CSI sequence. If nothing follows, + * return immediatly. + */ + if ((rc = Waitchar(ch, 5)) == -1) + return rc; + + /* + * Test for the most important keys. Note + * that only the cursor movement keys are + * guaranteed to work with PC-clients. + */ + c = *ch; + if (c == 'A') + c = KEY_UP; + if (c == 'B') + c = KEY_DOWN; + if (c == 'C') + c = KEY_RIGHT; + if (c == 'D') + c = KEY_LEFT; + if ((c == '1') || (c == 'H') || (c == 0)) + c = KEY_HOME; + if ((c == '4') || (c == 'K') || (c == 101) || (c == 144)) + c = KEY_END; + if (c == '2') + c = KEY_INS; + if (c == '3') + c = KEY_DEL; + if (c == '5') + c = KEY_PGUP; + if (c == '6') + c = KEY_PGDN; + memcpy(ch, &c, sizeof(unsigned char)); + return rc; + } + return -1; +} + + + +/* + * This next function will detect the grey keys on the keyboard for + * VT100, VT220, Xterm, PC-ANSI, and Linux console. Works with + * several terminals on serial lines (tested 1200 bps). + * If for example cursur keys are detected, this function returns + * a translated value. + */ +unsigned char Readkey(void) +{ + unsigned char ch = 0; + int rc = -1; + + while (rc == -1) { + rc = Waitchar(&ch, 5); + + /* + * If the character is not an Escape character, + * then this function is finished. + */ + if ((rc == 1) && (ch != KEY_ESCAPE)) + return ch; + + if ((rc == 1) && (ch == KEY_ESCAPE)) { + rc = Escapechar(&ch); + if (rc == 1) + return ch; + else + return KEY_ESCAPE; + } + } + + return(ch); +} + + + diff --git a/lib/records.h b/lib/records.h new file mode 100644 index 00000000..7ccc3642 --- /dev/null +++ b/lib/records.h @@ -0,0 +1,123 @@ +/***************************************************************************** + * + * File ..................: records.h + * Purpose ...............: MBSE BBS Global structure + * Last modification date : 25-Sep-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#ifndef _RECORDS_H +#define _RECORDS_H + +struct userhdr usrconfighdr; /* Users database */ +struct userrec usrconfig; +struct userrec exitinfo; /* Users online data */ + +struct servicehdr servhdr; /* Services database */ +struct servicerec servrec; + +struct sysrec SYSINFO; /* System info statistics */ + +struct prothdr PROThdr; /* Transfer protocols */ +struct prot PROT; + +struct onelinehdr olhdr; /* Oneliner database */ +struct oneline ol; + +struct fileareashdr areahdr; /* File areas */ +struct fileareas area; +struct FILERecord file; +struct _fgrouphdr fgrouphdr; /* File groups */ +struct _fgroup fgroup; + +struct _ngrouphdr ngrouphdr; /* Newfiles groups */ +struct _ngroup ngroup; + +struct bbslisthdr bbshdr; /* BBS list */ +struct bbslist bbs; + +struct lastcallershdr LCALLhdr; /* Lastcallers info */ +struct lastcallers LCALL; + +struct sysconfig CFG; /* System configuration */ + +struct limitshdr LIMIThdr; /* User limits */ +struct limits LIMIT; + +struct menufile menus; + +struct msgareashdr msgshdr; /* Messages configuration */ +struct msgareas msgs; +struct _mgrouphdr mgrouphdr; /* Message groups */ +struct _mgroup mgroup; + +struct timebankhdr bankhdr; /* Timebank structure */ +struct timebank bank; + +struct languagehdr langhdr; /* Language data */ +struct language lang; +struct langdata ldata; + +struct crackerhdr safehdr; /* Safe cracker structure */ +struct cracker safe; + +struct _fidonethdr fidonethdr; /* Fidonet structure */ +struct _fidonet fidonet; +struct domhdr domainhdr; +struct domrec domtrans; + +struct _archiverhdr archiverhdr; /* Archivers */ +struct _archiver archiver; + +struct _virscanhdr virscanhdr; /* Virus scanners */ +struct _virscan virscan; + +struct _ttyinfohdr ttyinfohdr; /* TTY lines */ +struct _ttyinfo ttyinfo; +struct _modemhdr modemhdr; /* Modem models */ +struct _modem modem; + +struct _tichdr tichdr; /* TIC areas */ +struct _tic tic; +struct _hatchhdr hatchhdr; /* Hatch areas */ +struct _hatch hatch; +struct _magichdr magichdr; /* Magic areas */ +struct _magic magic; + +struct _nodeshdr nodeshdr; /* Fidonet nodes */ +struct _nodes nodes; + +struct _bill bill; /* Unsent bills */ + +struct _newfileshdr newfileshdr; /* New file reports */ +struct _newfiles newfiles; + +struct _scanmgrhdr scanmgrhdr; /* Filefind areas */ +struct _scanmgr scanmgr; + +#endif + diff --git a/lib/rfcaddr.c b/lib/rfcaddr.c new file mode 100644 index 00000000..538c8fba --- /dev/null +++ b/lib/rfcaddr.c @@ -0,0 +1,328 @@ +/***************************************************************************** + * + * File ..................: rfcaddr.c + * Purpose ...............: MBSE BBS Common Library + * Last modification date : 23-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +extern int addrerror; + +static char *errname[] = { + (char *)"nested <>", + (char *)"multiple <>", + (char *)"unmatched <>""()", + (char *)"badtoken", + (char *)"badstructure", +}; + + + +char *addrerrstr(int err) +{ + int i; + static char buf[128]; + + buf[0] = '\0'; + for (i = 0; i < ADDR_ERRMAX; i++) + if (err & (1 << i)) { + if (buf[0]) + strcat(buf,","); + strcat(buf, errname[i]); + } + if (buf[0] == '\0') + strcpy(buf,"none"); + return buf; +} + + + +void tidyrfcaddr(parsedaddr addr) +{ + if (addr.target) + free(addr.target); + if (addr.remainder) + free(addr.remainder); + if (addr.comment) + free(addr.comment); +} + + + +parsedaddr parserfcaddr(char *s) +{ + parsedaddr result; + char *inbrackets = NULL, *outbrackets = NULL, *cleanbuf = NULL, *combuf = NULL; + char *t, *r, *c, *p, *q, **x; + int quotes, brackets, escaped, anglecomplete; + char *firstat, *lastat, *percent, *colon, *comma, *exclam; + +// Syslog('M', "parserfcaddr() 1"); + + result.target = NULL; + result.remainder = NULL; + result.comment = NULL; + addrerror = 0; + + if ((s == NULL) || (*s == '\0')) + return result; + + /* First check if there is an "angled" portion */ + +// Syslog('M', "parserfcaddr() 1b strlen=%d", strlen(s)); + inbrackets = calloc(strlen(s)+1, sizeof(char)); + outbrackets = calloc(strlen(s)+1, sizeof(char)); + brackets = quotes = escaped = anglecomplete = 0; +// Syslog('M', "parserfcaddr() 2"); + for (p = s,q = inbrackets, r = outbrackets, x = &r; *p; p++) { + if (escaped) + escaped = FALSE; + else /* process all special chars */ + switch (*p) { + case '\\': escaped = TRUE; break; + case '\"': quotes = !quotes; break; + case '<': if (quotes) + break; + if (brackets) + addrerror |= ADDR_NESTED; + if (anglecomplete) + addrerror |= ADDR_MULTIPLE; + brackets++; + x = &q; + break; + case '>': if (quotes) + break; + if (brackets) + brackets--; + else + addrerror |= ADDR_UNMATCHED; + if (!brackets) + anglecomplete = 1; + break; + } + *((*x)++) = *p; + if (!brackets) + x = &r; + } +// Syslog('M', "parserfcaddr() 3"); + *q = '\0'; + *r = '\0'; + if (brackets || quotes) + addrerror |= ADDR_UNMATCHED; + +// Syslog('N', " inbrackets: \"%s\"",inbrackets); +// Syslog('N', "outbrackets: \"%s\"",outbrackets); +// Syslog('N', " addrerror: 0x%04x",addrerror); + + if (addrerror) + goto leave1; + + cleanbuf = calloc(strlen(s)+1, sizeof(char)); + combuf = calloc(strlen(s)+1, sizeof(char)); +// Syslog('M', "parserfcaddr() 4"); + if (*inbrackets) { /* there actually is an angled portion */ + strcpy(combuf, outbrackets); + c = combuf + strlen(combuf); + p = inbrackets + 1; + *(p+strlen(p)-1) = '\0'; + } else { + c = combuf; + p = outbrackets; + } + +// Syslog('N', " now parsing: \"%s\"",p); +// Syslog('N', "current comment: \"%s\"",result.comment); + + + /* OK, now we have result.comment filled with wat was outside + angle brackets, c pointing past the end of it, + p pointing to what is supposed to be address, with angle + brackets already removed */ +// Syslog('M', "parserfcaddr() 5"); + quotes = brackets = escaped = 0; + for (r = cleanbuf, x = &r; *p; p++) { + if (escaped) { + escaped=0; + *((*x)++)=*p; + } else /* process all special chars */ + if (isspace(*p)) { + if ((quotes) || (brackets)) + *((*x)++) = *p; + } else + switch (*p) { + case '\\': escaped=1; + /* pass backslash itself only inside quotes + and comments, or for the special cases + \" and \\ otherwise eat it away */ + if ((quotes) || (brackets)) + *((*x)++) = *p; + else if ((*(p+1)=='"') || (*(p+1)=='\\')) + *((*x)++) = *p; + break; + case '\"': quotes = !quotes; + *((*x)++) = *p; + break; + case '(': + brackets++; + x = &c; + break; + case ')': + if (brackets) + brackets--; + else + addrerror |= ADDR_UNMATCHED; + if (!brackets) + x = &r; + break; + default: + *((*x)++) = *p; + break; + } + } + *r = '\0'; + *c = '\0'; + if (brackets || quotes) + addrerror |= ADDR_UNMATCHED; + +// Syslog('N', " now parsing: \"%s\"",inbrackets); +// Syslog('N', "complete comment: \"%s\"",result.comment); +// Syslog('N', " addrerror: 0x%04x",addrerror); + +// Syslog('M', "parserfcaddr() 6"); + if (addrerror) + goto leave2; + + /* OK, now we have inangles buffer filled with the 'clean' address, + all comments removed, and result.comment is ready filled */ + + /* seach for special chars that are outside quotes */ + + firstat = lastat = percent = colon = comma = exclam = NULL; + quotes = 0; escaped = 0; + for (p = cleanbuf; *p; p++) + if (*p == '\\') + p++; + else if (*p == '\"') + quotes = !quotes; + else if (!quotes) + switch (*p) { + case '@': + if (!firstat) + firstat = p; + lastat = p; + break; + case '%': + percent = p; + break; + case ':': + colon = p; + break; + case ',': + comma = p; + break; + case '!': + if (!exclam) + exclam = p; + break; + } +// Syslog('M', "parserfcaddr() 7"); + if ((firstat == cleanbuf) && colon) { +// Syslog('N', "@aaa,@bbb:xxx@yyy construct"); + if (comma && (comma < colon)) { + *comma = '\0'; + r = comma + 1; +// Syslog('M', "parserfcaddr() 9"); + } else { + *colon = '\0'; + r = colon + 1; +// Syslog('M', "parserfcaddr() 10"); + } + t = firstat + 1; +// Syslog('M', "parserfcaddr() 11"); + } else if (lastat) { +// Syslog('N', "anything@somewhere construct"); + *lastat = '\0'; + r = cleanbuf; + t = lastat + 1; +// Syslog('M', "parserfcaddr() 12"); + } else if (exclam) { +// Syslog('N', "domain!something construct (without @'s)"); + *exclam = '\0'; + r = exclam + 1; + t = cleanbuf; +// Syslog('M', "parserfcaddr() 13"); + } else if (percent) { +// Syslog('N', "anything%%somewhere construct (without !'s and @'s)"); + *percent = '\0'; + r = cleanbuf; + t = percent + 1; +// Syslog('M', "parserfcaddr() 14"); + } else { +// Syslog('N', "remainder only present"); + /* unquote it if necessary */ + if ((*cleanbuf == '\"') && (*(p = (cleanbuf+strlen(cleanbuf)-1)) == '\"')) { + *p = '\0'; + r = cleanbuf + 1; + } else + r = cleanbuf; + t = NULL; +// Syslog('M', "parserfcaddr() 15"); + } +// Syslog('M', "parserfcaddr() 16"); + if (t && (*t != '\0')) + result.target = xstrcpy(t); +// Syslog('M', "parserfcaddr() 17"); + if (r && (*r != '\0')) + result.remainder = xstrcpy(r); +// Syslog('M', "parserfcaddr() 18"); + if (*combuf != '\0') + result.comment = xstrcpy(combuf); +// Syslog('M', "parserfcaddr() 19"); + +leave1: /* this is also normal exit */ +// Syslog('M', "parserfcaddr() leave1"); + free(cleanbuf); + free(combuf); + free(inbrackets); + free(outbrackets); +// Syslog('M', "going"); + return result; + +leave2: /* if error found on second stage, free */ +// Syslog('M', "parserfcaddr() leave2"); + free(cleanbuf); + free(combuf); +// Syslog('M', "going"); + return result; +} + diff --git a/lib/rfcdate.c b/lib/rfcdate.c new file mode 100644 index 00000000..c12eabdf --- /dev/null +++ b/lib/rfcdate.c @@ -0,0 +1,192 @@ +/***************************************************************************** + * + * File ..................: rfcdate.c + * Purpose ...............: Date utilities + * Last modification date : 30-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" +#include "clcomm.h" + + +static char *wdays[]={(char *)"Sun",(char *)"Mon",(char *)"Tue",(char *)"Wed", + (char *)"Thu",(char *)"Fri",(char *)"Sat"}; + +static char *months[]={(char *)"Jan",(char *)"Feb",(char *)"Mar", + (char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep", + (char *)"Oct",(char *)"Nov",(char *)"Dec"}; + + + +time_t parsefdate(char *str, void *now) +{ + struct tm tm, *pnow; + int i, rc; + time_t Now; + char *dummy, *pday, *pmon, *pyear, *phour, *pminute, *psecond; + char *buf; + + Now = time(NULL); + pnow = localtime(&Now); + dummy = pday = pmon = pyear = phour = pminute = psecond = NULL; + + if (str == NULL) { + WriteError("parsefdate entered NULL"); + return (time_t)0; + } + + buf = xstrcpy(str); + rc = 1; + memset(&tm, 0, sizeof(tm)); + + if ((strncasecmp(str,"Sun ",4) == 0) || + (strncasecmp(str,"Mon ",4) == 0) || + (strncasecmp(str,"Tue ",4) == 0) || + (strncasecmp(str,"Wed ",4) == 0) || + (strncasecmp(str,"Thu ",4) == 0) || + (strncasecmp(str,"Fri ",4) == 0) || + (strncasecmp(str,"Sat ",4) == 0)) { + /* + * SEAdog mode + */ + if ((dummy = strtok(str, " ")) != NULL) + if ((pday = strtok(NULL, " ")) != NULL) + if ((pmon = strtok(NULL, " ")) != NULL) + if ((pyear = strtok(NULL, " ")) != NULL) + if ((phour = strtok(NULL, ": ")) != NULL) + if ((pminute = strtok(NULL, ": ")) != NULL) + rc = 0; + psecond = xstrcpy((char *)"00"); + } else { + /* + * FTS-0001 Standard mode + */ + if ((pday = strtok(str, " ")) != NULL) + if ((pmon = strtok(NULL, " ")) != NULL) + if ((pyear = strtok(NULL, " ")) != NULL) + if ((phour = strtok(NULL, ": ")) != NULL) + if ((pminute = strtok(NULL, ": ")) != NULL) + if ((psecond = strtok(NULL, ": ")) != NULL) + rc = 0; + } + if (rc == 1) { + WriteError("Could not parse date \"%s\"", str); + return (time_t)0; + } + + tm.tm_sec = atoi(psecond); + tm.tm_min = atoi(pminute); + tm.tm_hour = atoi(phour); + tm.tm_mday = atoi(pday); + tm.tm_isdst = pnow->tm_isdst; + + for (i = 0; i < 12; i++) + if (strncasecmp(months[i], pmon, 3) == 0) + break; + tm.tm_mon = i; + + tm.tm_year = atoi(pyear); + if (tm.tm_year < 0) { + rc = 1; + } else if (tm.tm_year < 100) { /* Correct date field */ + while (pnow->tm_year - tm.tm_year > 50) { + tm.tm_year +=100; /* Sliding window adaption */ + } + } else if (tm.tm_year < 1900) { /* Field contains year like */ + rc = 2; /* Timed/Netmgr bug */ + } else { + tm.tm_year -= 1900; /* 4 Digit year field */ + rc = 2; + } + + /* + * Log if something isn't right + */ + if (rc) + Syslog('+', "fdate \"%s\" to %02d-%02d-%d %02d:%02d:%02d rc=%d", buf, + tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, + tm.tm_hour, tm.tm_min, tm.tm_sec, rc); + + free(buf); + return mktime(&tm) - (gmt_offset((time_t)0) * 60); +} + + + +char *rfcdate(time_t now) +{ + static char buf[40]; + struct tm ptm, gtm; + char sign; + int hr, min; + long offset; + + if (!now) + time(&now); + ptm = *localtime(&now); + + /* + * To get the timezone, compare localtime with GMT. + */ + gtm = *gmtime(&now); + + /* + * Assume we are never more than 24 hours away. + */ + offset = gtm.tm_yday - ptm.tm_yday; + if (offset > 1) + offset = -24; + else if (offset < -1) + offset = 24; + else + offset *= 24; + + /* + * Scale in the hours and minutes; ignore seconds. + */ + offset += gtm.tm_hour - ptm.tm_hour; + offset *= 60; + offset += gtm.tm_min - ptm.tm_min; + + if (offset <= 0) { + sign = '+'; + offset = -offset; + } else + sign = '-'; + hr = offset / 60L; + min = offset % 60L; + + sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d", wdays[ptm.tm_wday], ptm.tm_mday, months[ptm.tm_mon], + ptm.tm_year + 1900, ptm.tm_hour, ptm.tm_min, ptm.tm_sec, sign, hr, min); + return(buf); +} + + + diff --git a/lib/rfcmsg.c b/lib/rfcmsg.c new file mode 100644 index 00000000..c5afd82d --- /dev/null +++ b/lib/rfcmsg.c @@ -0,0 +1,168 @@ +/***************************************************************************** + * + * File ..................: rfcmsg.c + * Purpose ...............: RFC msg + * Last modification date : 14-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "common.h" +#include "clcomm.h" + + + +#ifndef BUFSIZ +#define BUFSIZ 512 +#endif + +#define KWDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_." + + + +rfcmsg *parsrfc(FILE *fp) +{ + int linecont=FALSE,newcont,firstline; + rfcmsg *start=NULL, *cur=NULL; + char buffer[BUFSIZ]; + char *p; + + while (bgets(buffer, BUFSIZ-1, fp) && strcmp(buffer,"\n")) { + newcont = (buffer[strlen(buffer)-1] != '\n'); + Syslog('M', "Line read: \"%s\" - %s continued", buffer,newcont?"to be":"not to be"); + if (linecont) { + Syslog('M', "this is a continuation of a long line"); + cur->val=xstrcat(cur->val,buffer); + } else { + if (isspace(buffer[0])) { + if (strspn(buffer," \t\n") == strlen(buffer)) { + Syslog('M', "breaking with blank-only line"); + break; + } + Syslog('M', "this is a continuation line"); + if (!cur) { + Syslog('M', "Wrong first line: \"%s\"",buffer); + cur = (rfcmsg *)malloc(sizeof(rfcmsg)); + start = cur; + cur->next = NULL; + cur->key = xstrcpy((char *)"X-Body-Start"); + cur->val = xstrcpy(buffer); + break; + } else + cur->val = xstrcat(cur->val,buffer); + } else { +// Syslog('M', "this is a header line"); + if (cur) { + firstline=FALSE; + (cur->next) = (rfcmsg *)malloc(sizeof(rfcmsg)); + cur = cur->next; + } else { + firstline = TRUE; + cur = (rfcmsg *)malloc(sizeof(rfcmsg)); + start = cur; + } + cur->next = NULL; + cur->key = NULL; + cur->val = NULL; + if (firstline && !strncmp(buffer,"From ",5)) { + Syslog('M', "This is a uucpfrom line"); + cur->key=xstrcpy((char *)"X-UUCP-From"); + cur->val=xstrcpy(buffer+4); + } else if ( !strncasecmp(buffer,"Cc:",3)) { + Syslog('M', "Cc: line"); + if (strchr(buffer+3,'@')) { + cur->key = xstrcpy((char *)"Cc"); + cur->val = xstrcpy(buffer+3); + } else { + Syslog('M', "FTN Cc: line: \"%s\"", buffer); + cur->key = xstrcpy((char *)"X-Body-Start"); + cur->val = xstrcpy(buffer); + break; + } + } else if ((p=strchr(buffer,':')) && (p > buffer) && /* ':' isn't 1st chr */ + isspace(*(p+1)) && /* space past ':' */ + /* at least one non blank char */ + (strspn(p+2, " \t\n") < strlen(p+2)) && (strspn(buffer,KWDCHARS) == (p-buffer))) { + *p='\0'; +// Syslog('M', "This is a regular header"); + cur->key = xstrcpy(buffer); + cur->val = xstrcpy(p+1); + } else { + Syslog('M', "Non-header line: \"%s\"",buffer); + cur->key = xstrcpy((char *)"X-Body-Start"); + cur->val = xstrcpy(buffer); + break; + } + } + } + linecont = newcont; + } + return(start); +} + + + +void tidyrfc(rfcmsg *msg) +{ + rfcmsg *nxt; + + for (; msg; msg=nxt) { + nxt = msg->next; + if (msg->key) + free(msg->key); + if (msg->val) + free(msg->val); + free(msg); + } + return; +} + + + +void dumpmsg(rfcmsg *msg, FILE *fp) +{ + char *p; + + p = hdr((char *)"X-Body-Start",msg); + for (; msg; msg=msg->next) + if (strcasecmp(msg->key, "X-Body-Start")) { + if (!strcasecmp(msg->key, "X-UUCP-From")) + fputs("From", fp); + else { + fputs(msg->key,fp); + fputs(":",fp); + } + fputs(msg->val,fp); + } + fputs("\n",fp); + if (p) + fputs(p,fp); + return; +} + + diff --git a/lib/semafore.c b/lib/semafore.c new file mode 100644 index 00000000..5cae6a19 --- /dev/null +++ b/lib/semafore.c @@ -0,0 +1,73 @@ +/***************************************************************************** + * + * File ..................: semafore.c + * Purpose ...............: Create, test and remove semafore's + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +void CreateSema(char *sem) +{ + char temp[40]; + + sprintf(temp, "%s", SockR("SECR:1,%s;", sem)); + if (strncmp(temp, "200", 3) == 0) + WriteError("Can't create semafore %s", sem); +} + + + +void RemoveSema(char *sem) +{ + char temp[40]; + + sprintf(temp, "%s", SockR("SERM:1,%s;", sem)); + if (strncmp(temp, "200", 3) == 0) + WriteError("Can't remove semafore %s", sem); +} + + + +int IsSema(char *sem) +{ + char temp[40]; + + sprintf(temp, "%s", SockR("SEST:1,%s;", sem)); + if (strncmp(temp, "200", 3) == 0) { + WriteError("Can't read semafore %s", sem); + return FALSE; + } + strtok(temp, ","); + return atoi(strtok(NULL, ";")); +} + + diff --git a/lib/signame.c b/lib/signame.c new file mode 100644 index 00000000..8f63d4c7 --- /dev/null +++ b/lib/signame.c @@ -0,0 +1,95 @@ +/***************************************************************************** + * + * File ..................: signame.c + * Purpose ...............: Signal names + * Last modification date : 19-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" + + +/* + * Signal handler signal names. + */ + +#ifdef __i386__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __PPC__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __sparc__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGLOST", "SIGUSR1", "SIGUSR2"}; +#endif + +#ifdef __alpha__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGINFO", "SIGUSR1", "SIGUSR2"}; + + +#endif + diff --git a/lib/smtp.c b/lib/smtp.c new file mode 100644 index 00000000..6bdc7619 --- /dev/null +++ b/lib/smtp.c @@ -0,0 +1,213 @@ +/***************************************************************************** + * + * File ..................: smtp.c + * Purpose ...............: MBSE BBS Internet Library + * Last modification date : 23-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "mbinet.h" + + +static int smtpsock = -1; /* TCP/IP socket */ +struct hostent *shp; /* Host info remote */ +struct servent *ssp; /* Service information */ +struct sockaddr_in smtp_loc; /* For local socket address */ +struct sockaddr_in smtp_rem; /* For remote socket address */ + + + +int smtp_connect(void) +{ + int addrlen; + char *p, temp[40]; + + if (smtpsock != -1) + return smtpsock; + + if (!strlen(CFG.smtpnode)) { + WriteError("SMTP: host not configured"); + return -1; + } + + Syslog('+', "SMTP: connecting host: %s", CFG.smtpnode); + memset(&smtp_loc, 0, sizeof(struct sockaddr_in)); + memset(&smtp_rem, 0, sizeof(struct sockaddr_in)); + + smtp_rem.sin_family = AF_INET; + + if ((shp = gethostbyname(CFG.smtpnode)) == NULL) { + WriteError("$SMTP: can't find host %s", CFG.smtpnode); + return -1; + } + + smtp_rem.sin_addr.s_addr = ((struct in_addr *)(shp->h_addr))->s_addr; + + if ((ssp = getservbyname("smtp", "tcp")) == NULL) { + WriteError("$SMTP: can't find service port for smtp/tcp"); + return -1; + } + smtp_rem.sin_port = ssp->s_port; + + if ((smtpsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + WriteError("$SMTP: unable to create tcp socket"); + return -1; + } + + if (connect(smtpsock, (struct sockaddr *)&smtp_rem, sizeof(struct sockaddr_in)) == -1) { + WriteError("$SMTP: can't connect tcp socket"); + return -1; + } + + addrlen = sizeof(struct sockaddr_in); + + if (getsockname(smtpsock, (struct sockaddr *)&smtp_loc, &addrlen) == -1) { + WriteError("$SMTP: unable to read socket address"); + return -1; + } + + p = smtp_receive(); + if (strlen(p) == 0) { + WriteError("SMTP: no response"); + smtp_close(); + return -1; + } + + if (strncmp(p, "220", 3)) { + WriteError("SMTP: bad response: %s", p); + smtp_close(); + return -1; + } + + Syslog('+', "SMTP: %s", p); + + sprintf(temp, "HELO %s\r\n", CFG.sysdomain); + if (smtp_cmd(temp, 250)) { + smtp_close(); + return -1; + } + + return smtpsock; +} + + + +int smtp_send(char *buf) +{ + if (smtpsock == -1) + return -1; + + if (send(smtpsock, buf, strlen(buf), 0) != strlen(buf)) { + WriteError("$SMTP: socket send failed"); + return -1; + } + return 0; +} + + + +/* + * Return empty buffer if something went wrong, else the complete + * dataline is returned + */ +char *smtp_receive(void) +{ + static char buf[SS_BUFSIZE]; + int i, j; + + memset((char *)&buf, 0, SS_BUFSIZE); + i = 0; + while ((strchr(buf, '\n')) == NULL) { + j = recv(smtpsock, &buf[i], SS_BUFSIZE-i, 0); + if (j == -1) { + WriteError("$SMTP: error reading socket"); + memset((char *)&buf, 0, SS_BUFSIZE); + return buf; + } + i += j; + } + + for (i = 0; i < strlen(buf); i++) { + if (buf[i] == '\n') + buf[i] = '\0'; + if (buf[i] == '\r') + buf[i] = '\0'; + } + + return buf; +} + + + +int smtp_close(void) +{ + if (smtpsock == -1) + return 0; + + smtp_cmd((char *)"QUIT\r\n", 221); + + if (shutdown(smtpsock, 1) == -1) { + WriteError("$SMTP: can't close socket"); + return -1; + } + + smtpsock = -1; + Syslog('+', "SMTP: closed"); + return 0; +} + + + +/* + * Send command to the SMTP service. On error return the + * received error number, else return zero. + */ +int smtp_cmd(char *cmd, int resp) +{ + char *p, rsp[6]; + + if (smtp_send(cmd) == -1) + return -1; + + sprintf(rsp, "%d", resp); + p = smtp_receive(); + + if (strncmp(p, rsp, strlen(rsp))) { + WriteError("SMTP> %s", cmd); + WriteError("SMTP< %s", p); + memset(&resp, 0, sizeof(rsp)); + strncpy(rsp, p, 3); + return atoi(rsp); + } + return 0; +} + + + diff --git a/lib/strcasestr.c b/lib/strcasestr.c new file mode 100644 index 00000000..35bc82db --- /dev/null +++ b/lib/strcasestr.c @@ -0,0 +1,25 @@ + +#include "libs.h" + +#ifndef HAVE_STRCASESTR + +char *strcasestr(char *a, char *b) +{ + char *p,*max; + int l; + + if (a && b) { + + l=strlen(b); + max=a+strlen(a)-l; + for (p=a;p<=max;p++) + if (!strncasecmp(p,b,l)) return(p); + return((char *)0); + } + else { + return ((char *) 0); + } +} + +#endif + diff --git a/lib/structs.h b/lib/structs.h new file mode 100644 index 00000000..a80083bd --- /dev/null +++ b/lib/structs.h @@ -0,0 +1,1546 @@ +/***************************************************************************** + * + * File ..................: structs.h + * Purpose ...............: MBSE BBS Global structure + * Last modification date : 06-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#ifndef _STRUCTS_H +#define _STRUCTS_H + + + +/***************************************************************************** + * + * Global definitions and structures. + * + */ + +#define Copyright "Copyright (C) 1997-2001 Michiel Broek, All Rights Reserved" +#define ShortRight "Copyright (C) 1997-2001 M. Broek" + + +typedef enum {YES, NO, ASK, ONLY} ASKTYPE; +typedef enum {LOCALMAIL, NETMAIL, ECHOMAIL, NEWS} MSGTYPE; +typedef enum {BOTH, PRIVATE, PUBLIC, RONLY, FTNMOD, USEMOD} MSGKINDSTYPE; +typedef enum {IGNORE, CREATE, KILL} ORPHANTYPE; +typedef enum {SEND, RECV, BOTHDIR} NODETYPE; +typedef enum {POTS, ISDN, NETWORK, LOCAL} LINETYPE; +typedef enum {BROWSING, DOWNLOAD, UPLOAD, READ_POST, DOOR, SYSOPCHAT, + FILELIST, TIMEBANK, SAFE, WHOSON, OLR} DOESTYPE; +typedef enum {I_AVT0, I_ANSI, I_VT52, I_VT100, I_TTY} ITERM; +typedef enum {I_DZA, I_ZAP, I_ZMO, I_SLK, I_KER} IPROT; +typedef enum {E_NOISP, E_TMPISP, E_PRMISP} EMODE; +typedef enum {AREAMGR, FILEMGR, EMAIL} SERVICE; +typedef enum {FEEDINN, FEEDRNEWS, FEEDUUCP} NEWSFEED; + + + +/*********************************************************************** + * + * Nodelist definitions. + * + */ + +#define MAXUFLAGS 16 + + +/* + * Nodelist index file to nodelists. (node.files) + */ +typedef struct _nlfil { + char filename[13]; /* Nodelist filename */ + char domain[13]; /* Domain name */ + unsigned short number; /* File number */ +} nlfil; + + + +/* + * Nodelist index file for node lookup. (node.index) + */ +typedef struct _nlidx { + unsigned short zone; /* Zone number */ + unsigned short net; /* Net number */ + unsigned short node; /* Node number */ + unsigned short point; /* Point number */ + unsigned short region; /* Region of node */ + unsigned short upnet; /* Uplink net */ + unsigned short upnode; /* Uplink node */ + unsigned char type; /* Node type */ + unsigned char pflag; /* Node status */ + unsigned short fileno; /* Nodelist number */ + long offset; /* Offset in nodelist */ +} nlidx; + + + +/* + * Nodelist usernames index file. (node.users) + */ +typedef struct _nlusr { + char user[36]; /* User name */ + long record; /* Record in index */ +} nlusr; + + + +/* + * type values + */ +#define NL_NONE 0 +#define NL_ZONE 1 +#define NL_REGION 2 +#define NL_HOST 3 +#define NL_HUB 4 +#define NL_NODE 5 +#define NL_POINT 6 + + + +/* + * pflag values, all bits zero, node may be dialed analogue FTS-0001. + * the rest are special cases. + */ +#define NL_DOWN 0x01 /* Node is Down */ +#define NL_HOLD 0x02 /* Node is Hold */ +#define NL_PVT 0x04 /* Private node */ +#define NL_DUMMY 0x08 /* Dummy entry */ +#define NL_ISDN 0x10 /* ISDN Only node */ +#define NL_TCPIP 0x20 /* TCP/IP Only node */ + + +/************************************************************************ + * + * Other BBS structures + * + */ + + +/* + * Security structure + */ +typedef struct _security { + unsigned int level; /* Security level */ + unsigned long flags; /* Access flags */ + unsigned long notflags; /* No Access flags */ +} securityrec; + + + +/* + * Fidonet 5d address structure + */ +typedef struct _fidoaddr { + unsigned short zone; /* Zone number */ + unsigned short net; /* Net number */ + unsigned short node; /* Node number */ + unsigned short point; /* Point number */ + char domain[13]; /* Domain name (no dots) */ +} fidoaddr; + + + +/* + * Connected system structure + */ +typedef struct _sysconnect { + fidoaddr aka; /* Address of system */ + unsigned short sendto; /* If we send to system */ + unsigned short receivefrom; /* If we receive from */ + unsigned pause : 1; /* If system is paused */ + unsigned cutoff : 1; /* Cutoff by moderator */ + unsigned spare3 : 1; + unsigned spare4 : 1; + unsigned spare5 : 1; + unsigned spare6 : 1; + unsigned spare7 : 1; + unsigned spare8 : 1; + unsigned spare9 : 1; /* Forces enough space */ +} sysconnect; + + + int Diw; /* Day in week index */ + int Miy; /* Month in year index */ + + +/* + * Statistic counters structure + */ +typedef struct _statcnt { + unsigned long tdow[7]; /* Days of current week */ + unsigned long ldow[7]; /* Days of previous week */ + unsigned long tweek; /* Week total counters */ + unsigned long lweek; /* Last week counters */ + unsigned long month[12]; /* Monthly total counters */ + unsigned long total; /* The ever growing total */ +} statcnt; + + + +/* + * Find replace match structure (phone translation etc). + */ +typedef struct _dual { + char match[21]; /* String to match */ + char repl[21]; /* To replace with */ +} dual; + + + +/* + * Downloaded FTP files (~/var/download.ftp) + */ +typedef struct _downftp { + unsigned long Areanr; + char Name[13]; +} downftp; + + +/**************************************************************************** + * + * Datafile records structure in $MBSE_ROOT/etc + * + */ + + +/* + * Task Manager configuration (task.data) + */ +struct taskrec { + float maxload; /* Maximum system load */ + + char isp_connect[81]; /* ISP connect command */ + char isp_hangup[81]; /* ISP hangup command */ + char isp_ping1[41]; /* ISP ping host 1 */ + char isp_ping2[41]; /* ISP ping host 2 */ + + char zmh_start[6]; /* Zone Mail Hour start */ + char zmh_end[6]; /* Zone Mail Hour end */ + + char cmd_mailout[81]; /* mailout command */ + char cmd_mailin[81]; /* mailin command */ + char cmd_newnews[81]; /* newnews command */ + char cmd_mbindex1[81]; /* mbindex command 1 */ + char cmd_mbindex2[81]; /* mbindex command 2 */ + char cmd_mbindex3[81]; /* mbindex command 3 */ + char cmd_msglink[81]; /* msglink command */ + char cmd_reqindex[81]; /* reqindex command */ + + int max_pots; /* maximum pots calls */ + int max_isdn; /* maximum ISDN calls */ + int max_tcp; /* maximum TCP/IP calls */ + + unsigned ipblocks : 1; /* internet blocks dial */ + unsigned debug : 1; /* debugging on/off */ +}; + + + +/* + * Special mail services (service.data) + */ +struct servicehdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last updated at */ +}; + +struct servicerec { + char Service[16]; /* Service name */ + int Action; /* Service action */ + unsigned Active : 1; /* Service is active */ + unsigned Deleted : 1; /* Service is deleted */ +}; + + + +/* + * Domain translation (domain.data) + */ +struct domhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last updated at */ +}; + +struct domrec { + char ftndom[61]; /* Fidonet domain */ + char intdom[61]; /* Internet domain */ + unsigned Active : 1; /* Domain is active */ + unsigned Deleted : 1; /* Domain is deleted */ +}; + + + +/* + * Users Control Structures (users.data) + */ +struct userhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct userrec { + char sUserName[36]; /* User First and Last Name */ + char Name[9]; /* Unix name */ + unsigned long iPassword; /* Users Password (CRC) */ + char sVoicePhone[20]; /* Voice Number */ + char sDataPhone[20]; /* Data/Business Number */ + char sLocation[28]; /* Users Location */ + char address[3][41]; /* Users address */ + char sDateOfBirth[12]; /* Date of Birth */ + time_t tFirstLoginDate; /* Date of First Login */ + time_t tLastLoginDate; /* Date of Last Login */ + securityrec Security; /* User Security Level */ + char sComment[81]; /* User Comment */ + char sExpiryDate[12]; /* User Expiry Date */ + securityrec ExpirySec; /* Expiry Security Level */ + char sSex[8]; /* Users Sex */ + + unsigned Hidden : 1; /* Hide User from Lists */ + unsigned HotKeys : 1; /* Hot-Keys ON/OFF */ + unsigned GraphMode : 1; /* ANSI Mode ON/OFF */ + unsigned Deleted : 1; /* Deleted Status */ + unsigned NeverDelete : 1; /* Never Delete User */ + unsigned Chat : 1; /* Has IEMSI Chatmode */ + unsigned LockedOut : 1; /* User is locked out */ + unsigned DoNotDisturb : 1; /* DoNot disturb */ + unsigned Cls : 1; /* CLS on/off */ + unsigned More : 1; /* More prompt */ + unsigned FsMsged : 1; /* Fullscreen editor */ + unsigned MailScan : 1; /* New Mail scan */ + unsigned Guest : 1; /* Is guest account */ + unsigned OL_ExtInfo : 1; /* OLR extended msg info */ + int iTotalCalls; /* Total number of calls */ + int iTimeLeft; /* Time left today */ + int iConnectTime; /* Connect time this call */ + int iTimeUsed; /* Time used today */ + int iScreenLen; /* User Screen Length */ + time_t tLastPwdChange; /* Date last password chg */ + unsigned iHangUps; /* Total improper hangups */ + long Credit; /* Users credit */ + int Paged; /* Times paged today */ + int OfflineFmt; /* Offline Reader format */ + int LastPktNum; /* Todays Last packet number*/ + char Archiver[6]; /* Archiver to use */ + + int iLastFileArea; /* Number of last file area */ + int iLastFileGroup; /* Number of last file group*/ + char sProtocol[21]; /* Users default protocol */ + unsigned long Downloads; /* Total number of d/l's */ + unsigned long Uploads; /* Total number of uploads */ + unsigned long UploadK; /* Upload KiloBytes */ + unsigned long DownloadK; /* Download KiloBytes */ + long DownloadKToday; /* KB Downloaded today */ + long UploadKToday; /* KB Uploaded today */ + int iTransferTime; /* Last file transfer time */ + int iLastMsgArea; /* Number of last msg area */ + int iLastMsgGroup; /* Number of last msg group */ + int iPosted; /* Number of msgs posted */ + int iLanguage; /* Current Language */ + char sHandle[36]; /* Users Handle */ + int iStatus; /* WhosDoingWhat status */ + int DownloadsToday; /* Downloads today */ + int CrtDef; /* IEMSI Terminal emulation */ + int Protocol; /* IEMSI protocol */ + unsigned IEMSI : 1; /* Is this a IEMSI session */ + unsigned ieMNU : 1; /* Can do ASCII download */ + unsigned ieTAB : 1; /* Can handle TAB character */ + unsigned ieASCII8 : 1; /* Can handle 8-bit IBM-PC */ + unsigned ieNEWS : 1; /* Show bulletins */ + unsigned ieFILE : 1; /* Check for new files */ + unsigned Email : 1; /* Has private email box */ + char Password[15]; /* Plain password */ +}; + + + +/* + * System Control Structures (sysinfo.data) + */ +struct sysrec { + unsigned long SystemCalls; /* Total # of system calls */ + unsigned long Pots; /* POTS calls */ + unsigned long ISDN; /* ISDN calls */ + unsigned long Network; /* Network (internet) calls*/ + unsigned long Local; /* Local calls */ + unsigned long ADSL; /* ADSL calls */ + time_t StartDate; /* Start Date of BBS */ + char LastCaller[36]; /* Last Caller to BBS */ +}; + + + +/* + * Protocol Control Structure (protocol.data) + */ +struct prothdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct prot { + char ProtKey[2]; /* Protocol Key */ + char ProtName[21]; /* Protocol Name */ + char ProtUp[51]; /* Upload Path & Binary */ + char ProtDn[51]; /* Download Path & Bianry */ + unsigned Available : 1; /* Available/Not Available */ + unsigned Batch : 1; /* Batching protocol */ + unsigned Bidir : 1; /* Bi Directional */ + unsigned Deleted : 1; /* Protocol is deleted */ + unsigned Internal : 1; /* Internal protocol */ + char Advice[31]; /* Small advice to user */ + int Efficiency; /* Protocol efficiency in % */ + securityrec Level; /* Sec. level to select */ +}; + + + +/* + * Oneliners Control Structure (oneline.data) + */ +struct onelinehdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of record */ +}; + +struct oneline { + char Oneline[81]; /* Oneliner text */ + char UserName[36]; /* User who wrote oneliner */ + char DateOfEntry[12]; /* Date of oneliner entry */ + unsigned Available : 1; /* Deleted Status */ +}; + + + +/* + * File Areas Control Structure (fareas.data) + */ +struct fileareashdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct fileareas { + char Name[45]; /* Filearea Name */ + char Path[81]; /* Filearea Path */ + securityrec DLSec; /* Download Security */ + securityrec UPSec; /* Upload Security */ + securityrec LTSec; /* List Security */ + int Age; /* Age to access area */ + unsigned New : 1; /* New Files Check */ + unsigned Dupes : 1; /* Check for Duplicates */ + unsigned Free : 1; /* All files are Free */ + unsigned DirectDL : 1; /* Direct Download */ + unsigned PwdUP : 1; /* Password Uploads */ + unsigned FileFind : 1; /* FileFind Scan */ + unsigned AddAlpha : 1; /* Add New files sorted */ + unsigned Available : 1; /* Area is available */ + unsigned CDrom : 1; /* Area is on CDrom */ + unsigned FileReq : 1; /* Allow File Requests */ + char BbsGroup[13]; /* BBS Group */ + char Password[21]; /* Area Password */ + unsigned DLdays; /* Move not DL for days */ + unsigned FDdays; /* Move if FD older than */ + unsigned MoveArea; /* Move to Area */ + int Cost; /* File Cost */ + char FilesBbs[65]; /* Path to files.bbs if CD */ + char NewGroup[13]; /* Newfiles scan group */ + char Archiver[6]; /* Archiver for area */ + unsigned Upload; /* Upload area */ +}; + + + +/* + * Index file for fast search of file requests (request.index) + */ +struct FILEIndex { + char Name[13]; /* Short DOS name */ + char LName[81]; /* Long filename */ + long AreaNum; /* File area number */ + long Record; /* Record in database */ +}; + + + +/* + * File Record Control Structure (fdb#.data) + */ +struct FILERecord { + char Name[13]; /* DOS style filename */ + char LName[81]; /* Long filename */ + char xTicArea[13]; /* Tic area file came in */ + off_t Size; /* File Size */ + unsigned long Crc32; /* File CRC-32 */ + char Uploader[36]; /* Uploader name */ + time_t UploadDate; /* Date/Time uploaded */ + time_t FileDate; /* Real file date */ + time_t LastDL; /* Last Download date */ + unsigned long TimesDL; /* Times file was dl'ed */ + unsigned long TimesFTP; /* Times file was FTP'ed */ + unsigned long TimesReq; /* Times file was frequed */ + char Password[16]; /* File password */ + char Desc[25][49]; /* file description */ + int Cost; /* File cost */ + unsigned Free : 1; /* Free File */ + unsigned Deleted : 1; /* Deleted */ + unsigned Missing : 1; /* Missing */ + unsigned NoKill : 1; /* Cannot be deleted */ + unsigned Announced : 1; /* File is announced */ +}; + + + +/* + * BBS List Control Structure (bbslist.data) + */ +struct bbslisthdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct bbslist { + char UserName[36]; /* User Name */ + char DateOfEntry[12]; /* Entry date */ + char Verified[12]; /* Last Verify date */ + unsigned Available : 1; /* Available Status */ + char BBSName[41]; /* BBS Name */ + int Lines; /* Nr of phone lines */ + char Phone[5][21]; /* BBS phone number */ + char Speeds[5][41]; /* Speeds for each line */ + fidoaddr FidoAka[5]; /* Fidonet Aka's */ + char Software[20]; /* BBS Software */ + char Sysop[36]; /* Name of Sysop */ + int Storage; /* Storage amount in megs */ + char Desc[2][81]; /* Description */ + char IPaddress[51]; /* IP or domain name */ + char Open[21]; /* Online time */ +}; + + + +/* + * Last Callers Control Structure (lastcall.data) + */ +struct lastcallershdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct lastcallers { + char UserName[36]; /* User Name */ + char Handle[36]; /* User Handle */ + char TimeOn[6]; /* Time user called bbs */ + int CallTime; /* Time this call */ + char Device[10]; /* Device user used */ + int Calls; /* Total calls to bbs */ + unsigned int SecLevel; /* Users security level */ + char Speed[21]; /* Caller speed */ + unsigned Hidden : 1; /* Hidden or Not at time */ + unsigned Download : 1; /* If downloaded */ + unsigned Upload : 1; /* If uploaded */ + unsigned Read : 1; /* If read messages */ + unsigned Wrote : 1; /* If wrote a message */ + unsigned Chat : 1; /* If did chat */ + unsigned Olr : 1; /* If used Offline Reader */ + char Location[28]; /* User Location */ +}; + + + +/* + * System Control Structure (config.data) + */ +struct sysconfig { + /* Registration Info */ + char sysop_name[36]; /* Sysop Name */ + char bbs_name[36]; /* BBS Name */ + char sysop[9]; /* Unix Sysop name */ + char location[36]; /* System location */ + char bbsid[9]; /* QWK/Bluewave BBS ID */ + char bbsid2[3]; /* Omen filename */ + char sysdomain[36]; /* System Domain name */ + char comment[56]; /* Do what you like here */ + char origin[51]; /* Default origin line */ + + /* FileNames */ + char error_log[15]; /* Name of Error Log */ + char default_menu[15]; /* Default Menu */ + char current_language[15]; /* Default Language */ + char chat_log[15]; /* Chat Logfile */ + char welcome_logo[15]; /* Welcome Logofile */ + + /* Paths */ + char rnewspath[65]; /* Path to rnews */ + char bbs_menus[65]; /* Default Menus */ + char bbs_txtfiles[65]; /* Default Textfiles */ + char nntpnode[65]; /* NNTP server */ + char xbbs_filebase[65]; + char xbbs_language[65]; + char req_magic[65]; /* Request magic directory */ + char bbs_usersdir[65]; /* Users Home Dir Base */ + char nodelists[65]; /* Nodelists */ + char inbound[65]; /* Inbound directory */ + char pinbound[65]; /* Protected inbound */ + char outbound[65]; /* Outbound */ + char xsequencer[65]; + char dospath[65]; /* DOS path */ + char uxpath[65]; /* Unix path */ + + /* Allfiles/Newfiles */ + char ftp_base[65]; /* FTP root */ + int newdays; /* New files since */ + securityrec security; /* Max level list */ + + unsigned addr4d : 1; /* Use 4d addressing */ + unsigned leavecase : 1; /* Leave outbound case */ + + /* BBS Globals */ + int max_login; /* Maximum login attempts */ + unsigned NewAreas : 1; /* Notify if new msg areas */ + unsigned elite_mode : 1; /* Allow new users/Private? */ + unsigned slow_util : 1; /* Run utils slowly */ + unsigned exclude_sysop : 1; /* Exclude Sysop from lists */ + unsigned xUseSysDomain : 1; + unsigned xChkMail : 1; + unsigned iConnectString : 1; /* Display Connect String */ + unsigned iAskFileProtocols : 1; /* Ask user FileProtocols */ + /* before every d/l or u/l */ + unsigned sysop_access; /* Sysop Access Security */ + int password_length; /* Minimum Password Length */ + long bbs_loglevel; /* Logging level for BBS */ + int iPasswd_Char; /* Password Character */ + int iQuota; /* User homedir quota in MB */ + int idleout; /* Idleout Value */ + int CityLen; /* Minimum city length */ + short OLR_NewFileLimit; /* Limit Newfilesscan days */ + unsigned iCRLoginCount; /* Count login Enters */ + + /* New Users */ + securityrec newuser_access; /* New Users Access level */ + int OLR_MaxMsgs; /* OLR Max nr Msgs download */ + unsigned iCapUserName : 1; /* Capitalize Username */ + unsigned iAnsi : 1; /* Ask Ansi */ + unsigned iSex : 1; /* Ask Sex */ + unsigned iDataPhone : 1; /* Ask Data Phone */ + unsigned iVoicePhone : 1; /* Ask Voice Phone */ + unsigned iHandle : 1; /* Ask Alias/Handle */ + unsigned iDOB : 1; /* Ask Date of Birth */ + unsigned iTelephoneScan : 1; /* Telephone Scan */ + unsigned iLocation : 1; /* Ask Location */ + unsigned iCapLocation : 1; /* Capitalize Location */ + unsigned iHotkeys : 1; /* Ask Hot-Keys */ + unsigned GiveEmail : 1; /* Give user email */ + unsigned AskAddress : 1; /* Ask Home Address */ + unsigned iOneName : 1; /* Allow one user name */ + unsigned iCrashLevel; /* User level for crash mail*/ + unsigned iAttachLevel; /* User level for fileattach*/ + + /* Colors */ + int TextColourF; /* Text Colour Foreground */ + int TextColourB; /* Text Colour Background */ + int UnderlineColourF; /* Underline Text Colour */ + int UnderlineColourB; /* Underline Colour */ + int InputColourF; /* Input Text Colour */ + int InputColourB; /* Input Text Colour */ + int CRColourF; /* CR Text Colour */ + int CRColourB; /* CR Text Colour */ + int MoreF; /* More Prompt Text Colour */ + int MoreB; /* More Prompt Text Colour */ + int HiliteF; /* Hilite Text Colour */ + int HiliteB; /* Hilite Text Colour */ + int FilenameF; /* Filename Colour */ + int FilenameB; /* Filename Colour */ + int FilesizeF; /* Filesize Colour */ + int FilesizeB; /* Filesize Colour */ + int FiledateF; /* Filedate Colour */ + int FiledateB; /* Filedate Colour */ + int FiledescF; /* Filedesc Colour */ + int FiledescB; /* Filedesc Colour */ + int MsgInputColourF; /* MsgInput Filename Colour */ + int MsgInputColourB; /* MsgInput Filename Colour */ + + /* Next User Door */ + char sNuScreen[50]; /* Next user txtfile */ + char sNuQuote[81]; /* next user quote */ + + /* Safe Cracker Door */ + int iSafeFirstDigit; /* Safe Door First Digit */ + int iSafeSecondDigit; /* Safe Door Second Digit */ + int iSafeThirdDigit; /* Safe Door Third Digit */ + int iSafeMaxTrys; /* Max trys per day */ + int iSafeMaxNumber; /* Maximum Safe Number */ + unsigned iSafeNumGen : 1; /* Use number generator */ + char sSafePrize[81]; /* Safe Prize */ + char sSafeWelcome[81]; /* Safe welcome file */ + char sSafeOpened[81]; /* Opended safe file */ + + /* Sysop Paging */ + int iPageLength; /* Page Length in Seconds */ + int iMaxPageTimes; /* Max Pages per call */ + unsigned iAskReason : 1; /* Ask Reason */ + int iSysopArea; /* Msg Area if Sysop not in */ + unsigned iExternalChat : 1; /* Use External Chat */ + char sExternalChat[50]; /* External Chat Program */ + unsigned iAutoLog : 1; /* Log Chats ? */ + char sChatDevice[20]; /* Chat Device */ + unsigned iChatPromptChk; /* Check for chat at prompt */ + unsigned iStopChatTime; /* Stop time during chat */ + char cStartTime[7][6]; /* Starting Times */ + char cStopTime[7][6]; /* Stop Times */ + char sCallScript[51]; /* Sysop External Call scr. */ + + /* Mail Options */ + char xquotestr[11]; /* Quote String */ + + /* Time Bank Door */ + int iMaxTimeBalance; /* Users Time Balance */ + int iMaxTimeWithdraw; /* Max Time WithDrawel */ + int iMaxTimeDeposit; /* Max Time Deposit Per day */ + int iMaxByteBalance; /* Users Time Balance */ + int iMaxByteWithdraw; /* Max Time WithDrawel */ + int iMaxByteDeposit; /* Max Time Deposit Per dat */ + unsigned xNewBytes : 1; + char sTimeRatio[7]; /* User Time Ratio,Returned */ + char sByteRatio[7]; /* User Time Ratio,Returned */ + + long new_groups; /* Maximum newfiles groups */ + int new_split; /* Split reports at KB. */ + int new_force; /* Force split at KB. */ + char startname[9]; /* BBS startup name */ + char extra4[239]; + + /* TIC Processing */ + unsigned ct_KeepDate : 1; /* Keep Filedate */ + unsigned ct_KeepMgr : 1; /* Keep Mgr netmails */ + unsigned ct_ResFuture : 1; /* Reset Future filedates */ + unsigned ct_LocalRep : 1; /* Respond to local requests*/ + unsigned ct_ReplExt : 1; /* Replace Extension */ + unsigned ct_PlusAll : 1; /* Areamgr: allow +%* */ + unsigned ct_Notify : 1; /* Areamgr: Notify on/off */ + unsigned ct_Passwd : 1; /* Areamgr: Passwd change */ + unsigned ct_Message : 1; /* Areamgr: Msg file on/off */ + unsigned ct_TIC : 1; /* Areamgr: TIC files on/off*/ + unsigned ct_Pause : 1; /* Areamgr: Allow Pause */ + char logfile[15]; /* System Logfile */ + int OLR_MaxReq; /* Max nr of Freq's */ + int tic_days; /* Keep on hold for n days */ + char hatchpasswd[21]; /* Internal Hatch Passwd */ + unsigned long drspace; /* Minimum free drivespace */ + char xmgrname[5][21]; /* Areamgr names */ + long tic_systems; /* Systems in database */ + long tic_groups; /* Groups in database */ + long tic_dupes; /* TIC dupes dabase size */ + char badtic[65]; /* Bad TIC's path */ + char ticout[65]; /* TIC queue */ + + /* Mail Tosser */ + char pktdate[65]; /* pktdate by Tobias Ernst */ + int maxpktsize; /* Maximum packet size */ + int maxarcsize; /* Maximum archive size */ + int toss_old; /* Reject older then days */ + char xtoss_log[11]; + long util_loglevel; /* Logging level for utils */ + char badboard[65]; /* Bad Mail board */ + char dupboard[65]; /* Dupe Mail board */ + char popnode[65]; /* Node with pop3 boxes */ + char smtpnode[65]; /* SMTP node */ + int toss_days; /* Keep on hold */ + int toss_dupes; /* Dupes in database */ + int defmsgs; /* Default purge messages */ + int defdays; /* Default purge days */ + int freespace; /* Free diskspace in MBytes */ + long toss_systems; /* Systems in database */ + long toss_groups; /* Groups in database */ + char xareamgr[5][21]; /* Areamgr names */ + + /* Flags */ + char fname[32][17]; /* Name of the access flags */ + fidoaddr aka[40]; /* Fidonet AKA's */ + unsigned short akavalid[40]; /* Fidonet AKA valid/not */ + + long cico_loglevel; /* Mailer loglevel */ + long timeoutreset; /* Reset timeout */ + long timeoutconnect; /* Connect timeout */ + long dialdelay; /* Delay between calls */ + unsigned NoFreqs : 1; /* Don't allow requests */ + unsigned NoCall : 1; /* Don't call */ + unsigned NoHold : 1; /* Don't send hold mail */ + unsigned NoPUA : 1; /* Don't Pickup All */ + unsigned NoEMSI : 1; /* Don't do EMSI */ + unsigned NoWazoo : 1; /* Don't do Yooho/2U2 */ + unsigned NoZmodem : 1; /* Don't do Zmodem */ + unsigned NoZedzap : 1; /* Don't do Zedzap */ + unsigned xNoJanus : 1; + unsigned NoHydra : 1; /* Don't do Hydra */ + unsigned NoTCP : 1; /* Don't do TCP/IP */ + char Phone[21]; /* Default phonenumber */ + unsigned long Speed; /* Default linespeed */ + char Flags[31]; /* Default EMSI flags */ + int Req_Files; /* Maximum files request */ + int Req_MBytes; /* Maximum MBytes request */ + char extra5[96]; + dual phonetrans[40]; /* Phone translation table */ + + /* FTP Daemon */ + int ftp_limit; /* Connections limit */ + int ftp_loginfails; /* Maximum login fails */ + unsigned ftp_compress : 1; /* Allow compress */ + unsigned ftp_tar : 1; /* Allow tar */ + unsigned ftp_upl_mkdir : 1; /* Allow mkdir */ + unsigned ftp_log_cmds : 1; /* Log user commands */ + unsigned ftp_anonymousok : 1; /* Allow anonymous logins */ + unsigned ftp_mbseok : 1; /* Allow mbse user login */ + unsigned ftp_x7 : 1; + unsigned ftp_x8 : 1; + unsigned ftp_x9 : 1; + char ftp_readme_login[21]; /* Readme file for login */ + char ftp_readme_cwd[21]; /* Readme file for cwd */ + char ftp_msg_login[21]; /* Message file for login */ + char ftp_msg_cwd[21]; /* Message file for cwd */ + char ftp_msg_shutmsg[41]; /* Shutdown message */ + char ftp_upl_path[81]; /* Upload path */ + char ftp_banner[81]; /* Banner file */ + char ftp_email[41]; /* Email address */ + char ftp_pth_filter[41]; /* Path filter expression */ + char ftp_pth_message[81]; /* Message to display */ + + /* HTML creation */ + char www_root[81]; /* HTML doc root */ + char www_link2ftp[21]; /* Link name to ftp_base */ + char www_url[41]; /* Webserver URL */ + char www_charset[21]; /* Default characher set */ + char www_tbgcolor[21]; /* Table bgcolor */ + char www_hbgcolor[21]; /* Header bgcolor */ + char www_author[41]; /* Author name in pages */ + char www_convert[81]; /* Graphic Convert command */ + char www_icon_home[21]; /* Icon for Home */ + char www_name_home[21]; /* String for Home */ + char www_icon_back[21]; /* Icon for Back */ + char www_name_back[21]; /* String for Back */ + char www_icon_prev[21]; /* Icon for previous page */ + char www_name_prev[21]; /* String for previous page */ + char www_icon_next[21]; /* Icon for next page */ + char www_name_next[21]; /* String for next page */ + int www_files_page; /* Files per webpage */ + + fidoaddr EmailFidoAka; /* Email aka in fidomode */ + fidoaddr UUCPgate; /* UUCP gateway in fidomode */ + int EmailMode; /* Email mode to use */ + unsigned modereader : 1; /* NNTP Mode Reader */ + unsigned allowcontrol : 1; /* Allow control messages */ + unsigned dontregate : 1; /* Don't regate gated msgs */ + char nntpuser[16]; /* NNTP username */ + char nntppass[16]; /* NNTP password */ + long nntpdupes; /* NNTP dupes database size */ + int newsfeed; /* Newsfeed mode */ +}; + + + +/* + * Limits Control Structure (limits.data) + */ +struct limitshdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct limits { + unsigned long Security; /* Security Level */ + long Time; /* Amount of time per call */ + unsigned long DownK; /* Download KB per call */ + unsigned int DownF; /* Download files per call */ + char Description[41]; /* Description for level */ + unsigned Available : 1; /* Is this limit available */ + unsigned Deleted : 1; /* Is this limit deleted */ +}; + + + +/* + * Menu File Control Structure (*.mnu) + */ +struct menufile { + char MenuKey[2]; /* Menu Key */ + int MenuType; /* Menu Type */ + char OptionalData[81]; /* Optional Date */ + char Display[81]; /* Menu display line */ + securityrec MenuSecurity; /* Menu Security Level */ + int Age; /* Minimum Age to use menu */ + unsigned int MaxSecurity; /* Maximum security level */ + char Password[15]; /* Menu Password */ + char TypeDesc[30]; /* Menu Type Description */ + unsigned AutoExec : 1; /* Auto Exec Menu Type */ + unsigned NoDoorsys : 1; /* Suppress door.sys */ + unsigned Y2Kdoorsys : 1; /* Write Y2K style door.sys */ + unsigned Comport : 1; /* Vmodem compart mode */ + long Credit; /* Credit needed */ + int OpenFrom; /* Open From */ + int OpenTo; /* Open To */ + int ForeGnd; /* ForeGround color */ + int BackGnd; /* BackGround color */ +}; + + + +/* + * News dupes database. Stores newsgroupname and CRC32 of article msgid. + */ +struct newsdupes { + char NewsGroup[65]; /* Name of the group */ + unsigned long Crc; /* CRC32 of msgid */ +}; + + + +/* + * Message Areas Structure (mareas.data) + * This is also used for echomail, netmail and news + */ +struct msgareashdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + long syssize; /* Size for systems */ + time_t lastupd; /* Last date stats updated */ +}; + +struct msgareas { + char Name[41]; /* Message area Name */ + char Tag[51]; /* Area tag */ + char Base[65]; /* JAM base */ + char QWKname[21]; /* QWK area name */ + int Type; /* Msg Area Types */ + /* Local, Net, Echo, New, E */ + int MsgKinds; /* Type of Messages */ + /* Public,Private,ReadOnly */ + int DaysOld; /* Days to keep messages */ + int MaxMsgs; /* Maximum number of msgs */ + int UsrDelete; /* Allow users to delete */ + securityrec RDSec; /* Read Security */ + securityrec WRSec; /* Write Security */ + securityrec SYSec; /* Sysop Security */ + int Age; /* Age to access this area */ + char Password[20]; /* Area Password */ + char Group[13]; /* Group Area */ + fidoaddr Aka; /* Fidonet address */ + char Origin[65]; /* Origin Line */ + unsigned Aliases : 1; /* Allow aliases */ + unsigned NetReply; /* Area for Netmail reply */ + unsigned Active : 1; /* Area is active */ + unsigned OLR_Forced : 1; /* OLR Area always on */ + unsigned xFileAtt : 1; /* Allow file attach */ + unsigned xModerated : 1; /* Moderated newsgroup */ + unsigned Quotes : 1; /* Add random quotes */ + unsigned Mandatory : 1; /* Mandatory for nodes */ + unsigned UnSecure : 1; /* UnSecure tossing */ + unsigned xUseFidoDomain : 1; + unsigned OLR_Default : 1; /* OLR Deafault turned on */ + unsigned xPrivate : 1; /* Pvt bits allowed */ + unsigned xCheckSB : 1; + unsigned xPassThru : 1; + unsigned xNotiFied : 1; + unsigned xUplDisc : 1; + statcnt Received; /* Received messages */ + statcnt Posted; /* Posted messages */ + time_t LastRcvd; /* Last time msg received */ + time_t LastPosted; /* Last time msg posted */ + char Newsgroup[81]; /* Newsgroup name */ + char Distribution[17]; /* Ng distribution */ + char Moderator[65]; /* Moderator */ + int Rfccode; /* RFC characterset */ + int Ftncode; /* FTN characterset */ +}; + + + +/* + * System Bank Control Structure (bank.data) + */ +struct timebankhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct timebank { + char Name[36]; /* Account Name */ + char Date[12]; /* Current Date */ + int TimeDeposit; /* Time deposited today */ + int KByteDeposit; /* Bytes deposited today */ + int TimeWithdraw; /* Time withdrawn today */ + int KByteWithdraw; /* Bytes withdrawn today */ + int TimeBalance; /* Current Time Balance */ + int KByteBalance; /* Current Byte Balance */ +}; + + + +/* + * Structure for Language file (language.data) + */ +struct languagehdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct language { + char Name[30]; /* Name of Language */ + char LangKey[2]; /* Language Key */ + char MenuPath[81]; /* Path of menu directory */ + char TextPath[81]; /* Path of text files */ + unsigned Available : 1; /* Availability of Language*/ + unsigned Deleted : 1; /* Language is deleted */ + char Filename[81]; /* Path of language file */ + securityrec Security; /* Security level */ + char MacroPath[81]; /* Path to the macro files */ +}; + + + +/* + * Structure for Language Data File (english.lang) + */ +struct langdata { + char sString[85]; /* Language text */ + char sKey[30]; /* Keystroke characters */ +}; + + + +/* + * Structure for Safe Cracker Door Data File (safe.data) + */ +struct crackerhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct cracker { + char Date[12]; /* Date used */ + char Name[36]; /* User name */ + int Trys; /* Trys today */ + unsigned Opened : 1; /* If user succeeded */ +}; + + + +/* + * Fidonet Networks (fidonet.data) + */ +struct _fidonethdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +typedef struct _seclist { + char nodelist[9]; /* Secondary nodelist name */ + unsigned short zone; /* Adress for this list */ + unsigned short net; + unsigned short node; +} seclistrec; + +struct _fidonet { + char domain[13]; /* Network domain name */ + char nodelist[9]; /* Nodelist name */ + seclistrec seclist[6]; /* 6 secondary nodelists */ + unsigned short zone[6]; /* Maximum 6 zones */ + char comment[41]; /* Record comment */ + unsigned available : 1; /* Network available */ + unsigned deleted : 1; /* Network is deleted */ +}; + + + +/* + * Archiver programs (archiver.data) + */ +struct _archiverhdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +struct _archiver { + char comment[41]; /* Archiver comment */ + char name[6]; /* Archiver name */ + unsigned available : 1; /* Archiver available */ + unsigned deleted : 1; /* Archiver is deleted */ + char farc[65]; /* Archiver for files */ + char marc[65]; /* Archiver for mail */ + char barc[65]; /* Archiver for banners */ + char tarc[65]; /* Archiver test */ + char funarc[65]; /* Unarc files */ + char munarc[65]; /* Unarc mail */ + char iunarc[65]; /* Unarc FILE_ID.DIZ */ +}; + + + +/* + * Virus scanners (virscan.data) + */ +struct _virscanhdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +struct _virscan { + char comment[41]; /* Comment */ + char scanner[65]; /* Scanner command */ + unsigned available : 1; /* Scanner available */ + unsigned deleted : 1; /* Scanner is deleted */ + char options[65]; /* Scanner options */ + int error; /* Error level for OK */ +}; + + + +/* + * TTY information + */ +struct _ttyinfohdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +struct _ttyinfo { + char comment[41]; /* Comment for tty */ + char tty[7]; /* TTY device name */ + char phone[26]; /* Phone or dns name */ + char speed[21]; /* Max speed for this tty */ + char flags[31]; /* Fidonet capabilty flags */ + int type; /* Pots/ISDN/Netw/Local */ + unsigned available : 1; /* Available flag */ + unsigned authlog : 1; /* Is speed logged */ + unsigned honor_zmh : 1; /* Honor ZMH on this line */ + unsigned deleted : 1; /* Is deleted */ + unsigned callout : 1; /* Callout allowed */ + char modem[31]; /* Modem type */ + char name[36]; /* EMSI line name */ + long portspeed; /* Locked portspeed */ +}; + + + +/* + * Modem definitions. + */ +struct _modemhdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +struct _modem { + char modem[31]; /* Modem type */ + char init[3][61]; /* Init strings */ + char ok[11]; /* OK string */ + char hangup[41]; /* Hangup command */ + char info[41]; /* After hangup get info */ + char dial[41]; /* Dial command */ + char connect[20][31]; /* Connect strings */ + char error[10][21]; /* Error strings */ + char reset[61]; /* Reset string */ + int costoffset; /* Offset add to connect */ + char speed[16]; /* EMSI speed string */ + unsigned available : 1; /* Is modem available */ + unsigned deleted : 1; /* Is modem deleted */ + unsigned stripdash : 1; /* Strip dashes from dial */ +}; + + + +/* + * Structure for TIC areas (tic.data) + */ +struct _tichdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + long syssize; /* Size for systems */ + time_t lastupd; /* Last statistic update */ +}; + +struct _tic { + char Name[21]; /* Area name */ + char Comment[56]; /* Area comment */ + long FileArea; /* The BBS filearea */ + char Message[15]; /* Message file */ + char Group[13]; /* FDN group */ + int KeepLatest; /* Keep latest n files */ + long xOld[6]; + time_t AreaStart; /* Startdate */ + fidoaddr Aka; /* Fidonet address */ + char Convert[6]; /* Archiver to convert */ + time_t LastAction; /* Last Action in this area*/ + char Banner[15]; /* Banner file */ + long xUnitCost; + long xUnitSize; + long xAddPerc; + unsigned Replace : 1; /* Allow Replace */ + unsigned DupCheck : 1; /* Dupe Check */ + unsigned Secure : 1; /* Check for secure system */ + unsigned NoTouch : 1; /* Don't touch filedate */ + unsigned VirScan : 1; /* Run Virus scanners */ + unsigned Announce : 1; /* Announce files */ + unsigned UpdMagic : 1; /* Update Magic database */ + unsigned FileId : 1; /* Check FILE_ID.DIZ */ + unsigned ConvertAll : 1; /* Convert allways */ + unsigned SendOrg : 1; /* Send Original to downl's*/ + unsigned Mandat : 1; /* Mandatory area */ + unsigned Notified : 1; /* Notified if disconn. */ + unsigned UplDiscon : 1; /* Uplink disconnected */ + unsigned Active : 1; /* If this area is active */ + unsigned Deleted : 1; /* If this area is deleted */ + statcnt Files; /* Total processed files */ + statcnt KBytes; /* Total processed KBytes */ +}; + + + +/* + * Nodes, up- and downlinks. (nodes.data) + */ +struct _nodeshdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + long filegrp; /* Size for file groups */ + long mailgrp; /* Size for mail groups */ + time_t lastupd; /* Last statistic update */ +}; + +struct _nodes { + char Sysop[36]; /* Sysop name */ + fidoaddr Aka[20]; /* Aka's for this system */ + char Fpasswd[16]; /* Files password */ + char Epasswd[16]; /* Session/Mail password */ + char Apasswd[16]; /* Areamgr password */ + char UplFmgrPgm[9]; /* Uplink FileMgr program */ + char UplFmgrPass[16]; /* Uplink FileMgr password */ + char UplAmgrPgm[9]; /* Uplink AreaMgr program */ + char UplAmgrPass[16]; /* Uplink AreaMgr password */ + + unsigned Direct : 1; /* Netmail Direct */ + unsigned Message : 1; /* Send Message w. files */ + unsigned Tic : 1; /* Send TIC files */ + unsigned Notify : 1; /* Send Notify messages */ + unsigned FileFwd : 1; /* Accept File Forward */ + unsigned MailFwd : 1; /* Accept Mail Forward */ + unsigned AdvTic : 1; /* Advanced Tic files */ + unsigned Billing : 1; /* Cost sharing on/off */ + + unsigned BillDirect : 1; /* Send bill direct */ + unsigned Crash : 1; /* Netmail crash */ + unsigned Hold : 1; /* Netmail hold */ + unsigned AddPlus : 1; /* Add + for uplink msgs */ + unsigned MailPwdCheck : 1; /* Mail password check */ + unsigned Deleted : 1; /* Node is deleted */ + unsigned NoEMSI : 1; /* No EMSI handshake */ + unsigned NoWaZOO : 1; /* No YooHoo/2U2 handshake */ + + unsigned NoFreqs : 1; /* Don't allow requests */ + unsigned NoCall : 1; /* Don't call this node */ + unsigned NoHold : 1; /* Don't send hold mail */ + unsigned NoPUA : 1; /* Don't pickup all */ + unsigned NoZmodem : 1; /* Don't use Zmodem */ + unsigned NoZedzap : 1; /* Don't use Zedzap */ + unsigned xNoJanus : 1; /* Don't use Janus */ + unsigned NoHydra : 1; /* Don't use Hydra */ + + unsigned NoTCP : 1; /* Don't use TCP/IP */ + unsigned PackNetmail : 1; /* Pack netmail */ + unsigned ARCmailCompat : 1; /* ARCmail Compatibility */ + unsigned ARCmailAlpha : 1; /* Allow a..z ARCmail name */ + unsigned FNC : 1; /* FileName Conversion */ + + char xExtra[94]; + time_t StartDate; /* Node start date */ + time_t LastDate; /* Last action date */ + long Credit; /* Node's credit */ + long Debet; /* Node's debet */ + long AddPerc; /* Add Percentage */ + long WarnLevel; /* Warning level */ + long StopLevel; /* Stop level */ + fidoaddr RouteVia; /* Routing address */ + int Language; /* Language for netmail */ + statcnt FilesSent; /* Files sent to node */ + statcnt FilesRcvd; /* Files received from node*/ + statcnt F_KbSent; /* File KB. sent */ + statcnt F_KbRcvd; /* File KB. received */ + statcnt MailSent; /* Messages sent to node */ + statcnt MailRcvd; /* Messages received */ + char dial[41]; /* Dial command override */ + char phone[2][21]; /* Phone numbers override */ +}; + + + +/* + * Groups for file areas. (fgroups.data) + */ +struct _fgrouphdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last statistics update */ +}; + +struct _fgroup { + char Name[13]; /* Group Name */ + char Comment[56]; /* Group Comment */ + unsigned Active : 1; /* Group Active */ + unsigned Deleted : 1; /* Is group deleted */ + unsigned DivideCost : 1; /* Divide cost over links */ + fidoaddr UseAka; /* Aka to use */ + fidoaddr UpLink; /* Uplink address */ + long UnitCost; /* Cost per unit */ + long UnitSize; /* Size per unit */ + long AddProm; /* Promillage to add */ + time_t StartDate; /* Start Date */ + time_t LastDate; /* Last active date */ + char AreaFile[13]; /* Areas filename */ + statcnt Files; /* Files processed */ + statcnt KBytes; /* KBytes msgs or files */ +}; + + + +/* + * Groups for message areas. (mgroups.data) + */ +struct _mgrouphdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last statistics update */ +}; + +struct _mgroup { + char Name[13]; /* Group Name */ + char Comment[56]; /* Group Comment */ + unsigned Active : 1; /* Group Active */ + unsigned Deleted : 1; /* Group is deleted */ + fidoaddr UseAka; /* Aka to use */ + fidoaddr UpLink; /* Uplink address */ + long xOld[6]; + time_t StartDate; /* Start Date */ + time_t LastDate; /* Last active date */ + char AreaFile[13]; /* Areas filename */ + statcnt MsgsRcvd; /* Received messages */ + statcnt MsgsSent; /* Sent messages */ +}; + + + +/* + * Groups for newfiles announce. (ngroups.data) + */ +struct _ngrouphdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct _ngroup { + char Name[13]; /* Group Name */ + char Comment[56]; /* Group Comment */ + unsigned Active : 1; /* Group Active */ + unsigned Deleted : 1; /* Group is deleted */ +}; + + + +/* + * Hatch manager (hatch.data) + */ +struct _hatchhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last stats update */ +}; + +struct _hatch { + char Spec[79]; /* File spec to hatch */ + char Name[21]; /* File Echo name */ + char Replace[15]; /* File to replace */ + char Magic[15]; /* Magic to update */ + char Desc[256]; /* Description for file */ + unsigned DupeCheck : 1; /* Check for dupes */ + unsigned Active : 1; /* Record active */ + unsigned Deleted : 1; /* Record is deleted */ + unsigned short Days[7]; /* Days in the week */ + unsigned short Month[32]; /* Days in the month */ + statcnt Hatched; /* Hatched statistics */ +}; + + + +/* + * Magic manager (magic.data) + */ +typedef enum { + MG_EXEC, /* Execute command */ + MG_COPY, /* Copy file */ + MG_UNPACK, /* Unpack file */ + MG_KEEPNUM, /* Keep nr of files */ + MG_MOVE, /* Move to other area */ + MG_UPDALIAS, /* Update alias */ + MG_ADOPT, /* Adopt file */ + MG_OTHER, /* Store in other path */ + MG_DELETE /* Delete file */ +} MAGICTYPE; + +struct _magichdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct _magic { + char Mask[15]; /* Filemask for magic */ + unsigned int Attrib; /* Record type */ + unsigned Active : 1; /* Record active */ + unsigned Compile : 1; /* Compile Flag */ + unsigned Deleted : 1; /* Deleted record */ + char From[21]; /* From area */ + char Path[65]; /* Destination path */ + char Cmd[65]; /* Command to execute */ + int KeepNum; /* Keep number of files */ + char ToArea[21]; /* Destination area */ +}; + + + +/* + * Billing database + */ +struct _bill { + fidoaddr Node; /* Fido address */ + char FileName[15]; /* File Name */ + char FileEcho[21]; /* File Echo */ + char Group[13]; /* Group */ + off_t Size; /* File Size */ + long Cost; /* File Cost */ +}; + + + +/* + * Newfile reports (newfiles.data) + */ +struct _newfileshdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + long grpsize; /* Size of groups */ +}; + +struct _newfiles { + char Comment[56]; /* Comment */ + char Area[51]; /* Message area */ + char Origin[51]; /* Origin line, or random */ + char From[36]; /* From field */ + char Too[36]; /* To field */ + char Subject[61]; /* Subject field */ + int Language; /* Language */ + char Template[15]; /* Template filename */ + fidoaddr UseAka; /* Aka to use */ + unsigned Active : 1; /* Active */ + unsigned HiAscii : 1; /* Hi-Ascii allowed */ + unsigned Deleted : 1; /* Report is deleted */ +}; + + + +/* + * Scanmanager (scanmgr.data) + */ +struct _scanmgrhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct _scanmgr { + char Comment[56]; /* Comment */ + char Origin[51]; /* Origin line */ + fidoaddr Aka; /* Fido address */ + char ScanBoard[51]; /* Board to scan */ + char ReplBoard[51]; /* Reply board */ + int Language; /* Language to use */ + char template[15]; /* Template filename */ + unsigned Active : 1; /* Record active */ + unsigned NetReply : 1; /* Netmail reply */ + unsigned Deleted : 1; /* Area is deleted */ + unsigned HiAscii : 1; /* High Ascii allowed */ +}; + + + +/* + * Record structure for file handling + */ +struct _filerecord { + char Echo[21]; /* File echo */ + char Comment[56]; /* Comment */ + char Group[13]; /* Group */ + char Name[13]; /* File Name */ + char LName[81]; /* Long FileName */ + off_t Size; /* File Size */ + unsigned long SizeKb; /* File Size in Kb */ + time_t Fdate; /* File Date */ + char Origin[24]; /* Origin system */ + char From[24]; /* From system */ + char Crc[9]; /* CRC 32 */ + char Replace[13]; /* Replace file */ + char Magic[21]; /* Magic name */ + char Desc[256]; /* Short description */ + char LDesc[25][49]; /* Long description */ + int TotLdesc; /* Total long desc lines */ + long Cost; /* File cost */ + unsigned Announce : 1; /* Announce this file */ +}; + + + +/* + * Mailer history file (mailhist.data) + * The first record conatains only the date (online) from which date this + * file is valid. The offline date is teh date this file is created or + * packed. From the second record and on the records are valid data records. + */ +struct _history { + fidoaddr aka; /* Node number */ + char system_name[36]; /* System name */ + char sysop[36]; /* Sysop name */ + char location[36]; /* System location */ + char tty[7]; /* Tty of connection */ + time_t online; /* Starttime of session */ + time_t offline; /* Endtime of session */ + unsigned long sent_bytes; /* Bytes sent */ + unsigned long rcvd_bytes; /* Bytes received */ + int cost; /* Session cost */ + unsigned inbound : 1; /* Inbound session */ +}; + + +#endif + diff --git a/lib/strutil.c b/lib/strutil.c new file mode 100644 index 00000000..9d85aba4 --- /dev/null +++ b/lib/strutil.c @@ -0,0 +1,357 @@ +/***************************************************************************** + * + * File ..................: strutil.c + * Purpose ...............: Common string functions + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + + + +char *padleft(char *str, int size, char pad) +{ + static char stri[256]; + static char temp[256]; + + strcpy(stri, str); + memset(temp, pad, (long)size); + temp[size] = '\0'; + if (strlen(stri) <= size) + memmove(temp, stri, (long)strlen(stri)); + else + memmove(temp, stri, (long)size); + return temp; +} + + + +/* + * Small function to convert String to LowerCase + */ +char *tl(char *str) +{ + char *p = str; + + while (*p != '\0') { + *p = (char)tolower(*p); + p++; + } + + return str; +} + + + + +void Striplf(char *String) +{ + int i; + + for(i = 0; i < strlen(String); i++) { + if(*(String + i) == '\0') + break; + if(*(String + i) == '\n') + *(String + i) = '\0'; + } +} + + + +/* + * Converts first letter to UpperCase + */ +void tlf(char *str) +{ + *(str) = toupper(*(str)); +} + + + +/* + * Small function to convert String to UpperCase + */ +char *tu(char *str) +{ + char *p = str; + + while (*p != '\0') { + *p = (char)toupper(*p); + p++; + } + + return str; +} + + + +/* + * Converts the first letter in every word in a string to uppercase, + * all other character will be lowercase. Will handle the notation + * Bob Ten.Dolle as well + */ +char *tlcap(char *String) +{ + static char stri[256]; + int Loop, Strlen; + + strcpy(stri, String); + Strlen = strlen(stri); + + /* + * Automatic do the first character + */ + stri[0] = toupper(stri[0]); + + for(Loop = 1; Loop < Strlen; Loop++) { + stri[Loop] = tolower(stri[Loop]); + if (( stri[Loop] == ' ') || (stri[Loop] == '.')) { + /* + * This is a space charracter, increase the counter + * and convert the next character to uppercase. + */ + Loop++; + stri[Loop] = toupper(stri[Loop]); + } + } + return stri; +} + + + +/* + * Hilite "Word" in string, this is done by inserting ANSI + * Hilite characters in the string. + */ +char *Hilite(char *str, char *Word) +{ + char *pos; + char *new; + char *old; + int t; + + new = strdup(str); + old = strdup(str); + tl(new); + + if ((pos = strstr(new,Word)) == NULL) + return(str); + + str = realloc(str,strlen(new)+200); + strcpy(str,"\0"); + + while (( pos = strstr(new,Word)) != NULL) { + *pos = '\0'; + t = strlen(new); + strncat(str,old,t); + strcat(str,""); + old+=t; + strncat(str,old,strlen(Word)); + strcat(str,""); + old+=strlen(Word); + new = new+t+strlen(Word); + } + strcat(str,old); + return(str); +} + + + +/* + * Replace spaces is a string with underscore characters. + */ +void Addunderscore(char *temp) +{ + int i; + + for(i = 0; i < strlen(temp); i++) { + if (*(temp + i) == '\0') + break; + if (*(temp + i) == ' ') + *(temp + i) = '_'; + } +} + + + +/* + * Find & Replace string in a string + */ +void strreplace(char *sStr, char *sFind, char *sReplace) +{ + char sNewstr[81]=""; + char *posStr, *posFind; + int iPos, iLen, iCounter; + + posStr=sStr; + if(( posFind = strstr(sStr, sFind)) != NULL) { + iPos = (int)(posFind - posStr); + strncpy(sNewstr, sStr, iPos); + strcat(sNewstr, sReplace); + iPos+= strlen(sFind); + iLen = strlen(sNewstr); + for (iCounter=0; iCounter < (strlen(sStr) - iPos); iCounter++) + sNewstr[iCounter + iLen] = sStr[iCounter + iPos]; + sNewstr[iCounter+1+iLen] = '\0'; + strcpy(sStr, sNewstr); + } +} + + + +/* + * Converts to HH:MM + */ +char *StrTimeHM(time_t date) +{ + static char ttime[6]; + struct tm *l_d; + + l_d = localtime(&date); + sprintf(ttime, "%02d:%02d", l_d->tm_hour, l_d->tm_min); + return ttime; +} + + + +/* + * Returns HH:MM:SS + */ +char *StrTimeHMS(time_t date) +{ + static char ttime[9]; + struct tm *l_d; + + l_d = localtime(&date); + sprintf(ttime, "%02d:%02d:%02d", l_d->tm_hour, l_d->tm_min, l_d->tm_sec); + return ttime; +} + + + +/* + * Get the current local time, returns HH:MM + */ +char *GetLocalHM() +{ + static char gettime[15]; + time_t T_Now; + + time(&T_Now); + sprintf(gettime,"%s", StrTimeHM(T_Now)); + return(gettime); +} + + + + +/* + * Get the current local time, returns HH:MM:SS + */ +char *GetLocalHMS() +{ + static char gettime[15]; + time_t T_Now; + + time(&T_Now); + sprintf(gettime,"%s", StrTimeHMS(T_Now)); + return(gettime); +} + + + +/* + * Returns date as MM-DD-YYYY + */ +char *StrDateMDY(time_t *Clock) +{ + struct tm *tm; + static char cdate[12]; + + tm = localtime(Clock); + sprintf(cdate,"%02d-%02d-%04d", tm->tm_mon+1, tm->tm_mday, tm->tm_year+1900); + return(cdate); +} + + + +/* + * Returns DD-MM-YYYY + */ +char *StrDateDMY(time_t date) +{ + static char tdate[15]; + struct tm *l_d; + + l_d = localtime(&date); + sprintf(tdate, "%02d-%02d-%04d", l_d->tm_mday, l_d->tm_mon+1, l_d->tm_year+1900); + return tdate; +} + + + + +/* + * This function returns the date for today, to test against other functions + * DD-MM-YYYY (DAY-MONTH-YEAR) + */ +char *GetDateDMY() +{ + static char tdate[15]; + struct tm *l_d; + time_t T_Now; + + time(&T_Now); + l_d = localtime(&T_Now); + sprintf(tdate, "%02d-%02d-%04d", l_d->tm_mday,l_d->tm_mon+1,l_d->tm_year+1900); + return(tdate); +} + + + +/* + * Returns current date in DDMMYYY + */ +/* +char *tDate1() +{ + static char tdate1[15]; + struct tm *l_d; + time_t T_Now; + + time(&T_Now); + l_d = localtime(&T_Now); + sprintf(tdate1, "%02d%02d%02d", + l_d->tm_mday,l_d->tm_mon+1,l_d->tm_year+1900); + + return(tdate1); +} + +*/ diff --git a/lib/term.c b/lib/term.c new file mode 100644 index 00000000..772c0e01 --- /dev/null +++ b/lib/term.c @@ -0,0 +1,245 @@ +/***************************************************************************** + * + * File ..................: term.c + * Purpose ...............: Terminal output routines. + * Last modification date : 03-Feb-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#define DB_USERS + +#include "libs.h" +#include "structs.h" +#include "ansi.h" +#include "records.h" +#include "common.h" + + +int termmode; /* 0 = tty, 1 = ANSI */ + + + +void TermInit(int mode) +{ + termmode = mode; +} + + + +/* + * Function will print about of enters specified + */ +void Enter(int num) +{ + int i; + + for(i = 0; i < num; i++) + printf("\n"); +} + + + + +void pout(int fg, int bg, char *Str) +{ + colour(fg, bg); + printf(Str); +} + + + +void poutCenter(int fg, int bg, char *Str) +{ + colour(fg, bg); + Center(Str); +} + + + +void poutCR(int fg, int bg, char *Str) +{ + colour(fg, bg); + puts(Str); +} + + + +/* + * Changes ansi background and foreground color + */ +void colour(int fg, int bg) +{ + if (termmode == 1) { + + int att=0, fore=37, back=40; + + if (fg<0 || fg>31 || bg<0 || bg>7) { + printf("ANSI: Illegal colour specified: %i, %i\n", fg, bg); + return; + } + + printf("["); + if ( fg > 15) { + printf("5;"); + fg-=16; + } + if (fg > 7) { + att=1; + fg=fg-8; + } + + if (fg==0) fore=30; + else if (fg==1) fore=34; + else if (fg==2) fore=32; + else if (fg==3) fore=36; + else if (fg==4) fore=31; + else if (fg==5) fore=35; + else if (fg==6) fore=33; + else fore=37; + + if (bg==1) back=44; + else if (bg==2) back=42; + else if (bg==3) back=46; + else if (bg==4) back=41; + else if (bg==5) back=45; + else if (bg==6) back=43; + else if (bg==7) back=47; + else back=40; + + printf("%d;%d;%dm", att, fore, back); + } +} + + + +void Center(char *string) +{ + int Strlen; + int Maxlen = 70; + int i, x, z; + char *Str; + + Str = calloc(81, sizeof(char)); + Strlen = strlen(string); + + if(Strlen == Maxlen) + printf("%s\n", string); + else { + x = Maxlen - Strlen; + z = x / 2; + for(i = 0; i < z; i++) + strcat(Str, " "); + strcat(Str, string); + printf("%s\n", Str); + } + + free(Str); +} + + + +void clear() +{ + if (termmode == 1) { + colour(LIGHTGRAY, BLACK); + printf(ANSI_HOME); + printf(ANSI_CLEAR); + } else + Enter(1); +} + + + +/* + * Moves cursor to specified position + */ +void locate(int y, int x) +{ + if (termmode > 0) { + if (exitinfo.iScreenLen != 0) { + if (y > exitinfo.iScreenLen || x > 80) { + printf("ANSI: Invalid screen coordinates: %i, %i\n", y, x); + printf("ANSI: exitinfo.iScreenLen: %i\n", exitinfo.iScreenLen); + return; + } + } else { + if (y > 25 || x > 80) { + printf("ANSI: Invalid screen coordinates: %i, %i\n", y, x); + return; + } + } + printf("\x1B[%i;%iH", y, x); + } +} + + + +void fLine(int Len) +{ + int x; + + if (termmode == 0) + for (x = 0; x < Len; x++) + printf("-"); + + if (termmode == 1) + for (x = 0; x < Len; x++) + printf("%c", 196); + + printf(" \n"); +} + + + + +void sLine() +{ + fLine(79); +} + + + +/* + * curses compatible functions + */ +void mvprintw(int y, int x, const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + locate(y, x); + printf(outputstr); + free(outputstr); +} + + + diff --git a/lib/test.c b/lib/test.c new file mode 100644 index 00000000..1734e725 --- /dev/null +++ b/lib/test.c @@ -0,0 +1,106 @@ + +/* +** NOTE: Running this program in a Win32 or Unix environment +** will probably result in a segmentation fault or protection +** error. These errors may be caused by MEMWATCH when it's +** looking at memory to see if it owns it, or may be caused by +** the test program writing to memory it does not own. +** +** MEMWATCH has two functions called 'mwIsReadAddr()' and +** 'mwIsSafeAddr()', which are system-specific. +** If they are implemented for your system, and works +** correctly, MEMWATCH will identify garbage pointers and +** avoid causing segmentation faults, GP's etc. +** +** If they are NOT implemented, count on getting the core +** dumped when running this test program! As of this writing, +** the safe-address checking has been implemented for Win32 +** and ANSI-C compliant systems. The ANSI-C checking traps +** SIGSEGV and uses setjmp/longjmp to resume processing, +** but I've only tested this under Linux (where it works). +** +** Note for Win95 users: The Win32 IsBadReadPtr() and it's +** similar functions can return incorrect values. This has +** not happened under WinNT, though, just Win95. +** +** 980318 Johan Lindh +** +*/ + +#include "libs.h" + +#error "Hey! Don't just compile this program, read the comments first!" +#ifndef SIGSEGV +#error SIGNAL.H does not define SIGSEGV; running this program WILL cause a core dump/crash! +#endif + +main() +{ + char *p; + + /* Collect stats on a line number basis */ + mwStatistics( 2 ); + + /* Slows things down, but OK for this test prg */ + /* mwAutoCheck( 1 ); */ + + TRACE("Hello world!\n"); + + p = malloc(210); + free(p); + p = malloc(20); + p = malloc(200); /* causes unfreed error */ + p[-1] = 0; /* causes underflow error */ + free(p); + + p = malloc(100); + p[ -(int)(sizeof(long)*8) ] = -1; /* try to damage MW's heap chain */ + free( p ); /* should cause relink */ + + mwSetAriFunc( mwAriHandler ); + ASSERT(1==2); + + mwLimit(1000000); + mwNoMansLand( MW_NML_ALL ); + + /* These may cause a general protection fault (segmentation fault) */ + /* They're here to help test the no-mans-land protection */ + if( mwIsSafeAddr(p+50000,1) ) { + TRACE("Killing byte at %p\n", p+50000); + *(p+50000) = 0; + } + if( mwIsSafeAddr(p+30000,1) ) { + TRACE("Killing byte at %p\n", p+30000); + *(p+30000) = 0; + } + if( mwIsSafeAddr(p+1000,1) ) { + TRACE("Killing byte at %p\n", p+1000); + *(p+1000) = 0; + } + if( mwIsSafeAddr(p-100,1) ) { + TRACE("Killing byte at %p\n", p-100); + *(p-100) = 0; + } + + /* This may cause a GP fault as well, since MW data buffers */ + /* have been damaged in the above killing spree */ + CHECK(); + + p = malloc(12000); + p[-5] = 1; + p[-10] = 2; + p[-15] = 3; + p[-20] = 4; + + /* This may cause a GP fault since MW's buffer list may have */ + /* been damaged by above killing, and it will try to repair it. */ + free(p); + + p = realloc(p,10); /* causes realloc: free'd from error */ + + /* May cause GP since MW will inspect the memory to see if it owns it. */ + free( (void*)main ); + + return 0; +} + diff --git a/lib/unpacker.c b/lib/unpacker.c new file mode 100644 index 00000000..1723b3c9 --- /dev/null +++ b/lib/unpacker.c @@ -0,0 +1,102 @@ +/***************************************************************************** + * + * File ..................: unpacker.c + * Purpose ...............: Archive unpacker + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#define DB_ARCHIVE + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +char *unpacker(char *fn) +{ + FILE *fp; + unsigned char buf[8]; + + if ((fp = fopen(fn,"r")) == NULL) { + WriteError("$Could not open file %s", fn); + return NULL; + } + + if (fread(buf,1,sizeof(buf),fp) != sizeof(buf)) { + WriteError("$Could not read head of the file %s", fn); + fclose(fp); + return NULL; + } + + fclose(fp); + + if (memcmp(buf,"PK",2) == 0) return (char *)"ZIP"; + if (*buf == 0x1a) return (char *)"ARC"; + if (memcmp(buf+2,"-l",2) == 0) return (char *)"LZH"; + if (memcmp(buf,"ZOO",3) == 0) return (char *)"ZOO"; + if (memcmp(buf,"`\352",2) == 0) return (char *)"ARJ"; + if (memcmp(buf,"Rar",3) == 0) return (char *)"RAR"; + if (memcmp(buf, ";A ",3) == 0) return (char *)"ASC"; + + Syslog('p', "Unknown compress scheme in file %s", fn); + return NULL; +} + + + +int getarchiver(char *unarc) +{ + FILE *fp; + char *filename; + + memset(&archiver, 0, sizeof(archiver)); + filename = calloc(PATH_MAX, sizeof(char)); + sprintf(filename, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(filename, "r")) == NULL) { + WriteError("$Can't open %s", filename); + free(filename); + return FALSE; + } + free(filename); + + fread(&archiverhdr, sizeof(archiverhdr), 1, fp); + while (fread(&archiver, archiverhdr.recsize, 1, fp) == 1) { + if ((archiver.available) && (strcmp(archiver.name, unarc) == 0)) { + fclose(fp); + return TRUE; + } + } + + fclose(fp); + return FALSE; +} + + + diff --git a/mbcico/Makefile.am b/mbcico/Makefile.am new file mode 100644 index 00000000..4779f331 --- /dev/null +++ b/mbcico/Makefile.am @@ -0,0 +1,36 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = README +SUBDIRS = . + +noinst_PROGRAMS = mbcico mbout + +mbcico_SOURCES = zmmisc.c zmrle.c zmrecv.c zmsend.c binkp.c \ +xmsend.c xmrecv.c m7recv.c m7send.c hydra.c \ +answer.c chat.c dial.c dietifna.c emsidat.c filelist.c \ +openfile.c openport.c opentcp.c rdoptions.c yoohoo.c \ +recvbark.c respfreq.c sendbark.c tcp.c tcpproto.c wazoo.c \ +filetime.c ftsc.c atoul.c portsel.c \ +ttyio.c lutil.c scanout.c emsi.c ulock.c \ +callstat.c session.c call.c callall.c mbcico.c \ +zmodem.h binkp.h config.h statetbl.h \ +xmsend.h xmrecv.h m7recv.h m7send.h hydra.h \ +answer.h chat.h dial.h dietifna.h emsidat.h filelist.h \ +openfile.h openport.h opentcp.h rdoptions.h yoohoo.h \ +recvbark.h respfreq.h sendbark.h tcp.h tcpproto.h wazoo.h \ +filetime.h ftsc.h atoul.h portsel.h \ +ttyio.h lutil.h scanout.h emsi.h ulock.h \ +callstat.h session.h call.h callall.h mbcico.h + +mbout_SOURCES = outstat.c nlinfo.c mbout.c scanout.c callstat.c \ +outstat.h nlinfo.h scanout.h callstat.h + +LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a \ +../lib/libmsgbase.a ../lib/libdbase.a + +install-exec-local: + $(mkinstalldirs) $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbcico $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbout $(bindir) + + diff --git a/mbcico/Makefile.in b/mbcico/Makefile.in new file mode 100644 index 00000000..a5699638 --- /dev/null +++ b/mbcico/Makefile.in @@ -0,0 +1,536 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +EXTRA_DIST = README +SUBDIRS = . + +noinst_PROGRAMS = mbcico mbout + +mbcico_SOURCES = zmmisc.c zmrle.c zmrecv.c zmsend.c binkp.c xmsend.c xmrecv.c m7recv.c m7send.c hydra.c answer.c chat.c dial.c dietifna.c emsidat.c filelist.c openfile.c openport.c opentcp.c rdoptions.c yoohoo.c recvbark.c respfreq.c sendbark.c tcp.c tcpproto.c wazoo.c filetime.c ftsc.c atoul.c portsel.c ttyio.c lutil.c scanout.c emsi.c ulock.c callstat.c session.c call.c callall.c mbcico.c zmodem.h binkp.h config.h statetbl.h xmsend.h xmrecv.h m7recv.h m7send.h hydra.h answer.h chat.h dial.h dietifna.h emsidat.h filelist.h openfile.h openport.h opentcp.h rdoptions.h yoohoo.h recvbark.h respfreq.h sendbark.h tcp.h tcpproto.h wazoo.h filetime.h ftsc.h atoul.h portsel.h ttyio.h lutil.h scanout.h emsi.h ulock.h callstat.h session.h call.h callall.h mbcico.h + + +mbout_SOURCES = outstat.c nlinfo.c mbout.c scanout.c callstat.c outstat.h nlinfo.h scanout.h callstat.h + + +LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbcico_OBJECTS = zmmisc.o zmrle.o zmrecv.o zmsend.o binkp.o xmsend.o \ +xmrecv.o m7recv.o m7send.o hydra.o answer.o chat.o dial.o dietifna.o \ +emsidat.o filelist.o openfile.o openport.o opentcp.o rdoptions.o \ +yoohoo.o recvbark.o respfreq.o sendbark.o tcp.o tcpproto.o wazoo.o \ +filetime.o ftsc.o atoul.o portsel.o ttyio.o lutil.o scanout.o emsi.o \ +ulock.o callstat.o session.o call.o callall.o mbcico.o +mbcico_LDADD = $(LDADD) +mbcico_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbcico_LDFLAGS = +mbout_OBJECTS = outstat.o nlinfo.o mbout.o scanout.o callstat.o +mbout_LDADD = $(LDADD) +mbout_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbout_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbcico_SOURCES) $(mbout_SOURCES) +OBJECTS = $(mbcico_OBJECTS) $(mbout_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbcico/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbcico: $(mbcico_OBJECTS) $(mbcico_DEPENDENCIES) + @rm -f mbcico + $(LINK) $(mbcico_LDFLAGS) $(mbcico_OBJECTS) $(mbcico_LDADD) $(LIBS) + +mbout: $(mbout_OBJECTS) $(mbout_DEPENDENCIES) + @rm -f mbout + $(LINK) $(mbout_LDFLAGS) $(mbout_OBJECTS) $(mbout_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbcico + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +answer.o: answer.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h lutil.h \ + session.h config.h answer.h openport.h portsel.h dial.h \ + rdoptions.h mbcico.h +atoul.o: atoul.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h atoul.h +binkp.o: binkp.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbnode.h ../lib/clcomm.h ttyio.h \ + session.h statetbl.h config.h emsi.h openfile.h respfreq.h \ + filelist.h opentcp.h rdoptions.h lutil.h binkp.h +call.o: call.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h ../lib/dbnode.h session.h callstat.h call.h \ + config.h dial.h lutil.h portsel.h openport.h opentcp.h \ + rdoptions.h +callall.o: callall.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + config.h ../lib/clcomm.h scanout.h lutil.h callstat.h callall.h +callstat.o: callstat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h callstat.h +chat.o: chat.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h config.h portsel.h chat.h ttyio.h +dial.o: dial.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h ../lib/dbnode.h portsel.h config.h chat.h \ + ttyio.h session.h dial.h +dietifna.o: dietifna.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h emsi.h dietifna.h respfreq.h \ + filelist.h xmrecv.h xmsend.h +emsi.o: emsi.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/dbnode.h ../lib/clcomm.h ttyio.h session.h statetbl.h \ + config.h emsi.h emsidat.h hydra.h rdoptions.h tcp.h wazoo.h +emsidat.o: emsidat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h emsi.h \ + session.h lutil.h config.h emsidat.h filetime.h +filelist.o: filelist.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h config.h session.h filelist.h +filetime.o: filetime.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h filetime.h +ftsc.o: ftsc.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h session.h ttyio.h statetbl.h config.h ftsc.h \ + rdoptions.h recvbark.h filelist.h sendbark.h respfreq.h \ + xmrecv.h xmsend.h +hydra.o: hydra.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h session.h filelist.h filetime.h ttyio.h \ + statetbl.h config.h emsi.h openfile.h lutil.h respfreq.h \ + mbcico.h hydra.h +lutil.o: lutil.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h lutil.h +m7recv.o: m7recv.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h statetbl.h ttyio.h m7recv.h +m7send.o: m7send.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h statetbl.h ttyio.h m7send.h +mbcico.o: mbcico.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h \ + ../lib/dbftn.h config.h answer.h portsel.h call.h callall.h \ + lutil.h mbcico.h session.h +mbout.o: mbout.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h \ + ../lib/dbftn.h outstat.h nlinfo.h +nlinfo.o: nlinfo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h nlinfo.h +openfile.o: openfile.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/clcomm.h \ + ../lib/common.h config.h lutil.h openfile.h +openport.o: openport.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ulock.h ttyio.h openport.h +opentcp.o: opentcp.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h session.h \ + ttyio.h openport.h opentcp.h +outstat.o: outstat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h \ + ../lib/dbftn.h scanout.h callstat.h outstat.h +portsel.o: portsel.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h portsel.h +rdoptions.o: rdoptions.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h portsel.h \ + session.h config.h +recvbark.o: recvbark.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h statetbl.h recvbark.h \ + respfreq.h filelist.h +respfreq.o: respfreq.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h session.h lutil.h config.h \ + atoul.h respfreq.h filelist.h +scanout.o: scanout.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbftn.h config.h \ + scanout.h lutil.h +sendbark.o: sendbark.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h statetbl.h sendbark.h \ + xmrecv.h +session.o: session.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ttyio.h statetbl.h emsi.h \ + ftsc.h session.h yoohoo.h mbcico.h binkp.h callstat.h +tcp.o: tcp.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/common.h ../lib/clcomm.h ttyio.h \ + session.h statetbl.h config.h emsi.h respfreq.h filelist.h \ + tcpproto.h tcp.h +tcpproto.o: tcpproto.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h config.h emsi.h lutil.h \ + openfile.h filelist.h tcpproto.h +ttyio.o: ttyio.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ttyio.h lutil.h +ulock.o: ulock.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h +wazoo.o: wazoo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h statetbl.h config.h emsi.h \ + respfreq.h filelist.h wazoo.h zmodem.h +xmrecv.o: xmrecv.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h session.h ttyio.h statetbl.h config.h lutil.h \ + openfile.h m7recv.h xmrecv.h filetime.h +xmsend.o: xmsend.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h session.h ttyio.h statetbl.h xmsend.h m7send.h \ + filelist.h filetime.h +yoohoo.o: yoohoo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h ../lib/dbnode.h statetbl.h \ + ttyio.h session.h config.h emsi.h hydra.h rdoptions.h wazoo.h \ + dietifna.h yoohoo.h +zmmisc.o: zmmisc.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h zmodem.h +zmrecv.o: zmrecv.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/clcomm.h \ + ../lib/common.h lutil.h ttyio.h session.h zmodem.h config.h \ + emsi.h openfile.h openport.h +zmrle.o: zmrle.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/clcomm.h \ + ../lib/common.h ttyio.h session.h zmodem.h +zmsend.o: zmsend.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h zmodem.h lutil.h emsi.h \ + filelist.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(mkinstalldirs) $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbcico $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbout $(bindir) + +# 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/mbcico/README b/mbcico/README new file mode 100644 index 00000000..93aaaccd --- /dev/null +++ b/mbcico/README @@ -0,0 +1,35 @@ +This is the README file for mbcico, the fidonet mailer for MBSE BBS. + +This is a heavily patched version of ifcico from the ifmail package written +by Eugene G. Crosser (crosser@pccross.msk.su), 2:5020/230@fidonet. He deserves +most of the credits for this product. + +Many others have contributed to the original ifcico and utilities. This +version doesn't use the original config file anymore, it uses the databases +that are maintained with mbsetup. Also, mail behaviour is different then +in ifcico. + +I wrote this special version to let it fully integrate with all the other +programs that are distributed with MBSE BBS, so mbcico will hopefully function +in a multiline environment with mixed analogue modems and ISDN lines. + +The reason why I changed the name of this program is only to show that there +is a real difference in the behavior and configuration compared with ifcico. + +If you insist on running the original ifcico on your system, it is still +possible, I used it myself during the development of MBSE BBS. You need to +run ifcico as the mbse admin user in the bbs group. Also make sure that the +order of the nodelists is exactly the same in ifcico and MBSE BBS. + +The following people donated code to the original ifcico, this list is +not complete. It is possible that I forgot someone, but these are the names +that I found in the several ifmail packages. + +Martin Junius +Pablo Saratxaga (srtxg@linux.chanae.stben.be) +Christof Meerwald (cmeerw@htl-sbg.ac.at) +Tseneo Tanaka (tt@efnet.com) telnet TCP + + +Michiel Broek. + diff --git a/mbcico/answer.c b/mbcico/answer.c new file mode 100644 index 00000000..aa38add3 --- /dev/null +++ b/mbcico/answer.c @@ -0,0 +1,163 @@ +/***************************************************************************** + * + * File ..................: mbcico/answer.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "lutil.h" +#include "session.h" +#include "config.h" +#include "answer.h" +#include "openport.h" +#include "portsel.h" +#include "dial.h" +#include "rdoptions.h" +#include "mbcico.h" + + +extern int carrier, online; +extern time_t c_start, c_end; +extern unsigned long sentbytes; +extern unsigned long rcvdbytes; +extern int Loaded; + +int answer(char *stype) +{ + int st, rc; + char *p, *q; + FILE *fp; + + /* + * mgetty set's the environment variable CONNECT and CALLER_ID, + * so if they are present, we might as well make log entries. + */ + if ((q = getenv("CONNECT")) != NULL) + Syslog('+', "CONNECT %s", q); + if ((q = getenv("CALLER_ID")) != NULL) + if (strncmp(q, "none", 4)) + Syslog('+', "CALLER %s", q); + + /* + * Incoming calls from modem/ISDN lines do have a tty. + * Network calls don't have a tty attached. + */ + carrier = TRUE; + p = ttyname(0); + if (p) { + q = strrchr(ttyname(0), '/'); + if (q) + p = q + 1; + if (load_port(p)) + Syslog('d', "Port %s, modem %s", ttyinfo.tty, modem.modem); + else + Syslog('d', "Port and modem not loaded!"); + } + + if ((nlent = getnlent(NULL)) == NULL) { + WriteError("could not get dummy nodelist entry"); + return 1; + } + + c_start = time(NULL); + rdoptions(FALSE); + + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); /* slave session is unsecure by default */ + + if (stype == NULL) { + st=SESSION_UNKNOWN; + } else if (strcmp(stype,"tsync") == 0) { + st=SESSION_FTSC; + IsDoing("Answer ftsc"); + } else if (strcmp(stype,"yoohoo") == 0) { + st=SESSION_YOOHOO; + IsDoing("Answer yoohoo"); + } else if (strncmp(stype,"**EMSI_",7) == 0) { + st=SESSION_EMSI; + IsDoing("Answer EMSI"); + } else if (strncmp(stype,"ibn",3) == 0) { + st=SESSION_BINKP; + IsDoing("Answer Binkp"); + } else { + st=SESSION_UNKNOWN; + IsDoing("Answer unknown"); + } + + if ((rc = rawport()) != 0) + WriteError("Unable to set raw mode"); + else { + nolocalport(); + rc=session(NULL,NULL,SESSION_SLAVE,st,stype); + } + + cookedport(); + if (p) { + /* + * Hangup will write the history record. + */ + hangup(); + } else { + /* + * Network call, write history record. + */ + c_end = time(NULL); + online += (c_end - c_start); + + history.online = c_start; + history.offline = c_end; + history.sent_bytes = sentbytes; + history.rcvd_bytes = rcvdbytes; + history.inbound = TRUE; + + p = calloc(128, sizeof(char)); + sprintf(p, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fp = fopen(p, "a")) == NULL) + WriteError("$Can't open %s", p); + else { + Syslog('s', "answer() write history"); + fwrite(&history, sizeof(history), 1, fp); + fclose(fp); + } + free(p); + if (Loaded) { + Syslog('s', "Updateing noderecord %s", aka2str(nodes.Aka[0])); + nodes.LastDate = time(NULL); + UpdateNode(); + } + } + return rc; +} + + diff --git a/mbcico/answer.h b/mbcico/answer.h new file mode 100644 index 00000000..629d58c6 --- /dev/null +++ b/mbcico/answer.h @@ -0,0 +1,8 @@ +#ifndef _ANSWER_H +#define _ANSWER_H + +int answer(char *); + + +#endif + diff --git a/mbcico/atoul.c b/mbcico/atoul.c new file mode 100644 index 00000000..b846e795 --- /dev/null +++ b/mbcico/atoul.c @@ -0,0 +1,44 @@ +/***************************************************************************** + * + * File ..................: mbcico/atoul.c + * Purpose ...............: Fidonet mailer + * Last modification date : 18-Dec-1998 + * + ***************************************************************************** + * Copyright (C) 1997-1998 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "atoul.h" + + +unsigned long atoul(char *str) +{ + unsigned long x; + + if (sscanf(str,"%lu",&x) == 1) + return x; + else return 0xffffffff; +} + diff --git a/mbcico/atoul.h b/mbcico/atoul.h new file mode 100644 index 00000000..50f62b1d --- /dev/null +++ b/mbcico/atoul.h @@ -0,0 +1,8 @@ +#ifndef _ATOUL_H +#define _ATOUL_H + + +unsigned long atoul(char *); + +#endif + diff --git a/mbcico/binkp.c b/mbcico/binkp.c new file mode 100644 index 00000000..658e69f2 --- /dev/null +++ b/mbcico/binkp.c @@ -0,0 +1,1228 @@ +/***************************************************************************** + * + * File ....................: mbcico/binkp.c + * Purpose .................: Fidonet binkd protocol + * Last modification date ..: 07-Jul-2001 + * Binkp protocol copyright : Dima Maloff. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "openfile.h" +#include "respfreq.h" +#include "filelist.h" +#include "opentcp.h" +#include "rdoptions.h" +#include "lutil.h" +#include "binkp.h" +#include "config.h" + + +static char rbuf[2048]; + +void binkp_send_data(char *, int); +void binkp_send_control(int id, ...); +int binkp_recv_frame(char *, int *, int *); +void binkp_settimer(int); +int resync(off_t); + + +static int orgbinkp(void); +static int ansbinkp(void); +static int binkp_batch(file_list *); + +extern char *ttystat[]; +extern int Loaded; + +extern unsigned long sentbytes; +extern unsigned long rcvdbytes; + +typedef enum {RxWaitFile, RxAcceptFile, RxReceData, RxWriteData, RxEndOfBatch, RxDone} RxType; +typedef enum {TxGetNextFile, TxTryRead, TxReadSend, TxWaitLastAck, TxDone} TxType; +typedef enum {InitTransfer, Switch, Receive, Transmit} TransferType; +typedef enum {Ok, Failure, Continue} TrType; + +static int RxState; +static int TxState; +static int TfState; +static time_t Timer; +static int NRflag = FALSE; +static int MBflag = FALSE; +static int NDflag = FALSE; +static int CRYPTflag = FALSE; +static int CRAMflag = FALSE; +unsigned long nethold, mailhold; +int transferred = FALSE; +int batchnr = 0; + + + +int binkp(int role) +{ + int rc = 0; + fa_list *eff_remote; + file_list *tosend = NULL, *request = NULL, *respond = NULL, *tmpfl; + char *nonhold_mail; + + if (role == 1) { + Syslog('+', "BINKP start outbound session"); + IsDoing("Binkp %s outb", ascfnode(remote->addr, 0x0f)); + if (orgbinkp()) { + rc = 5; + } + } else { + Syslog('+', "BINKP start inbound session"); + IsDoing("Answer binkp"); + if (ansbinkp()) { + rc = 5; + } + } + + if (rc) { + Syslog('!', "BINKP session failed"); + return rc; + } + + if (role) { + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + } else { + nonhold_mail = (char *)ALL_MAIL; + } + + eff_remote = remote; + + /* + * Some systems hang on sending lowercase filenames, setting + * FNC forces old 8.3 uppercase filenames. + */ + if (!nodes.FNC) + remote_flags &= ~SESSION_FNC; + tosend = create_filelist(eff_remote, nonhold_mail, 0); + + request = create_freqlist(remote); + + if (request != NULL) { + Syslog('b', "Inserting request list"); + tmpfl = tosend; + tosend = request; + for (; request->next; request = request->next); + request->next = tmpfl; + + request = NULL; + } + + rc = binkp_batch(tosend); + tidy_filelist(tosend, (rc == 0)); + tosend = NULL; + + if ((rc == 0) && transferred && MBflag) { + /* + * Running Multiple Batch, only if last batch actually + * did transfer some data. + */ + respond = respond_wazoo(); + /* + * Just create the tosend list again, there may be something + * ready again for this node. + */ + tosend = create_filelist(eff_remote, nonhold_mail, 0); + for (tmpfl = tosend; tmpfl->next; tmpfl = tmpfl->next); + tmpfl->next = respond; + rc = binkp_batch(tosend); + tmpfl->next = NULL; + } + + Syslog('+', "BINKP end transfer rc=%d", rc); + closetcp(); + + if (!MBflag) { + /* + * In singe batch mode we process filerequests after the batch. + * The results will be put on hold for the calling node. + */ + respond = respond_wazoo(); + for (tmpfl = respond; tmpfl; tmpfl = tmpfl->next) { + if (strncmp(tmpfl->local, "/tmp", 4)) { + attach(*remote->addr, tmpfl->local, LEAVE, 'h'); + Syslog('+', "Put on hold: %s", MBSE_SS(tmpfl->local)); + } else { + file_mv(tmpfl->local, pktname(remote->addr, 'h')); + Syslog('+', "New netmail: %s", pktname(remote->addr, 'h')); + } + } + } + + tidy_filelist(request, (rc == 0)); + tidy_filelist(tosend, (rc == 0)); + tidy_filelist(respond, 0); + + rc = abs(rc); + return rc; +} + + + +int resync(off_t off) +{ + return 0; +} + + + +/* + * Transmit data frame + */ +void binkp_send_data(char *buf, int len) +{ + unsigned short header = 0; + + Syslog('B', "send_data(%d)", len); + header = ((BINKP_DATA_BLOCK + len) & 0xffff); + + PUTCHAR((header >> 8) & 0x00ff); + PUTCHAR(header & 0x00ff); + if (len) + PUT(buf, len); + FLUSHOUT(); + binkp_settimer(BINKP_TIMEOUT); +} + + + +/* + * Transmit control frame + */ +void binkp_send_control(int id,...) +{ + va_list args; + char *fmt, *s; + binkp_frame frame; + static char buf[1024]; + int sz; + + va_start(args, id); + fmt = va_arg(args, char*); + + if (fmt) { + vsprintf(buf, fmt, args); + sz = ((1 + strlen(buf)) & 0x7fff); + } else { + buf[0]='\0'; + sz = 1; + } + + frame.header = ((BINKP_CONTROL_BLOCK + sz) & 0xffff); + frame.id = (char)id; + frame.data = buf; + + s = (unsigned char *)malloc(sz + 2 + 1); + s[sz + 2] = '\0'; + s[0] = ((frame.header >> 8)&0xff); + s[1] = (frame.header & 0xff); + s[2] = frame.id; + if (frame.data[0]) + strncpy(s + 3, frame.data, sz-1); + + PUT(s, sz+2); + FLUSHOUT(); + + free(s); + va_end(args); + binkp_settimer(BINKP_TIMEOUT); +} + + + +/* + * Receive control frame + */ +int binkp_recv_frame(char *buf, int *len, int *cmd) +{ + int b0, b1; + + *len = *cmd = 0; + + b0 = GETCHAR(180); + if (tty_status) + goto to; + if (b0 & 0x80) + *cmd = 1; + + b1 = GETCHAR(1); + if (tty_status) + goto to; + + *len = (b0 & 0x7f) << 8; + *len += b1; + + GET(buf, *len, 120); + buf[*len] = '\0'; + if (tty_status) + goto to; + +to: + if (tty_status) + WriteError("TCP receive error: %d %s", tty_status, ttystat[tty_status]); + return tty_status; +} + + + +void binkp_settimer(int interval) +{ + Syslog('B', "Set timer %d", interval); + Timer = time((time_t*)NULL) + interval; +} + + + +int binkp_expired(void); +int binkp_expired(void) +{ + time_t now; + + (void)time(&now); + if (now >= Timer) + Syslog('b', "Timer expired"); + return (now >= Timer); +} + + + +void b_banner(int); +void b_banner(int originate) +{ + time_t t; + + binkp_send_control(MM_NUL,"SYS %s", CFG.bbs_name); + binkp_send_control(MM_NUL,"ZYZ %s", CFG.sysop_name); + binkp_send_control(MM_NUL,"LOC %s", CFG.location); + binkp_send_control(MM_NUL,"NDL %s", CFG.Flags); + time(&t); + binkp_send_control(MM_NUL,"TIME %s", rfcdate(t)); + binkp_send_control(MM_NUL,"VER mbcico/%s binkp/1.0", VERSION); + if (strlen(CFG.Phone)) + binkp_send_control(MM_NUL,"PHN %s", CFG.Phone); + if (strlen(CFG.comment)) + binkp_send_control(MM_NUL,"OPM %s", CFG.comment); +} + + + +void b_nul(char *); +void b_nul(char *msg) +{ + if (strncmp(msg, "SYS ", 4) == 0) { + Syslog('+', "System : %s", msg+4); + msg[40] = '\0'; + sprintf(history.system_name, "%s", msg+4); + } else if (strncmp(msg, "ZYZ ", 4) == 0) { + Syslog('+', "Sysop : %s", msg+4); + msg[40] = '\0'; + sprintf(history.sysop, "%s", msg+4); + } else if (strncmp(msg, "LOC ", 4) == 0) { + Syslog('+', "Location: %s", msg+4); + msg[40] = '\0'; + sprintf(history.location, "%s", msg+4); + } else if (strncmp(msg, "NDL ", 4) == 0) + Syslog('+', "Flags : %s", msg+4); + else if (strncmp(msg, "TIME ", 5) == 0) + Syslog('+', "Time : %s", msg+5); + else if (strncmp(msg, "VER ", 4) == 0) + Syslog('+', "Uses : %s", msg+4); + else if (strncmp(msg, "PHN ", 4) == 0) + Syslog('+', "Phone : %s", msg+4); + else if (strncmp(msg, "OPM ", 4) == 0) + Syslog('+', "Remark : %s", msg+4); + else if (strncmp(msg, "TRF ", 4) == 0) + Syslog('+', "Binkp: remote has %s mail/files for us", msg+4); + else if (strncmp(msg, "OPT ", 4) == 0) { + Syslog('+', "Options : %s", msg+4); + if (strstr(msg, (char *)"NR") != NULL) + NRflag = TRUE; + if (strstr(msg, (char *)"MB") != NULL) + MBflag = TRUE; + if (strstr(msg, (char *)"ND") != NULL) + NDflag = TRUE; + if (strstr(msg, (char *)"CRYPT") != NULL) + CRYPTflag = TRUE; + if (strstr(msg, (char *)"CRAM-") != NULL) { + CRAMflag = TRUE; + } + } else + Syslog('+', "M_NUL \"%s\"", msg); +} + + + +/* + * Originate a binkp session + */ +SM_DECL(orgbinkp, (char *)"orgbinkp") +SM_STATES + waitconn, + sendpass, + waitaddr, + authremote, + ifsecure, + waitok +SM_NAMES + (char *)"waitconn", + (char *)"sendpass", + (char *)"waitaddr", + (char *)"authremote", + (char *)"ifsecure", + (char *)"waitok" +SM_EDECL + faddr *primary; + char *p, *q; + int i, rc, bufl, cmd; + fa_list **tmp, *tmpa; + int SendPass = FALSE; + faddr *fa, ra; + +SM_START(waitconn) + +SM_STATE(waitconn) + + Loaded = FALSE; + Syslog('+', "Start binkp session with %s", ascfnode(remote->addr, 0x1f)); + b_banner(TRUE); +// binkp_send_control(MM_NUL,"OPT NR"); + binkp_send_control(MM_NUL,"OPT MB"); + + /* + * Build a list of aka's to send, the primary aka first. + */ + ra.zone = remote->addr->zone; + ra.net = remote->addr->net; + ra.node = remote->addr->node; + ra.point = remote->addr->point; + + primary = bestaka_s(remote->addr); + p = xstrcpy(ascfnode(primary, 0x1f)); + + for (i = 0; i < 40; i++) + if ((CFG.aka[i].zone) && (CFG.akavalid[i]) && + ((CFG.aka[i].zone != primary->zone) || + (CFG.aka[i].net != primary->net) || + (CFG.aka[i].node != primary->node) || + (CFG.aka[i].point!= primary->point))) { + p = xstrcat(p, (char *)" "); + p = xstrcat(p, aka2str(CFG.aka[i])); + } + + binkp_send_control(MM_ADR, "%s", p); + free(p); + tidy_faddr(primary); + SM_PROCEED(sendpass) + +SM_STATE(sendpass) + + if (strlen(nodes.Epasswd)) { + SendPass = TRUE; + binkp_send_control(MM_PWD, "%s", nodes.Epasswd); + } else + binkp_send_control(MM_PWD, "-"); + + SM_PROCEED(waitaddr) + +SM_STATE(waitaddr) + + for (;;) { + if ((rc = binkp_recv_frame(rbuf, &bufl, &cmd))) { + Syslog('!', "Error receiving remote info"); + SM_ERROR; + } + + if (cmd) { + if (rbuf[0] == MM_ADR) { + p = xstrcpy(&rbuf[1]); + tidy_falist(&remote); + remote = NULL; + tmp = &remote; + + for (q = strtok(p, " "); q; q = strtok(NULL, " ")) + if ((fa = parsefnode(q))) { + *tmp = (fa_list*)malloc(sizeof(fa_list)); + (*tmp)->next = NULL; + (*tmp)->addr = fa; + tmp = &((*tmp)->next); + } else { + Syslog('!', "Bad remote address: \"%s\"", printable(q, 0)); + binkp_send_control(MM_ERR, "Bad address"); + } + + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + Syslog('+', "Address : %s", ascfnode(tmpa->addr, 0x1f)); + if (nodelock(tmpa->addr)) { + binkp_send_control(MM_BSY, "Address %s locked", ascfnode(tmpa->addr, 0x1f)); + } + + /* + * With the loaded flag we prevent removing the noderecord + * when the remote presents us an address we don't know about. + */ + if (!Loaded) { + if (noderecord(tmpa->addr)) + Loaded = TRUE; + } + } + + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + sprintf(history.aka.domain, "%s", remote->addr->domain); + + SM_PROCEED(authremote) + + } else if (rbuf[0] == MM_BSY) { + Syslog('!', "Remote is busy"); + SM_ERROR; + + } else if (rbuf[0] == MM_ERR) { + Syslog('!', "Remote error: %s", &rbuf[1]); + SM_ERROR; + + } else if (rbuf[0] == MM_NUL) { + b_nul(&rbuf[1]); + } + } + } + +SM_STATE(authremote) + + rc = 0; + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + if ((tmpa->addr->zone == ra.zone) && + (tmpa->addr->net == ra.net) && + (tmpa->addr->node == ra.node) && + (tmpa->addr->point == ra.point)) { + rc = 1; + } + } + + if (rc) { + SM_PROCEED(ifsecure) + } else { + Syslog('!', "Error: the wrong node is reached"); + binkp_send_control(MM_ERR, "No AKAs in common or all AKAs busy"); + SM_ERROR; + } + +SM_STATE(ifsecure) + + if (SendPass) { + SM_PROCEED(waitok) + } + SM_SUCCESS; + +SM_STATE(waitok) + + for (;;) { + if ((rc = binkp_recv_frame(rbuf, &bufl, &cmd))) { + Syslog('!', "Error waiting for remote acknowledge"); + SM_ERROR; + } + + if (cmd) { + if (rbuf[0] == MM_OK) { + Syslog('+', "Password protected session"); + SM_SUCCESS; + + } else if (rbuf[0] == MM_BSY) { + Syslog('!', "Remote is busy"); + SM_ERROR; + + } else if (rbuf[0] == MM_ERR) { + Syslog('!', "Remote error: %s", &rbuf[1]); + SM_ERROR; + + } else if (rbuf[0] == MM_NUL) { + b_nul(&rbuf[1]); + } + } + } + +SM_END +SM_RETURN + + + +/* + * Answer a binkp session + */ +SM_DECL(ansbinkp, (char *)"ansbinkp") +SM_STATES + waitconn, + waitaddr, + ispasswd, + waitpwd, + pwdack +SM_NAMES + (char *)"waitconn", + (char *)"waitaddr", + (char *)"ispasswd", + (char *)"waitpwd", + (char *)"pwdack" + +SM_EDECL + char *p, *q; + int i, rc, bufl, cmd; + fa_list **tmp, *tmpa; + faddr *fa; + +SM_START(waitconn) + +SM_STATE(waitconn) + + Loaded = FALSE; + b_banner(FALSE); + p = xstrcpy((char *)""); + + for (i = 0; i < 40; i++) + if ((CFG.aka[i].zone) && (CFG.akavalid[i])) { + p = xstrcat(p, (char *)" "); + p = xstrcat(p, aka2str(CFG.aka[i])); + } + + binkp_send_control(MM_ADR, "%s", p); + free(p); + SM_PROCEED(waitaddr) + +SM_STATE(waitaddr) + + for (;;) { + if ((rc = binkp_recv_frame(rbuf, &bufl, &cmd))) { + Syslog('!', "Error waiting for remote info"); + SM_ERROR; + } + + if (cmd) { + if (rbuf[0] == MM_ADR) { + p = xstrcpy(&rbuf[1]); + tidy_falist(&remote); + remote = NULL; + tmp = &remote; + + for (q = strtok(p, " "); q; q = strtok(NULL, " ")) + if ((fa = parsefnode(q))) { + *tmp = (fa_list*)malloc(sizeof(fa_list)); + (*tmp)->next = NULL; + (*tmp)->addr = fa; + tmp = &((*tmp)->next); + } else { + Syslog('!', "Bad remote address: \"%s\"", printable(q, 0)); + binkp_send_control(MM_ERR, "Bad address"); + } + + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + Syslog('+', "Address : %s", ascfnode(tmpa->addr, 0x1f)); + if (nodelock(tmpa->addr)) { + binkp_send_control(MM_BSY, "Address %s locked", ascfnode(tmpa->addr, 0x1f)); + } + + /* + * With the loaded flag we prevent removing the noderecord + * when the remote presents us an address we don't know about. + */ + if (!Loaded) { + if (noderecord(tmpa->addr)) + Loaded = TRUE; + } + } + + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + if (((nlent = getnlent(tmpa->addr))) && + (nlent->pflag != NL_DUMMY)) { + Syslog('+', "Remote is a listed system"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); + break; + } + } + if (nlent) + rdoptions(Loaded); + + if (MBflag) { + Syslog('b', "Remote supports MB"); + binkp_send_control(MM_NUL,"OPT MB"); + } + + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + sprintf(history.aka.domain, "%s", remote->addr->domain); + + SM_PROCEED(ispasswd) + + } else if (rbuf[0] == MM_ERR) { + Syslog('!', "Remote error: %s", &rbuf[1]); + SM_ERROR; + + } else if (rbuf[0] == MM_NUL) { + b_nul(&rbuf[1]); + } + } + } + +SM_STATE(ispasswd) + + if (!Loaded && !strlen(nodes.Epasswd)) { + Syslog('+', "Unprotected session"); + SM_SUCCESS; + } + SM_PROCEED(waitpwd) + +SM_STATE(waitpwd) + + for (;;) { + if ((rc = binkp_recv_frame(rbuf, &bufl, &cmd))) { + Syslog('!', "Error waiting for password"); + SM_ERROR; + } + + if (cmd) { + if (rbuf[0] == MM_PWD) { + SM_PROCEED(pwdack) + + } else if (rbuf[0] == MM_ERR) { + Syslog('!', "Remote error: %s", &rbuf[1]); + SM_ERROR; + + } else if (rbuf[0] == MM_NUL) { + b_nul(&rbuf[1]); + } + } + } + +SM_STATE(pwdack) + if (strcmp(&rbuf[1], nodes.Epasswd) == 0) { + Syslog('+', "Password OK, protected BINKP session"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); + binkp_send_control(MM_OK, ""); + SM_SUCCESS; + } else { + Syslog('?', "Password error: expected \"%s\", got \"%s\"", nodes.Epasswd, &rbuf[1]); + binkp_send_control(MM_ERR, "*** Password error, check setup ***"); + SM_ERROR; + } + +SM_END + +SM_RETURN + + + +void fill_binkp_list(binkp_list **, file_list *, off_t); +void fill_binkp_list(binkp_list **bll, file_list *fal, off_t offs) +{ + binkp_list **tmpl; + struct stat tstat; + + if (stat(fal->local, &tstat) != 0) { + Syslog('!', "$Can't add %s to sendlist", fal->local); + exit; + } + if (strstr(fal->remote, (char *)".pkt")) + nethold += tstat.st_size; + else + mailhold += tstat.st_size; + + for (tmpl = bll; *tmpl; tmpl = &((*tmpl)->next)); + *tmpl = (binkp_list *)malloc(sizeof(binkp_list)); + + (*tmpl)->next = NULL; + (*tmpl)->state = NoState; + (*tmpl)->get = FALSE; + (*tmpl)->local = xstrcpy(fal->local); + (*tmpl)->remote = xstrcpy(fal->remote); + (*tmpl)->offset = offs; + (*tmpl)->size = tstat.st_size; + (*tmpl)->date = tstat.st_mtime; +} + + + +char *lbstat[]={(char *)"None", + (char *)"Sending", + (char *)"IsSent", + (char *)"Got", + (char *)"Skipped", + (char *)"Get"}; + + +void debug_binkp_list(binkp_list **); +void debug_binkp_list(binkp_list **bll) +{ + binkp_list *tmpl; + + Syslog('B', "Current filelist:"); + + for (tmpl = *bll; tmpl; tmpl = tmpl->next) + Syslog('B', "%s %s %s %ld", MBSE_SS(tmpl->local), MBSE_SS(tmpl->remote), lbstat[tmpl->state], tmpl->offset); +} + + + +int binkp_batch(file_list *to_send) +{ + int rc = 0, NotDone; + static char *txbuf, *rxbuf; + FILE *txfp = NULL; + FILE *rxfp = NULL; + int rxlen = 0, txlen = 0; + long txpos = 0, rxpos = 0; + long stxpos = 0; + time_t rxstarttime, rxendtime; + time_t txstarttime, txendtime; + int sverr, cmd = FALSE, GotFrame = FALSE; + int blklen = 0, c, Found = FALSE; + unsigned short header = 0; + char *rname, *lname; + long rsize, roffs, lsize; + time_t rtime, ltime; + long rxbytes, written; + binkp_list *bll = NULL, *tmp, *cursend = NULL; + file_list *tsl; + + batchnr++; + Syslog('+', "Binkp: starting batch %d", batchnr); + txbuf = calloc(MAX_BLKSIZE + 3, sizeof(unsigned char)); + rxbuf = calloc(MAX_BLKSIZE + 3, sizeof(unsigned char)); + rname = calloc(512, sizeof(char)); + lname = calloc(512, sizeof(char)); + TfState = Switch; + RxState = RxWaitFile; + TxState = TxGetNextFile; + binkp_settimer(BINKP_TIMEOUT); + nethold = mailhold = 0L; + transferred = FALSE; + + /* + * Build a new filelist from the existing filelist. + * This one is special for binkp behaviour. + */ + for (tsl = to_send; tsl; tsl = tsl->next) { + if (tsl->remote != NULL) + fill_binkp_list(&bll, tsl, 0L); + } + debug_binkp_list(&bll); + + Syslog('+', "Binkp: mail %ld, files %ld bytes", nethold, mailhold); + binkp_send_control(MM_NUL, "TRF %ld %ld", nethold, mailhold); + + while ((RxState != RxDone) || (TxState != TxDone)) { + + if (binkp_expired()) { + Syslog('!', "Binkp: Transfer timeout"); + Syslog('b', "Binkp: TxState=%d, RxState=%d, rxlen=%d", TxState, RxState, rxlen); + RxState = RxDone; + TxState = TxDone; + binkp_send_control(MM_ERR, "Transfer timeout"); + rc = -2; + break; + } + + /* + * Receiver binkp frame + */ + for (;;) { + if (GotFrame) { + Syslog('b', "WARNING: frame not processed"); + break; + } else { + c = GETCHAR(0); + if (c < 0) { + c = -c; + if (c == STAT_TIMEOUT) { + usleep(1); + break; + } + Syslog('?', "Binkp: receiver status %s", ttystat[c]); + TxState = TxDone; + RxState = RxDone; + rc = -c; + break; + } else { + switch (rxlen) { + case 0: header = c << 8; + break; + case 1: header += c; + break; + default:rxbuf[rxlen-2] = c; + } + if (rxlen == 1) { + cmd = header & 0x8000; + blklen = header & 0x7fff; + } + if ((rxlen == (blklen + 1) && (rxlen >= 1))) { + GotFrame = TRUE; + binkp_settimer(BINKP_TIMEOUT); + rxbuf[rxlen-1] = '\0'; + break; + } + rxlen++; + } + } + } + + /* + * Transmitter state machine + */ + switch (TxState) { + case TxGetNextFile: + for (tmp = bll; tmp; tmp = tmp->next) { + if (tmp->state == NoState) { + /* + * There is something to send + */ + struct flock txflock; + + txflock.l_type = F_RDLCK; + txflock.l_whence = 0; + txflock.l_start = 0L; + txflock.l_len = 0L; + + txfp = fopen(tmp->local, "r"); + if (txfp == NULL) { + sverr = errno; + if ((sverr == ENOENT) || (sverr == EINVAL)) { + Syslog('+', "Binkp: file %s doesn't exist, removing", MBSE_SS(tmp->local)); + tmp->state = Got; + } else { + WriteError("$Binkp: can't open %s, skipping", MBSE_SS(tmp->local)); + tmp->state = Skipped; + } + break; + } + + if (fcntl(fileno(txfp), F_SETLK, &txflock) != 0) { + WriteError("$Binkp: can't lock file %s, skipping", MBSE_SS(tmp->local)); + fclose(txfp); + tmp->state = Skipped; + break; + } + + txpos = stxpos = tmp->offset; + Syslog('+', "Binkp: send \"%s\" as \"%s\"", MBSE_SS(tmp->local), MBSE_SS(tmp->remote)); + Syslog('+', "Binkp: size %lu bytes, dated %s", (unsigned long)tmp->size, date(tmp->date)); + binkp_send_control(MM_FILE, "%s %lu %ld %ld", MBSE_SS(tmp->remote), + (unsigned long)tmp->size, (long)tmp->date, (unsigned long)tmp->offset); + (void)time(&txstarttime); + tmp->state = Sending; + cursend = tmp; + TxState = TxTryRead; + transferred = TRUE; + break; + } /* if state == NoState */ + } /* for */ + + if (tmp == NULL) { + /* + * No more files to send + */ + TxState = TxWaitLastAck; + Syslog('b', "Binkp: transmitter to WaitLastAck"); + } + break; + + case TxTryRead: + /* + * Check if there is room in the output buffer + */ + if ((WAITPUTGET(-1) & 2) != 0) + TxState = TxReadSend; + break; + + case TxReadSend: + Nopper(); + fseek(txfp, txpos, SEEK_SET); + txlen = fread(txbuf, 1, SND_BLKSIZE, txfp); + + if (txlen == 0) { + + if (ferror(txfp)) { + WriteError("$Binkp: error reading from file"); + TxState = TxGetNextFile; + cursend->state = Skipped; + debug_binkp_list(&bll); + break; + } + + /* + * Send empty dataframe, most binkp mailers need it to detect EOF. + */ + binkp_send_data(txbuf, 0); + + /* + * calculate time needed and bytes transferred + */ + (void)time(&txendtime); + txstarttime = txendtime - txstarttime; + if (txstarttime <= 0L) + txstarttime = 1L; + + /* + * Close transmitter file + */ + fclose(txfp); + + if (txpos >= 0) { + stxpos = txpos - stxpos; + Syslog('+', "Binkp: OK %lu bytes send in %s (%ld cps)", + stxpos, str_time(txstarttime), stxpos/txstarttime); + } else { + Syslog('+', "Binkp: transmitter skipped file after %ld seconds", txstarttime); + } + + cursend->state = IsSent; + TxState = TxGetNextFile; + break; + } else { + txpos += txlen; + sentbytes += txlen; + binkp_send_data(txbuf, txlen); + } + + TxState = TxTryRead; + break; + + case TxWaitLastAck: + debug_binkp_list(&bll); + NotDone = FALSE; + for (tmp = bll; tmp; tmp = tmp->next) + if ((tmp->state != Got) && (tmp->state != Skipped)) { + NotDone = TRUE; + break; + } + Syslog('B', "NotDone=%s", NotDone ? "True" : "False"); + if (tmp == NULL) { + TxState = TxDone; + binkp_send_control(MM_EOB, ""); + Syslog('+', "Binkp: sending EOB"); + } else { + Syslog('b', "tmp != NULL"); + } + break; + + case TxDone: + break; + } + + /* + * Process received frame + */ + if (GotFrame) { + if (cmd) { + switch (rxbuf[0]) { + case MM_ERR: Syslog('+', "Binkp: got ERR: %s", rxbuf+1); + RxState = RxDone; + TxState = TxDone; + break; + + case MM_BSY: Syslog('+', "Binkp: got BSY: %s", rxbuf+1); + RxState = RxDone; + TxState = TxDone; + break; + + case MM_SKIP: Syslog('+', "Got SKIP frame"); + break; + + case MM_GET: Syslog('+', "Got GET frame"); + break; + + case MM_GOT: sscanf(rxbuf+1, "%s %ld %ld", lname, &lsize, <ime); + Found = FALSE; + for (tmp = bll; tmp; tmp = tmp->next) + if ((strcmp(lname, tmp->remote) == 0) && + (lsize == tmp->size) && (ltime == tmp->date)) { + Syslog('+', "Binkp: remote GOT \"%s\"", + tmp->remote); + tmp->state = Got; + Found = TRUE; + } + if (!Found) { + Syslog('!', "Binkp: unexpected GOT \"%s\"", rxbuf+1); + } + break; + + case MM_NUL: b_nul(rxbuf+1); + break; + + case MM_EOB: Syslog('+', "Binkp: received EOB"); + RxState = RxEndOfBatch; + break; + + case MM_FILE: if ((RxState == RxWaitFile) || (RxState == RxEndOfBatch)) { + RxState = RxAcceptFile; + sscanf(rxbuf+1, "%s %ld %ld %ld", rname, &rsize, &rtime, &roffs); + } else { + Syslog('+', "Binkp: got unexpected FILE frame %s", rxbuf+1); + } + break; + + default: Syslog('+', "Binkp: Unexpected frame %d", rxbuf[0]); + } + } else { + if (blklen) { + if (RxState == RxReceData) { + written = fwrite(rxbuf, 1, blklen, rxfp); + if (!written && blklen) { + Syslog('+', "Binkp: file write error"); + RxState = RxDone; + } + rxpos += written; + if (rxpos == rsize) { + binkp_send_control(MM_GOT, "%s %ld %ld", rname, rsize, rtime); + closefile(TRUE); + rxpos = rxpos - rxbytes; + (void)time(&rxendtime); + if ((rxstarttime = rxendtime - rxstarttime) == 0L) + rxstarttime = 1L; + Syslog('+', "Binkp: received OK %lu bytes in %s (%ld cps)", + rxpos, str_time(rxstarttime), rxpos / rxstarttime); + rcvdbytes += rxpos; + RxState = RxWaitFile; + transferred = TRUE; + } + } else { + Syslog('+', "Binkp: unexpected DATA frame %d", rxbuf[0]); + } + } + } + GotFrame = FALSE; + rxlen = 0; + header = 0; + blklen = 0; + } + + switch (RxState) { + case RxWaitFile: + break; + + case RxAcceptFile: + Syslog('+', "Binkp: receive file \"%s\" date %s size %ld offset %ld", rname, date(rtime), rsize, roffs); + rxfp = openfile(rname, rtime, rsize, &rxbytes, resync); + (void)time(&rxstarttime); + rxpos = 0; + + if (!diskfree(CFG.freespace)) { + Syslog('+', "Binkp: low diskspace, sending BSY"); + binkp_send_control(MM_BSY, "Low diskspace, try again later"); + RxState = RxDone; + TxState = TxDone; + break; + } + + if (rsize == rxbytes) { + /* + * We already got this file, send GOT so it will + * be deleted at the remote. + */ + Syslog('+', "Binkp: already got %s, sending GOT", rname); + binkp_send_control(MM_GOT, "%s %ld %ld", rname, rsize, rtime); + RxState = RxWaitFile; + rxfp = NULL; + } else if (!rxfp) { + /* + * Some error, request to skip it + */ + Syslog('+', "Binkp: error file %s, sending SKIP", rname); + binkp_send_control(MM_SKIP, "%s %ld %ld", rname, rsize, rtime); + RxState = RxWaitFile; + } else { + RxState = RxReceData; + } + break; + + case RxReceData: + break; + + case RxEndOfBatch: + if (TxState == TxDone) + RxState = RxDone; + break; + + case RxDone: + break; + } + } + + debug_binkp_list(&bll); + + /* + * Process all send files. + */ + for (tsl = to_send; tsl; tsl = tsl->next) { + if (tsl->remote == NULL) { + execute_disposition(tsl); + } else { + for (tmp = bll; tmp; tmp = tmp->next) { + if ((strcmp(tmp->local, tsl->local) == 0) && + ((tmp->state == Got) || (tmp->state == Skipped))) { + execute_disposition(tsl); + } + } + } + } + + for (tmp = bll; bll; bll = tmp) { + tmp = bll->next; + if (bll->local) + free(bll->local); + if (bll->remote) + free(bll->remote); + free(bll); + } + + free(txbuf); + free(rxbuf); + free(rname); + free(lname); + Syslog('+', "Binkp: batch %d completed rc=%d", batchnr, rc); + return rc; +} + + diff --git a/mbcico/binkp.h b/mbcico/binkp.h new file mode 100644 index 00000000..f33201f8 --- /dev/null +++ b/mbcico/binkp.h @@ -0,0 +1,84 @@ +#ifndef _BINKP_H +#define _BINKP_H + +/* + + 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 + +-+-------+--------+--- ... ---+ + + */ + + +/* protocol version */ +#define BINKP_VERSION "1.1" + +#define MAX_BLKSIZE 0x7fff /* Don't change! */ +#define BLK_HDR_SIZE 2 /* 2 bytes header */ +#define BINKP_TIMEOUT 180 /* Global timeout value */ +#define SND_BLKSIZE 4096 /* Blocksize transmitter */ + +#define MM_NUL 0 /* Ignored by binkp (data optionally logged) */ +#define MM_ADR 1 /* System aka's */ +#define MM_PWD 2 /* Password */ +#define MM_FILE 3 +#define MM_OK 4 /* The password is ok (data ignored) */ +#define MM_EOB 5 /* End-of-batch (data ignored) */ +#define MM_GOT 6 /* File received */ +#define MM_ERR 7 /* Misc errors */ +#define MM_BSY 8 /* All AKAs are busy */ +#define MM_GET 9 /* Get a file from offset */ +#define MM_SKIP 10 /* Skip a file */ +#define MM_MAX 10 + +#define MM_DATA 0xff + +#define BINKP_DATA_BLOCK 0x0000 +#define BINKP_CONTROL_BLOCK 0x8000 + + +typedef struct _binkp_frame { + unsigned short header; + unsigned char id; + unsigned char *data; +} binkp_frame; + + + +/* + * Linked list of files to send and responses from the receiver. + */ +typedef enum {NoState, Sending, IsSent, Got, Skipped, Get} FileState; + +typedef struct _binkp_list { + struct _binkp_list *next; + char *remote; /* Remote filename */ + char *local; /* Local filename */ + int state; /* File state */ + int get; /* Boolean GET flag */ + off_t size; /* File size */ + time_t date; /* File date & time */ + off_t offset; /* Start offset */ +} binkp_list; + + + +/* + * state.NR_flag: state of binkp when in NR mode + */ +#define NO_NR 0 +#define WANT_NR 1 +#define WE_NR 2 +#define THEY_NR 3 + + +int binkp(int); + +#endif + diff --git a/mbcico/call.c b/mbcico/call.c new file mode 100644 index 00000000..493433fb --- /dev/null +++ b/mbcico/call.c @@ -0,0 +1,380 @@ +/***************************************************************************** + * + * File ..................: mbcico/call.c + * Purpose ...............: Fidonet mailer + * Last modification date : 22-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "session.h" +#include "callstat.h" +#include "call.h" +#include "config.h" +#include "dial.h" +#include "lutil.h" +#include "portsel.h" +#include "openport.h" +#include "opentcp.h" +#include "rdoptions.h" + + +extern int tcp_mode; +extern int forcedcalls; +extern int immediatecall; +extern char *forcedphone; +extern char *forcedline; +extern char *inetaddr; + + +int checkretry(callstat *); +int checkretry(callstat *st) +{ + Syslog('d', "Checkretry nr %d status %d", st->tryno, st->trystat); + if (st->tryno > 30) + return 2; + return 0; + /* check retries and time; rc=1 - not reached, rc=2 - undialable */ +} + + + +int portopen(faddr *addr) +{ + char *p, *q; + int rc, speed; + pp_list *pl = NULL, *tmp; + + if (inetaddr) { + Syslog('d', "portopen inetaddr %s", inetaddr); + if ((rc = opentcp(inetaddr))) { + Syslog('+', "Cannot connect %s", inetaddr); + nodeulock(addr); + putstatus(addr,1,ST_NOCONN); + return ST_NOCONN; + } + return 0; + } + + if (forcedline) { + Syslog('d', "portopen forcedline %s", forcedline); + p = forcedline; + if ((q = strchr(p, ':'))) { /* Note: DIT KAN WEG ! */ + *q++ = '\0'; + if ((*q == 'l') || (*q == 'L')) + speed=atoi(++q); + else { + speed = atoi(q); + if (nlent->speed < speed) + speed = nlent->speed; + } + } + + if (load_port(p)) { + speed = ttyinfo.portspeed; + rc = openport(p,speed); + if (rc) { + Syslog('+', "Cannot open port %s",p); + nodeulock(addr); + putstatus(addr, 10, ST_PORTERR); + return ST_PORTERR; + } + return 0; + } else { + nodeulock(addr); + putstatus(addr, 0, ST_PORTERR); + return ST_PORTERR; + } + } + + if (make_portlist(nlent, &pl) == 0) { + WriteError("No matching ports defined"); + nodeulock(addr); + putstatus(addr, 10, ST_NOPORT); + return ST_NOPORT; + } + + for (tmp = pl; tmp; tmp = tmp->next) { + if (load_port(tmp->tty)) { + Syslog('+', "Port %s at %ld, modem %s", ttyinfo.tty, ttyinfo.portspeed, modem.modem); + p = xstrcpy(tmp->tty); + speed = ttyinfo.portspeed; + rc = openport(p, speed); + free(p); + if (rc == 0) { + tidy_pplist(&pl); + return 0; + } + } + } + + tidy_pplist(&pl); + nodeulock(addr); + putstatus(addr, 0, ST_PORTERR); + return ST_PORTERR; +} + + + +int call(faddr *addr) +{ + int i, j, rc = 1; + callstat *st; + struct hostent *he; + + /* + * Don't call points, call their boss instead. + */ + addr->point = 0; + + /* + * First check if node is locked, if not lock it immediatly + * or stop further waste of time and logfile space. + */ + if (nodelock(addr)) { + Syslog('+', "System %s is locked", ascfnode(addr, 0x1f)); + putstatus(addr, 0, ST_LOCKED); + return ST_LOCKED; + } + nodeulock(addr); + + if ((nlent = getnlent(addr)) == NULL) { + WriteError("Cannot call %s: fatal in nodelist lookup", ascfnode(addr, 0x1f)); + putstatus(addr,0,ST_LOOKUP); + return ST_LOOKUP; + } + + /* + * Load the noderecord if the node is in the setup. + */ + noderecord(addr); + rdoptions(TRUE); + + /* + * Fill default history info in case we get a FTS0001 session + */ + sprintf(history.system_name, "%s", nlent->name); + sprintf(history.location, "%s", nlent->location); + history.aka.zone = addr->zone; + history.aka.net = addr->net; + history.aka.node = addr->node; + history.aka.point = addr->point; + if (addr->domain && strlen(addr->domain)) + sprintf(history.aka.domain, "%s", addr->domain); + + /* + * First see if this node can be reached over the internet and + * that internet calls are allowed. + */ + if (nlent->iflags && ((localoptions & NOTCP) == 0)) { + if (!inetaddr) { + Syslog('d', "Trying to find IP address..."); + /* + * There is no fdn or IP address at the commandline. + * First check nodesetup for an override in the phone field. + */ + if (strlen(nodes.phone[0])) { + inetaddr = xstrcpy(nodes.phone[0]); + } else if (strlen(nodes.phone[1])) { + inetaddr = xstrcpy(nodes.phone[1]); + } else { + /* + * Try to find the fdn in several places in the nodelist fields. + */ + if ((nlent->phone != NULL) && (strncmp(nlent->phone, (char *)"000-", 4) == 0)) { + inetaddr = xstrcpy(nlent->phone+4); + for (i = 0; i < strlen(inetaddr); i++) + if (inetaddr[i] == '-') + inetaddr[i] = '.'; + Syslog('d', "Got IP address from phone field"); + } else if ((he = gethostbyname(nlent->name))) { + inetaddr = xstrcpy(nlent->name); + Syslog('d', "Got hostname from nodelist system name"); + } else if ((he = gethostbyname(nlent->location))) { + /* + * A fdn at the nodelist location field is not in the specs + * but the real world differs from the specs. + */ + inetaddr = xstrcpy(nlent->location); + Syslog('d', "Got hostname from nodelist location"); + } + } + } + + /* + * If we have an internet address, set protocol + */ + if (inetaddr) { + Syslog('d', "TCP/IP node \"%s\"", MBSE_SS(inetaddr)); + + if (tcp_mode == TCPMODE_NONE) { + /* + * If protocol not forced at the commandline, get it + * from the nodelist. If it fails, fallback to dial. + * Priority IBN, IFC, ITN. + */ + if (nlent->iflags & IP_IBN) + tcp_mode = TCPMODE_IBN; + else if (nlent->iflags & IP_IFC) + tcp_mode = TCPMODE_IFC; + else if (nlent->iflags & IP_ITN) + tcp_mode = TCPMODE_ITN; + else { + Syslog('+', "No common TCP/IP protocols for node %s", nlent->name); + free(inetaddr); + inetaddr = NULL; + } + Syslog('d', "TCP mode set to %d", tcp_mode); + } + } else { + Syslog('d', "No IP address, fallback to dial"); + tcp_mode = TCPMODE_NONE; + } + } + + if (((nlent->oflags & OL_CM) == 0) && (!IsZMH())) { + if (!forcedcalls) { + Syslog('d', "Node is ZMH only and it is not ZMH"); + nodeulock(addr); + putstatus(addr,0,ST_NOTZMH); + return ST_NOTZMH; + } + Syslog('?', "Warning: calling MO system outside ZMH"); + } + + st = getstatus(addr); + if ((rc = checkretry(st))) { + Syslog('+', "Cannot call %s: %s", ascfnode(addr,0x1f), (rc == 1)?"retry time not reached":"node undialable"); + return 5; + } + + /* + * Over TCP/IP we don't do a delay because the node we are + * connecting can't be busy. Also forced calls don't delay. + */ + Syslog('d', "delay=%d inetaddr=%s immediatecall=%s", + CFG.dialdelay, inetaddr?"true":"false", immediatecall?"true":"false"); + if ((CFG.dialdelay > 10) && (!inetaddr) && (!immediatecall)) { + /* + * Generate a random number between CFG.dialdelay and + * CFG.dialdelay / 10, minimum value is 10. + */ + srand(getpid()); + while (TRUE) { + j = 1+(int) (1.0 * CFG.dialdelay * rand() / (RAND_MAX + 1.0)); + if ((j > (CFG.dialdelay / 10)) && (j > 9)) + break; + } + Syslog('d', "Dial delay %d seconds", j); + + for (i = j; i > 0; i--) { + IsDoing("Delay %d seconds", i); + sleep(1); + } + } + + if (nodelock(addr)) { + Syslog('+', "System %s is locked", ascfnode(addr, 0x1f)); + putstatus(addr, 0, ST_LOCKED); + return ST_LOCKED; + } + + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); /* master sessions are secure */ + + /* + * Call when: + * the nodelist has a phone, or phone on commandline, or TCP address given + * and + * nodenumber on commandline, or node is CM and not down, hold, pvt + * and + * nocall is false + */ + if ((nlent->phone || forcedphone || inetaddr ) && ((forcedcalls || (nlent->oflags & OL_CM)) || + (((nlent->pflag & (NL_DUMMY|NL_DOWN|NL_HOLD|NL_PVT)) == 0) && ((localoptions & NOCALL) == 0)))) { + Syslog('+', "Calling %s (%s, phone %s)",ascfnode(addr,0x1f), nlent->name,nlent->phone?nlent->phone:forcedphone); + IsDoing("Call %s", ascfnode(addr, 0x0f)); + rc = portopen(addr); + + if ((rc == 0) && (!inetaddr)) { + if ((rc = dialphone(forcedphone?forcedphone:nlent->phone))) { + Syslog('+', "Dial failed"); + nodeulock(addr); + rc+=1; /* rc=2 - dial fail, rc=3 - could not reset */ + } + } + + if (rc == 0) { + if (!inetaddr) + nolocalport(); + + if (tcp_mode == TCPMODE_IBN) + rc = session(addr,nlent,SESSION_MASTER,SESSION_BINKP,NULL); + else + rc = session(addr,nlent,SESSION_MASTER,SESSION_UNKNOWN,NULL); + + if (rc) + rc=abs(rc)+10; + } + + IsDoing("Disconnect"); + if (inetaddr) { + closetcp(); + } else { + hangup(); + if (rc == 0) + aftercall(); + localport(); + closeport(); + } + } else { + IsDoing("NoCall"); + Syslog('+', "Cannot call %s (%s, phone %s)", ascfnode(addr,0x1f),MBSE_SS(nlent->name), MBSE_SS(nlent->phone)); + if ((nlent->phone || forcedphone || inetaddr )) + rc=ST_NOCALL8; + else + rc=ST_NOCALL7; + putstatus(addr, 10, rc); + nodeulock(addr); + return rc; + } + + if ((rc > 10) && (rc < 20)) /* Session error */ + putstatus(addr, 5, rc); + else if ((rc == 2) || (rc == 30)) + putstatus(addr,1,rc); + else + putstatus(addr,0,rc); + return rc; +} + + diff --git a/mbcico/call.h b/mbcico/call.h new file mode 100644 index 00000000..70d113bf --- /dev/null +++ b/mbcico/call.h @@ -0,0 +1,10 @@ +#ifndef _CALL_H +#define _CALL_H + + +int call(faddr *); + + +#endif + + diff --git a/mbcico/callall.c b/mbcico/callall.c new file mode 100644 index 00000000..05551bc8 --- /dev/null +++ b/mbcico/callall.c @@ -0,0 +1,146 @@ +/***************************************************************************** + * + * File ..................: mbcico/callall.c + * Purpose ...............: Fidonet mailer + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "config.h" +#include "../lib/clcomm.h" +#include "scanout.h" +#include "lutil.h" +#include "callstat.h" +#include "callall.h" + + +static int each(faddr*, char, int, char*); +static fa_list *alist = NULL; + + + +fa_list *callall(void) +{ + fa_list *tmp; + int rc; + + if (alist) { + for (tmp = alist; tmp; tmp = alist) { + alist = tmp->next; + tidy_faddr(tmp->addr); + free(tmp); + } + alist = NULL; + } + + if ((rc = scanout(each))) { + WriteError("Error scanning outbound, aborting"); + return NULL; + } + + return (fa_list *)alist; +} + + + +static int each(faddr *addr, char flavor, int isflo, char *fname) +{ + fa_list **tmp; + callstat *st; + + if ((flavor == 'h') || + ((isflo != OUT_PKT) && (isflo != OUT_FLO) && (isflo != OUT_POL))) + return 0; + + /* + * Outside Zone Mail Hour normal flavor will be hold. + */ + if (!IsZMH() && (flavor == 'o')) + return 0; + + /* + * During ZMH only poll and .pkt files will be sent, except + * IMMediate mail, that goes always. + */ + if (flavor != 'i') { + if (IsZMH() && (isflo == OUT_FLO)) + return 0; + } + + /* + * Don't add nodes who are undiable + */ + st = getstatus(addr); + if (st->tryno >= 30) + return 0; + + for (tmp = &alist; *tmp; tmp=&((*tmp)->next)) + if (((*tmp)->addr->zone == addr->zone) && + ((*tmp)->addr->net == addr->net) && + ((*tmp)->addr->node == addr->node) && + ((*tmp)->addr->point == addr->point) && + (((*tmp)->addr->domain == NULL) || + (addr->domain == NULL) || + (strcasecmp((*tmp)->addr->domain,addr->domain) == 0))) + break; + + if (*tmp == NULL) { + *tmp=(fa_list *)malloc(sizeof(fa_list)); + (*tmp)->next=NULL; + (*tmp)->addr=(faddr *)malloc(sizeof(faddr)); + (*tmp)->addr->name=NULL; + (*tmp)->addr->zone=addr->zone; + (*tmp)->addr->net=addr->net; + (*tmp)->addr->node=addr->node; + (*tmp)->addr->point=addr->point; + (*tmp)->addr->domain=xstrcpy(addr->domain); + if (flavor == 'i') + (*tmp)->force = TRUE; + else + (*tmp)->force = FALSE; + if (isflo == OUT_POL) + (*tmp)->force = TRUE; + + switch (flavor) { + case 'i': Syslog('+', "Immediate mail to %s", ascfnode((*tmp)->addr,0x1f)); + break; + case 'c': Syslog('+', "Crash mail to %s", ascfnode((*tmp)->addr,0x1f)); + break; + case 'o': Syslog('+', "Normal mail to %s",ascfnode((*tmp)->addr,0x1f)); + break; + case 'p': Syslog('+', "Poll request to %s",ascfnode((*tmp)->addr,0x1f)); + break; + default : Syslog('+', "Some mail (%c) to %s",flavor,ascfnode((*tmp)->addr,0x1f)); + } + } + + return 0; +} + + diff --git a/mbcico/callall.h b/mbcico/callall.h new file mode 100644 index 00000000..d5dd56a4 --- /dev/null +++ b/mbcico/callall.h @@ -0,0 +1,9 @@ +#ifndef _CALLALL_H +#define _CALLALL_H + + +fa_list *callall(void); + + +#endif + diff --git a/mbcico/callstat.c b/mbcico/callstat.c new file mode 100644 index 00000000..acb306d9 --- /dev/null +++ b/mbcico/callstat.c @@ -0,0 +1,82 @@ +/***************************************************************************** + * + * File ..................: mbcico/callstat.c + * Purpose ...............: Fidonet mailer + * Last modification date : 13-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "callstat.h" + + + +callstat *getstatus(faddr *addr) +{ + static callstat cst; + FILE *fp; + + cst.trytime = 0L; + cst.tryno = 0; + cst.trystat = 0; + + if ((fp = fopen(stsname(addr), "r"))) { + fread(&cst, sizeof(callstat), 1, fp); + fclose(fp); + } + + return &cst; +} + + + +void putstatus(faddr *addr, int incr, int sts) +{ + FILE *fp; + callstat *cst; + + cst = getstatus(addr); + if ((fp = fopen(stsname(addr), "w"))) { + if (sts == 0) + cst->tryno = 0; + else + cst->tryno += incr; + cst->trystat = sts; + (void)time(&cst->trytime); + fwrite(cst, sizeof(callstat), 1, fp); + fclose(fp); + if (cst->tryno >= 30) + WriteError("Node %s is marked undialble.", ascfnode(addr, 0x1f)); + } else { + WriteError("$Cannot create status file for node %s", ascfnode(addr,0x1f)); + } +} + + diff --git a/mbcico/callstat.h b/mbcico/callstat.h new file mode 100644 index 00000000..a27eb37e --- /dev/null +++ b/mbcico/callstat.h @@ -0,0 +1,26 @@ +#ifndef CALLSTAT_H +#define CALLSTAT_H + + +#define ST_PORTERR 1 +#define ST_NOCONN 2 +#define ST_MDMERR 3 +#define ST_LOCKED 4 +#define ST_LOOKUP 6 +#define ST_NOCALL7 7 +#define ST_NOCALL8 8 +#define ST_NOPORT 9 +#define ST_NOTZMH 10 +#define ST_SESSION 30 + + +typedef struct _callstat { + time_t trytime; + int tryno; + int trystat; +} callstat; + +callstat *getstatus(faddr*); +void putstatus(faddr*,int,int); + +#endif diff --git a/mbcico/chat.c b/mbcico/chat.c new file mode 100644 index 00000000..fea4f754 --- /dev/null +++ b/mbcico/chat.c @@ -0,0 +1,253 @@ +/***************************************************************************** + * + * File ..................: mbcico/chat.c + * Purpose ...............: Fidonet mailer + * Last modification date : 27-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "config.h" +#include "portsel.h" +#include "chat.h" +#include "ttyio.h" + + +char *tranphone(char *Phone) +{ + static char trp[21]; + char buf[21]; + char *p; + int ln, i, j; + + if (Phone == NULL) + return NULL; + strncpy(trp,Phone,sizeof(trp)-1); + + for (i = 0; i < 40; i++) + if (strlen(CFG.phonetrans[i].match) || strlen(CFG.phonetrans[i].repl)) { + memset(&buf, 0, sizeof(buf)); + strncpy(buf,CFG.phonetrans[i].match,strlen(CFG.phonetrans[i].match)); + ln=strlen(buf); + p = xstrcpy(CFG.phonetrans[i].repl); + + if (strncmp(Phone,buf,ln) == 0) { + strcpy(trp,p); + strncat(trp,Phone+ln,sizeof(trp)-strlen(p)-1); + free(p); + break; + } else { + free(p); + } + } + + if (modem.stripdash) { + j = 0; + for (i = 0; i < strlen(trp); i++) { + if (trp[i] != '-') { + trp[j] = trp[i]; + j++; + } + } + trp[j] = '\0'; + } + return trp; +} + + + +int send_str(char *, char *); +int send_str(char *str, char *Phone) +{ + char *p, *q; + static char logs[81]; + + p = str; + memset(&logs, 0, sizeof(logs)); + q = logs; + + while (*p) { + if (*p == '\\') { + switch (*++p) { + case '\0': p--; break; + case '\\': PUTCHAR('\\'); *q++ = '\\'; break; + case 'r': PUTCHAR('\r'); *q++ = '\\'; *q++ = 'r'; break; + case 'n': PUTCHAR('\n'); *q++ = '\\'; *q++ = 'n'; break; + case 't': PUTCHAR('\t'); *q++ = '\\'; *q++ = 't'; break; + case 'b': PUTCHAR('\b'); *q++ = '\\'; *q++ = 'b'; break; + case 's': PUTCHAR(' '); *q++ = ' '; break; + case ' ': PUTCHAR(' '); *q++ = ' '; break; + case 'd': sleep(1); *q++ = '\\'; *q++ = 'd'; break; + case 'p': usleep(250000L); *q++ = '\\'; *q++ = 'p'; break; + case 'D': if (Phone) { + PUTSTR(Phone); + sprintf(q, "%s", Phone); + } + break; + case 'T': if (Phone) { + PUTSTR(tranphone(Phone)); + sprintf(q, "%s", tranphone(Phone)); + } + break; + default: PUTCHAR(*p); *q++ = *p; break; + } + while (*q) + q++; + } else { + PUTCHAR(*p); + *q++ = *p; + } + p++; + } + Syslog('+', "chat: snd \"%s\"", logs); + + if (STATUS) { + WriteError("$chat: send_str error %d", STATUS); + return 1; + } else + return 0; +} + + + +static int expired = FALSE; + +void almhdl(int); +void almhdl(int sig) +{ + expired = TRUE; + Syslog('c' ,"chat: timeout"); + return; +} + + + +int expect_str(int, char *); +int expect_str(int timeout, char *Phone) +{ + int matched = FALSE; + int smatch = FALSE; + int ematch = FALSE; + int ioerror = FALSE; + int i, rc; + char inbuf[256]; + unsigned char ch = '\0'; + int eol = FALSE; + + expired = FALSE; + signal(SIGALRM, almhdl); + alarm(timeout); + + while (!matched && !expired && !ioerror && !feof(stdin)) { + + eol = FALSE; + i = 0; + memset(&inbuf, 0, sizeof(inbuf)); + + while (!ioerror && !feof(stdin) && !eol && (i < 255)) { + + if ((rc = read(0, &ch, 1)) != 1) { + ioerror = TRUE; + } else { + switch(ch) { + case '\n': break; + case '\r': inbuf[i++] = '\r'; + eol = TRUE; + break; + default: inbuf[i++] = ch; + } + } + if (expired) + Syslog('c', "chat: got TIMEOUT"); + } + + inbuf[i] = '\0'; + Syslog('c', "chat: rcv \"%s\"", printable(inbuf, 0)); + + for (i = 0; (i < 10) && !matched; i++) + if (strlen(modem.error[i])) + if (strncmp(modem.error[i], inbuf, strlen(modem.error[i])) == 0) { + matched = TRUE; + ematch = TRUE; + Syslog('+', "chat: got \"%s\", aborting", printable(inbuf, 0)); + } + + if (Phone != NULL) + for (i = 0; (i < 20) && !matched; i++) + if (strlen(modem.connect[i])) + if (strncmp(modem.connect[i], inbuf, strlen(modem.connect[i])) == 0) { + matched = TRUE; + smatch = TRUE; + Syslog('+', "chat: got \"%s\", continue", printable(inbuf, 0)); + } + + if (!matched) + if (strlen(modem.ok)) + if (strncmp(modem.ok, inbuf, strlen(modem.ok)) == 0) { + matched = TRUE; + smatch = TRUE; + Syslog('+', "chat: got \"%s\", continue", printable(inbuf, 0)); + } + + if (expired) + Syslog('+', "chat: got timeout, aborting"); + else + if (ferror(stdin)) + Syslog('+', "chat: got error, aborting"); + + if (feof(stdin)) + WriteError("$chat: got EOF, aborting"); + } + alarm(0); + signal(SIGALRM, SIG_DFL); + + rc = !(matched && smatch); + return rc; +} + + + +/* + * Chat with modem. If phone is not NULL, then expect also tests the modem + * connect strings, else only the error strings and ok string is tested. + * The phone number must be full international notation unless the \D + * macro is in the dial command. + */ +int chat(char *Send, int timeout, char *Phone) +{ + int rc; + + if ((rc = send_str(Send, Phone)) == 0) + rc = expect_str(timeout, Phone); + + return rc; +} + + diff --git a/mbcico/chat.h b/mbcico/chat.h new file mode 100644 index 00000000..f69bdf33 --- /dev/null +++ b/mbcico/chat.h @@ -0,0 +1,8 @@ +#ifndef _CHAT_H +#define _CHAT_H + +char *tranphone(char *); +int chat(char *, int, char *); + +#endif + diff --git a/mbcico/config.h b/mbcico/config.h new file mode 100644 index 00000000..61daca5c --- /dev/null +++ b/mbcico/config.h @@ -0,0 +1,24 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include "../lib/structs.h" +#include "../lib/common.h" + + +extern long configtime; +extern long maxfsize; +extern long maxmsize; + + +extern char *name; +extern char *phone; +extern char *flags; +extern char *inbound; +extern char *myfqdn; +extern char *debugfile; +extern char *nonpacked; +extern char *magicname; +extern char *dosoutbound; +extern char *uxoutbound; + +#endif diff --git a/mbcico/dial.c b/mbcico/dial.c new file mode 100644 index 00000000..45ca130e --- /dev/null +++ b/mbcico/dial.c @@ -0,0 +1,166 @@ +/***************************************************************************** + * + * File ..................: mbcico/dial.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "portsel.h" +#include "config.h" +#include "chat.h" +#include "ttyio.h" +#include "session.h" +#include "dial.h" + + +extern time_t c_start; +extern time_t c_end; +extern int online; +extern int master; +int carrier; +extern long sentbytes; +extern long rcvdbytes; +extern int Loaded; + + +int initmodem(void) +{ + int i; + + for (i = 0; i < 3; i++) + if (strlen(modem.init[i])) + if (chat(modem.init[i], CFG.timeoutreset, NULL)) { + WriteError("dial: could not reset the modem"); + return 1; + } + return 0; +} + + + +int dialphone(char *Phone) +{ + int rc; + + Syslog('+', "dial: %s (%s)",MBSE_SS(Phone), MBSE_SS(tranphone(Phone))); + carrier = FALSE; + + if (initmodem()) + return 2; + + rc = 0; + if (strlen(nodes.phone[0])) { + if (strlen(nodes.dial)) + rc = chat(nodes.dial, CFG.timeoutconnect, nodes.phone[0]); + else + rc = chat(modem.dial, CFG.timeoutconnect, nodes.phone[0]); + if ((rc == 0) && strlen(nodes.phone[1])) { + if (strlen(nodes.dial)) + rc = chat(nodes.dial, CFG.timeoutconnect, nodes.phone[1]); + else + rc = chat(modem.dial, CFG.timeoutconnect, nodes.phone[1]); + } + } else { + if (strlen(nodes.dial)) + rc = chat(nodes.dial, CFG.timeoutconnect, Phone); + else + rc = chat(modem.dial, CFG.timeoutconnect, Phone); + } + + if (rc) { + Syslog('+', "Could not connect to the remote"); + return 1; + } else { + c_start = time(NULL); + carrier = TRUE; + return 0; + } +} + + + +int hangup() +{ + char *tmp; + FILE *fp; + + FLUSHIN(); + FLUSHOUT(); + if (strlen(modem.hangup)) + chat(modem.hangup, CFG.timeoutreset, NULL); + + if (carrier) { + time(&c_end); + online += (c_end - c_start); + Syslog('+', "Connection time %s", t_elapsed(c_start, c_end)); + carrier = FALSE; + history.offline = c_end; + history.online = c_start; + history.sent_bytes = sentbytes; + history.rcvd_bytes = rcvdbytes; + history.inbound = ~master; + tmp = calloc(128, sizeof(char)); + sprintf(tmp, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fp = fopen(tmp, "a")) == NULL) + WriteError("$Can't open %s", tmp); + else { + fwrite(&history, sizeof(history), 1, fp); + fclose(fp); + } + free(tmp); + memset(&history, 0, sizeof(history)); + if (Loaded) { + Syslog('s', "Updateing noderecord %s", aka2str(nodes.Aka[0])); + nodes.LastDate = time(NULL); + UpdateNode(); + } + } + FLUSHIN(); + FLUSHOUT(); + return 0; +} + + + +int aftercall() +{ + if (strlen(modem.info)) { + Syslog('d', "Reading link stat (aftercall)"); + FLUSHIN(); + FLUSHOUT(); + chat(modem.info, CFG.timeoutreset, NULL); + } + return 0; +} + + diff --git a/mbcico/dial.h b/mbcico/dial.h new file mode 100644 index 00000000..5874fa0b --- /dev/null +++ b/mbcico/dial.h @@ -0,0 +1,11 @@ +#ifndef _DIAL_H +#define _DIAL_H + +int dialphone(char *); +int hangup(void); +int aftercall(void); + + +#endif + + diff --git a/mbcico/dietifna.c b/mbcico/dietifna.c new file mode 100644 index 00000000..db643577 --- /dev/null +++ b/mbcico/dietifna.c @@ -0,0 +1,149 @@ +/***************************************************************************** + * + * File ..................: mbcico/dietifna.c + * Purpose ...............: Fidonet mailer + * Last modification date : 01-Feb-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "emsi.h" +#include "dietifna.h" +#include "respfreq.h" +#include "filelist.h" +#include "xmrecv.h" +#include "xmsend.h" + + +extern int made_request; +static int sendfiles(file_list*); +static int xmrcvfiles(void); + + + +int rxdietifna(void) +{ + int rc; + file_list *tosend = NULL, **tmpfl; + + Syslog('+', "Start DietIFNA session"); + session_flags |= SESSION_IFNA; + session_flags &= ~SESSION_BARK; + tosend = create_filelist(remote, (char *)ALL_MAIL, 0); + + if ((rc = xmrcvfiles()) == 0) { + if ((emsi_local_opts & OPT_NRQ) == 0) { + for (tmpfl = &tosend; *tmpfl; tmpfl = &((*tmpfl)->next)); + *tmpfl = respond_wazoo(); + } + rc = sendfiles(tosend); + /* we are not sending file requests in slave session */ + } + + tidy_filelist(tosend, (rc == 0)); + if (rc) + WriteError("DietIFNA session failed: rc=%d", rc); + else + Syslog('+', "DietIFNA session completed"); + return rc; +} + + + +int txdietifna(void) +{ + int rc; + file_list *tosend = NULL, *respond = NULL; + char *nonhold_mail; + + Syslog('+', "Start DietIFNA session"); + session_flags |= SESSION_IFNA; + session_flags &= ~SESSION_BARK; + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + tosend = create_filelist(remote, nonhold_mail, 2); + + if ((rc = sendfiles(tosend)) == 0) + if ((rc = xmrcvfiles()) == 0) + if ((emsi_local_opts & OPT_NRQ) == 0) + if ((respond = respond_wazoo())) + rc = sendfiles(respond); + /* but we are trying to respond other's file requests in master */ + /* session, though they are not allowed by the DietIFNA protocol */ + + tidy_filelist(tosend, (rc == 0)); + tidy_filelist(respond, 0); + if (rc) + WriteError("DietIFNA session failed: rc=%d", rc); + else + Syslog('+', "DietIFNA session completed"); + return rc; +} + + + +int xmrcvfiles(void) +{ + int rc; + + while ((rc = xmrecv(NULL)) == 0); + if (rc == 1) + return 0; + else + return rc; +} + + + +int sendfiles(file_list *tosend) +{ + int c, count = 0; + + while (((c = GETCHAR(15)) >= 0) && (c != NAK) && (c != 'C') && + (count++ < 9)) + Syslog('s', "got '%s' waiting for C/NAK", + printablec(c)); + + if (c == NAK) + session_flags &= ~FTSC_XMODEM_CRC; + else if (c == 'C') + session_flags |= FTSC_XMODEM_CRC; + else if (c < 0) + return c; + else + return 1; + + return xmsndfiles(tosend); +} + + diff --git a/mbcico/dietifna.h b/mbcico/dietifna.h new file mode 100644 index 00000000..4f5057b3 --- /dev/null +++ b/mbcico/dietifna.h @@ -0,0 +1,9 @@ +#ifndef _DIETIFNA_H +#define _DIETIFNA_H + +int rxdietifna(void); +int txdietifna(void); + + +#endif + diff --git a/mbcico/emsi.c b/mbcico/emsi.c new file mode 100644 index 00000000..9d6e3bf3 --- /dev/null +++ b/mbcico/emsi.c @@ -0,0 +1,612 @@ +/***************************************************************************** + * + * File ..................: mbcico/emsi.c + * Purpose ...............: Fidonet mailer + * Last modification date : 07-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "emsidat.h" +#include "hydra.h" +#include "rdoptions.h" +#include "tcp.h" +#include "wazoo.h" + + +#define LOCAL_PROTOS (PROT_ZMO | PROT_ZAP | PROT_HYD | PROT_TCP) + +static int rxemsi(void); +static int txemsi(void); +static char *intro; +static int caller; + +extern int most_debug; + +int emsi_local_lcodes; +int emsi_remote_lcodes; +int emsi_local_protos; +int emsi_remote_protos; +int emsi_local_opts; +int emsi_remote_opts; +char *emsi_local_password = NULL; +char *emsi_remote_password = NULL; +char emsi_remote_comm[4]="8N1"; + + + +int rx_emsi(char *data) +{ + int rc; + fa_list *tmr; + int denypw=0; + + Syslog('+', "Start inbound EMSI session"); + + emsi_local_lcodes = LCODE_RH1; + if (localoptions & NOPUA) + emsi_local_lcodes |= LCODE_PUP; + emsi_remote_lcodes=0; + + emsi_local_protos=LOCAL_PROTOS; + if (localoptions & NOZMODEM) + emsi_local_protos &= ~(PROT_ZMO | PROT_ZAP | PROT_DZA); + if (localoptions & NOZEDZAP) + emsi_local_protos &= ~PROT_ZAP; + if (localoptions & NOJANUS) + emsi_local_protos &= ~PROT_JAN; + if (localoptions & NOHYDRA) + emsi_local_protos &= ~PROT_HYD; + if ((localoptions & NOTCP) || ((session_flags & SESSION_TCP) == 0)) { + emsi_local_protos &= ~PROT_TCP; + } + + emsi_remote_protos=0; + emsi_local_opts = OPT_XMA; + emsi_remote_opts=0; + emsi_local_password = NULL; + emsi_remote_password = NULL; + intro=data+2; + caller=0; + + if ((rc=rxemsi())) + return rc; + + Syslog('i', "local lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_local_lcodes,emsi_local_protos,emsi_local_opts); + Syslog('i', "remote lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_remote_lcodes,emsi_remote_protos,emsi_remote_opts); + + if (emsi_remote_opts & OPT_EII) { + emsi_local_opts |= OPT_EII; + } + + emsi_local_protos &= emsi_remote_protos; + if (emsi_local_protos & PROT_TCP) + emsi_local_protos &= PROT_TCP; + else if (emsi_local_protos & PROT_HYD) + emsi_local_protos &= PROT_HYD; + else if (emsi_local_protos & PROT_JAN) + emsi_local_protos &= PROT_JAN; + else if (emsi_local_protos & PROT_ZAP) + emsi_local_protos &= PROT_ZAP; + else if (emsi_local_protos & PROT_ZMO) + emsi_local_protos &= PROT_ZMO; + else if (emsi_local_protos & PROT_DZA) + emsi_local_protos &= PROT_DZA; + else if (emsi_local_protos & PROT_KER) + emsi_local_protos &= PROT_KER; + + emsi_local_password = NULL; + + for (tmr = remote; tmr; tmr = tmr->next) + if (((nlent = getnlent(tmr->addr))) && (nlent->pflag != NL_DUMMY)) { + Syslog('+', "Remote is a listed system"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); + break; + } + if (nlent) + rdoptions(TRUE); + + /* + * Added these options, if they are in the setup for this + * calling node, then disable these options. + */ + if (localoptions & NOHYDRA) + emsi_local_opts &= ~PROT_HYD; + if (localoptions & NOZEDZAP) + emsi_local_opts &= ~PROT_ZAP; + if (localoptions & NOZMODEM) + emsi_local_opts &= ~(PROT_ZMO | PROT_ZAP | PROT_DZA); + + if (localoptions & NOFREQS) + emsi_local_opts |= OPT_NRQ; + + if (strlen(nodes.Epasswd)) { + if ((strncasecmp(emsi_remote_password, nodes.Epasswd, strlen(nodes.Epasswd)) == 0) && + (strlen(emsi_remote_password) == strlen(nodes.Epasswd))) { + emsi_local_password = xstrcpy(nodes.Epasswd); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); + Syslog('+', "Password correct, protected EMSI session"); + } else { + denypw = 1; + Syslog('?', "Remote password \"%s\", expected \"%s\"", MBSE_SS(emsi_remote_password), nodes.Epasswd); + emsi_local_password = xstrcpy((char *)"BAD_PASS"); + emsi_local_lcodes = LCODE_HAT; + } + } else { + Syslog('i', "No EMSI password check"); + Syslog('?', "Unexpected remote password \"%s\"", MBSE_SS(emsi_local_password)); + } + + Syslog('i', "local lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_local_lcodes,emsi_local_protos,emsi_local_opts); + + if ((rc=txemsi())) + return rc; + + if (denypw || (emsi_local_protos == 0)) { + Syslog('+', "Refusing remote: %s", emsi_local_protos?"bad password presented": "no common protocols"); + return 0; + } + + IsDoing("EMSI %s inb", ascfnode(remote->addr, 0x0f)); + + if ((emsi_remote_opts & OPT_NRQ) == 0) + session_flags |= SESSION_WAZOO; + else + session_flags &= ~SESSION_WAZOO; + + if (emsi_local_protos & PROT_TCP) + return rxtcp(); + else if (emsi_local_protos & PROT_HYD) + return hydra(0); +// else if (emsi_local_protos & PROT_JAN) +// return janus(); + else + return rxwazoo(); +} + + + +int tx_emsi(char *data) +{ + int rc; + + Syslog('+', "Start outbound EMSI session"); + emsi_local_lcodes = LCODE_PUA | LCODE_RH1; + if (localoptions & NOPUA) { + emsi_local_lcodes |= LCODE_PUP; + emsi_local_lcodes &= ~LCODE_PUA; + } + emsi_remote_lcodes = 0; + + emsi_local_protos=LOCAL_PROTOS; + if (localoptions & NOZMODEM) + emsi_local_protos &= ~(PROT_ZMO | PROT_ZAP | PROT_DZA); + if (localoptions & NOZEDZAP) + emsi_local_protos &= ~PROT_ZAP; + if (localoptions & NOJANUS) + emsi_local_protos &= ~PROT_JAN; + if (localoptions & NOHYDRA) + emsi_local_protos &= ~PROT_HYD; + if ((localoptions & NOTCP) || ((session_flags & SESSION_TCP) == 0)) { + emsi_local_protos &= ~PROT_TCP; + } + emsi_remote_protos=0; + emsi_local_opts=OPT_XMA | OPT_EII | OPT_NRQ; +// if (localoptions & NOFREQS) /* 17-Dec-1998, refuse requests when we pay the bill. */ +// emsi_local_opts |= OPT_NRQ; + emsi_remote_opts=0; + emsi_local_password=NULL; + emsi_remote_password=NULL; + intro=data+2; + caller=1; + emsi_local_password=NULL; + + Syslog('i', "local lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_local_lcodes,emsi_local_protos,emsi_local_opts); + + if ((rc=txemsi())) + return rc; + else { + if ((rc=rxemsi())) + return rc; + } + + if ((emsi_remote_opts & OPT_EII) == 0) { + emsi_local_opts &= ~OPT_EII; + } + + Syslog('i', "remote lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_remote_lcodes,emsi_remote_protos,emsi_remote_opts); + + if ((emsi_remote_protos == 0) || (emsi_remote_lcodes & LCODE_HAT)) { + Syslog('+', "Remote refused us: %s", emsi_remote_protos?"traffic held":"no common protos"); + return 0; + } + + IsDoing("EMSI %s out", ascfnode(remote->addr, 0x0f)); + + emsi_local_protos &= emsi_remote_protos; + if ((emsi_remote_opts & OPT_NRQ) == 0) + session_flags |= SESSION_WAZOO; + else + session_flags &= ~SESSION_WAZOO; + + if (emsi_local_protos & PROT_TCP) + return txtcp(); + else if (emsi_local_protos & PROT_HYD) + return hydra(1); +// else if (emsi_local_protos & PROT_JAN) +// return janus(); + else + return txwazoo(); +} + + + +SM_DECL(rxemsi,(char *)"rxemsi") +SM_STATES + waitpkt, + waitchar, + checkemsi, + getdat, + checkpkt, + checkdat, + sendnak, + sendack +SM_NAMES + (char *)"waitpkt", + (char *)"waitchar", + (char *)"checkemsi", + (char *)"getdat", + (char *)"checkpkt", + (char *)"checkdat", + (char *)"sendnak", + (char *)"sendack" +SM_EDECL + + int c = 0; + unsigned short lcrc, rcrc; + int len; + int standby = 0, tries = 0; + char buf[13], *p; + char *databuf = NULL; + + p = buf; + databuf = xstrcpy(intro); + +SM_START(checkpkt) + Syslog('I', "rxemsi START"); + Syslog('i', "RXEMSI: start"); + +SM_STATE(waitpkt) + + Syslog('I', "rxemsi WAITPKT"); + standby = 0; + SM_PROCEED(waitchar); + +SM_STATE(waitchar) + + Syslog('I', "rxemsi WAITCHAR"); + c = GETCHAR(5); + if (c == TIMEOUT) { + if (++tries > 9) { + Syslog('+', "Too many tries waiting EMSI handshake"); + SM_ERROR; + } else { + SM_PROCEED(sendnak); + } + } else if (c < 0) { + SM_ERROR; + } else if ((c >= ' ') && (c <= '~')) { + if (c == '*') { + standby = 1; + p = buf; + *p = '\0'; + } else if (standby) { + if ((p - buf) < (sizeof(buf) - 1)) { + *p++ = c; + *p = '\0'; + } if ((p - buf) >= (sizeof(buf) - 1)) { + standby = 0; + SM_PROCEED(checkemsi); + } + } + } else switch(c) { + case DC1: break; + case '\n': + case '\r': standby = 0; + break; + default: standby = 0; + break; + } + + SM_PROCEED(waitchar); + +SM_STATE(checkemsi) + + Syslog('I', "rxemsi CHECKEMSI"); + Syslog('i', "RXEMSI: rcvd %s", printable(buf, 0)); + + if (strncasecmp(buf, "EMSI_DAT",8) == 0) { + SM_PROCEED(getdat); + } else if (strncasecmp(buf, "EMSI_",5) == 0) { + if (databuf) + free(databuf); + databuf = xstrcpy(buf); + SM_PROCEED(checkpkt); + } else { + SM_PROCEED(waitpkt); + } + +SM_STATE(getdat) + + Syslog('I', "rxemsi GETDAT"); + + if (sscanf(buf+8,"%04x",&len) != 1) { + SM_PROCEED(sendnak); + } + + len += 16; /* strlen("EMSI_DATxxxxyyyy"), include CRC */ + if (databuf) + free(databuf); + databuf = malloc(len + 1); + strcpy(databuf, buf); + p = databuf + strlen(databuf); + + while (((p-databuf) < len) && ((c=GETCHAR(8)) >= 0)) { + *p++ = c; + *p = '\0'; + } + + Syslog('i', "RXEMSI: rcvd %s (%d bytes)", databuf, len); + + if (c == TIMEOUT) { + SM_PROCEED(sendnak); + } else if (c < 0) { + Syslog('+', "Error while reading EMSI_DAT packet"); + SM_ERROR; + } + + SM_PROCEED(checkdat); + +SM_STATE(checkpkt) + + Syslog('I', "rxemsi CHECKPKT"); + if (strncasecmp(databuf,"EMSI_DAT",8) == 0) { + SM_PROCEED(checkdat); + } + + lcrc = crc16xmodem(databuf, 8); + sscanf(databuf + 8, "%04hx", &rcrc); + if (lcrc != rcrc) { + Syslog('+', "Got EMSI packet \"%s\" with bad crc: %04x/%04x", printable(databuf, 0), lcrc, rcrc); + SM_PROCEED(sendnak); + } if (strncasecmp(databuf, "EMSI_HBT", 8) == 0) { + tries = 0; + SM_PROCEED(waitpkt); + } else if (strncasecmp(databuf, "EMSI_INQ", 8) == 0) { + SM_PROCEED(sendnak); + } else { + Syslog('I', "RXEMSI: ignore packet \"%s\"",databuf); + SM_PROCEED(waitpkt); + } + +SM_STATE(checkdat) + + Syslog('I', "rxemsi CHECKDAT"); + sscanf(databuf + 8, "%04x", &len); + if (len != (strlen(databuf) - 16)) { + Syslog('+', "Bad EMSI_DAT length: %d/%d", len, strlen(databuf)); + SM_PROCEED(sendnak); + } + /* Some FD versions send length of the packet including the + trailing CR. Arrrgh! Dirty overwork follows: */ + if (*(p = databuf + strlen(databuf) - 1) == '\r') + *p='\0'; + sscanf(databuf + strlen(databuf) - 4, "%04hx", &rcrc); + *(databuf + strlen(databuf) - 4) = '\0'; + lcrc = crc16xmodem(databuf, strlen(databuf)); + if (lcrc != rcrc) { + Syslog('+', "Got EMSI_DAT packet \"%s\" with bad crc: %04x/%04x", printable(databuf, 0), lcrc, rcrc); + SM_PROCEED(sendnak); + } if (scanemsidat(databuf + 12) == 0) { + SM_PROCEED(sendack); + } else { + Syslog('+', "Could not parse EMSI_DAT packet \"%s\"",databuf); + SM_ERROR; + } + +SM_STATE(sendnak) + + Syslog('I', "rxemsi SENDNAK"); + if (++tries > 9) { + Syslog('+', "Too many tries getting EMSI_DAT"); + SM_ERROR; + } if (caller) { + PUTSTR((char *)"**EMSI_NAKEEC3\r\021"); + Syslog('i', "RXEMSI: send **EMSI_NAKEEC3"); + } else { + PUTSTR((char *)"**EMSI_REQA77E\r\021"); + Syslog('i', "RXEMSI: send **EMSI_REQA77E"); + if (tries > 1) { + PUTSTR((char *)"**EMSI_NAKEEC3\r\021"); + Syslog('i', "RXEMSI: send **EMSI_NAKEEC3"); + } + } + SM_PROCEED(waitpkt); + +SM_STATE(sendack) + + Syslog('I', "rxemsi SENDACK"); + Syslog('i', "RXEMSI: send **EMSI_ACKA490 (2 times)"); + PUTSTR((char *)"**EMSI_ACKA490\r\021"); + PUTSTR((char *)"**EMSI_ACKA490\r\021"); + SM_SUCCESS; + +SM_END + Syslog('I', "rxemsi END"); + Syslog('i', "RXEMSI: end"); + free(databuf); + +SM_RETURN + + + + +SM_DECL(txemsi,(char *)"txemsi") +SM_STATES + senddata, + waitpkt, + waitchar, + checkpkt, + sendack +SM_NAMES + (char *)"senddata", + (char *)"waitpkt", + (char *)"waitchar", + (char *)"checkpkt", + (char *)"sendack" +SM_EDECL + + int c; + unsigned short lcrc, rcrc; + int standby = 0, tries = 0; + char buf[13], *p; + char trailer[8]; + + p = buf; + memset(&buf, 0, sizeof(buf)); + strncpy(buf, intro, sizeof(buf) - 1); + +SM_START(senddata) + Syslog('i', "TXEMSI: start"); + +SM_STATE(senddata) + + Syslog('I', "txemsi SENDDATA"); + p = mkemsidat(caller); + PUTCHAR('*'); + PUTCHAR('*'); + PUTSTR(p); + sprintf(trailer, "%04X\r\021", crc16xmodem(p, strlen(p))); + PUTSTR(trailer); + Syslog('i', "TXEMSI: send **%s%04X", p, crc16xmodem(p, strlen(p))); + free(p); + SM_PROCEED(waitpkt); + +SM_STATE(waitpkt) + + Syslog('I', "txemsi WAITPKT"); + standby = 0; + SM_PROCEED(waitchar); + +SM_STATE(waitchar) + + Syslog('I', "txemsi WAITCHAR"); + c = GETCHAR(8); + if (c == TIMEOUT) { + if (++tries > 9) { + Syslog('+', "too many tries sending EMSI"); + SM_ERROR; + } else { + SM_PROCEED(senddata); + } + } else if (c < 0) { + SM_ERROR; + } else if ((c >= ' ') && (c <= '~')) { + if (c == '*') { + standby = 1; + p = buf; + *p = '\0'; + } else if (standby) { + if ((p - buf) < (sizeof(buf) - 1)) { + *p++ = c; + *p = '\0'; + } if ((p - buf) >= (sizeof(buf) - 1)) { + standby = 0; + SM_PROCEED(checkpkt); + } + } + } else switch(c) { + case DC1: SM_PROCEED(waitchar); + break; + case '\n': + case '\r': standby = 0; + break; + default: standby = 0; + break; + } + SM_PROCEED(waitchar); + +SM_STATE(checkpkt) + + Syslog('I', "txemsi CHECKPKT"); + Syslog('i', "TXEMSI: rcvd %s", buf); + if (strncasecmp(buf, "EMSI_DAT", 8) == 0) { + SM_PROCEED(sendack); + } else if (strncasecmp(buf, "EMSI_", 5) == 0) { + lcrc = crc16xmodem(buf, 8); + sscanf(buf + 8, "%04hx", &rcrc); + if (lcrc != rcrc) { + Syslog('+', "Got EMSI packet \"%s\" with bad crc: %04x/%04x", printable(buf, 0), lcrc, rcrc); + SM_PROCEED(senddata); + } if (strncasecmp(buf, "EMSI_REQ", 8) == 0) { + SM_PROCEED(waitpkt); + } if (strncasecmp(buf, "EMSI_ACK", 8) == 0) { + SM_SUCCESS; + } else { + SM_PROCEED(senddata); + } + } else { + SM_PROCEED(waitpkt); + } + +SM_STATE(sendack) + + Syslog('I', "txemsi SENDACK"); + Syslog('i', "TXEMSI: send **EMSI_ACKA490 (2 times)"); + PUTSTR((char *)"**EMSI_ACKA490\r\021"); + PUTSTR((char *)"**EMSI_ACKA490\r\021"); + SM_PROCEED(waitpkt); + +SM_END + Syslog('i', "TXEMSI: end"); + +SM_RETURN + + diff --git a/mbcico/emsi.h b/mbcico/emsi.h new file mode 100644 index 00000000..bdade0f1 --- /dev/null +++ b/mbcico/emsi.h @@ -0,0 +1,52 @@ +#define PRODCODE 0xfe /* product code for ifcico */ + +#ifndef EMSI_H +#define EMSI_H + +#define LCODE_PUA 0x0001 +#define LCODE_PUP 0x0002 +#define LCODE_NPU 0x0004 +#define LCODE_HAT 0x0008 +#define LCODE_HXT 0x0010 +#define LCODE_HRQ 0x0020 +#define LCODE_FNC 0x0040 +#define LCODE_RMA 0x0080 +#define LCODE_RH1 0x0100 + +extern int emsi_local_lcodes; +extern int emsi_remote_lcodes; + +#define PROT_DZA 0x0001 +#define PROT_ZAP 0x0002 +#define PROT_ZMO 0x0004 +#define PROT_JAN 0x0008 +#define PROT_KER 0x0010 +#define PROT_HYD 0x0020 +#define PROT_TCP 0x0040 + +extern int emsi_local_protos; +extern int emsi_remote_protos; + +#define OPT_NRQ 0x0002 +#define OPT_ARC 0x0004 +#define OPT_XMA 0x0008 +#define OPT_FNC 0x0010 +#define OPT_CHT 0x0020 +#define OPT_SLK 0x0040 +#define OPT_EII 0x0080 +#define OPT_DFB 0x0100 +#define OPT_FRQ 0x0200 + +extern int emsi_local_opts; +extern int emsi_remote_opts; + +extern char *emsi_local_password; +extern char *emsi_remote_password; +extern char emsi_remote_comm[]; + + +int rx_emsi(char *); +int tx_emsi(char *); + + +#endif diff --git a/mbcico/emsidat.c b/mbcico/emsidat.c new file mode 100644 index 00000000..e50a7cb5 --- /dev/null +++ b/mbcico/emsidat.c @@ -0,0 +1,502 @@ +/***************************************************************************** + * + * File ..................: mbcico/emsidat.c + * Purpose ...............: Fidonet mailer + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "emsi.h" +#include "session.h" +#include "lutil.h" +#include "config.h" +#include "emsidat.h" +#include "filetime.h" + + +extern int Loaded; + + +char *emsiencode(char *s) +{ + char Base16Code[]="0123456789ABCDEF"; + static char *buf; + char *p, *q; + + if (buf) + free(buf); + if ((buf = malloc(2 * strlen(s) + 1 * sizeof(char))) == NULL) { + Syslog('+', "emsiencode:out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + switch (*p) { + case '\\': *q++ = '\\'; *q++ = *p++; break; + case '[': + case ']': + case '{': + case '}': *q++ = '\\'; + *q++ = Base16Code[(*p >> 4) & 0x0f]; + *q++ = Base16Code[*p & 0x0f]; + p++; break; + default: *q++ = *p++; break; + } + } + *q = '\0'; + + return buf; +} + + + +char *mkemsidat(int caller) +{ + time_t tt; + char cbuf[16]; + char *p; + faddr *primary; + int i; + + p = xstrcpy((char *)"EMSI_DAT0000{EMSI}{"); + + primary = bestaka_s(remote->addr); + p = xstrcat(p, ascfnode(primary, 0x1f)); + + for (i = 0; i < 40; i++) + if ((CFG.aka[i].node) && (CFG.akavalid[i]) && + ((CFG.aka[i].zone != primary->zone) || + (CFG.aka[i].net != primary->net) || + (CFG.aka[i].node != primary->node) || + (CFG.aka[i].point!= primary->point))) { + p = xstrcat(p, (char *)" "); + p = xstrcat(p, aka2str(CFG.aka[i])); + } + + p=xstrcat(p,(char *)"}{"); + tidy_faddr(primary); + + if (emsi_local_password) + p=xstrcat(p,emsi_local_password); + else + if (strlen(nodes.Epasswd)) { + p = xstrcat(p, nodes.Epasswd); + } + + if (emsi_local_opts & OPT_EII) { + p = xstrcat(p, (char *)"}{"); + + if (emsi_local_lcodes & LCODE_FNC) + p = xstrcat(p, (char *)"FNC,"); + if (emsi_local_lcodes & LCODE_RMA) + p = xstrcat(p, (char *)"RMA,"); + if (emsi_local_lcodes & LCODE_RH1) + p = xstrcat(p, (char *)"RH1,"); + + if (emsi_local_lcodes & LCODE_PUA) + p=xstrcat(p,(char *)"PUA,"); + else if (emsi_local_lcodes & LCODE_PUP) + p=xstrcat(p,(char *)"PUP,"); + else if (emsi_local_lcodes & LCODE_NPU) + p=xstrcat(p,(char *)"NPU,"); + if (emsi_local_lcodes & LCODE_HAT) + p=xstrcat(p,(char *)"HAT,"); + if (emsi_local_lcodes & LCODE_HXT) + p=xstrcat(p,(char *)"HXT,"); + if (emsi_local_lcodes & LCODE_HRQ) + p=xstrcat(p,(char *)"HRQ,"); + if (*(p+strlen(p)-1) == ',') + *(p+strlen(p)-1) = '}'; + else + p=xstrcat(p,(char *)"}"); + } else { + p=xstrcat(p,(char *)"}{8N1"); + if (emsi_local_lcodes & LCODE_RH1) + p = xstrcat(p, (char *)",RH1"); + if (caller) { + if (emsi_local_lcodes & LCODE_PUA) + p=xstrcat(p,(char *)",PUA"); + else if (emsi_local_lcodes & LCODE_PUP) + p=xstrcat(p,(char *)",PUP"); + else if (emsi_local_lcodes & LCODE_NPU) + p=xstrcat(p,(char *)",NPU"); + } else { + if (emsi_local_lcodes & LCODE_HAT) + p=xstrcat(p,(char *)",HAT"); + if (emsi_local_lcodes & LCODE_HXT) + p=xstrcat(p,(char *)",HXT"); + if (emsi_local_lcodes & LCODE_HRQ) + p=xstrcat(p,(char *)",HRQ"); + } + + p = xstrcat(p, (char *)"}"); + } + + p=xstrcat(p,(char *)"{"); + if (emsi_local_protos & PROT_TCP) + p=xstrcat(p,(char *)"TCP,"); + if (emsi_local_protos & PROT_HYD) + p=xstrcat(p,(char *)"HYD,"); + if (emsi_local_protos & PROT_JAN) + p=xstrcat(p,(char *)"JAN,"); + if (emsi_local_protos & PROT_ZAP) + p=xstrcat(p,(char *)"ZAP,"); + if (emsi_local_protos & PROT_ZMO) + p=xstrcat(p,(char *)"ZMO,"); + if (emsi_local_protos & PROT_DZA); + p=xstrcat(p,(char *)"DZA,"); + if (emsi_local_protos & PROT_KER) + p=xstrcat(p,(char *)"KER,"); + if (emsi_local_protos == 0) + p=xstrcat(p,(char *)"NCP,"); + if (emsi_local_opts & OPT_NRQ) + p=xstrcat(p,(char *)"NRQ,"); + if (emsi_local_opts & OPT_ARC) + p=xstrcat(p,(char *)"ARC,"); + if (emsi_local_opts & OPT_XMA) + p=xstrcat(p,(char *)"XMA,"); + if (emsi_local_opts & OPT_FNC) + p=xstrcat(p,(char *)"FNC,"); + if (emsi_local_opts & OPT_CHT) + p=xstrcat(p,(char *)"CHT,"); + if (emsi_local_opts & OPT_SLK) + p=xstrcat(p,(char *)"SLK,"); + if (emsi_local_opts & OPT_EII) + p=xstrcat(p,(char *)"EII,"); + if (emsi_local_opts & OPT_DFB) + p=xstrcat(p,(char *)"DFB,"); + if (emsi_local_opts & OPT_FRQ) + p=xstrcat(p,(char *)"FRQ,"); + if (*(p+strlen(p)-1) == ',') + *(p+strlen(p)-1) = '}'; + else + p=xstrcat(p,(char *)"}"); + + sprintf(cbuf,"{%X}",PRODCODE); + p=xstrcat(p,cbuf); + p=xstrcat(p,(char *)"{mbcico}{"); + p=xstrcat(p,(char *)VERSION); + p=xstrcat(p,(char *)"}{"); + p=xstrcat(p,(char *)__DATE__); + p=xstrcat(p,(char *)"}{IDENT}{["); + p=xstrcat(p,name?emsiencode(name):(char *)"Unknown"); + p=xstrcat(p,(char *)"]["); + p=xstrcat(p,emsiencode(CFG.location)); + p=xstrcat(p,(char *)"]["); + p=xstrcat(p,emsiencode(CFG.sysop_name)); + p=xstrcat(p,(char *)"]["); + p=xstrcat(p,phone?emsiencode(phone):(char *)"-Unpublished-"); + p=xstrcat(p,(char *)"]["); + if (CFG.Speed) + sprintf(cbuf,"%ld",CFG.Speed); + else + strcpy(cbuf,"9600"); + p=xstrcat(p,cbuf); + p=xstrcat(p,(char *)"]["); + p=xstrcat(p,flags?emsiencode(flags):(char *)""); + p=xstrcat(p,(char *)"]}{TRX#}{["); + (void)time(&tt); + sprintf(cbuf,"%08lX",mtime2sl(tt)); + p=xstrcat(p,cbuf); + p=xstrcat(p,(char *)"]}{TZUTC}{["); + p=xstrcat(p,gmtoffset(tt)); + p=xstrcat(p,(char *)"]}"); + + sprintf(cbuf,"%04X",(unsigned int)strlen(p+12)); + memcpy(p+8,cbuf,4); + Syslog('I',"Prepared: \"%s\"",p); + return p; +} + + + +char *sel_brace(char*); +char *sel_brace(char *s) +{ + static char *save; + char *p,*q; + int i; + + if (s == NULL) + s=save; + for (;*s && (*s != '{');s++); + if (*s == '\0') { + save=s; + return NULL; + } else + s++; + + for (p=s,q=s;*p;p++) + switch (*p) { + case '}': if (*(p+1) == '}') + *q++=*p++; + else { + *q='\0'; + save=p+1; + goto exit; + } + break; + case '\\': if (*(p+1) == '\\') + *q++=*p++; + else { + sscanf(p+1,"%02x",&i); + *q++=i; + p+=2; + } + break; + default: *q++=*p; + break; + } +exit: + return s; +} + + + +char *sel_bracket(char*); +char *sel_bracket(char *s) +{ + static char *save; + char *p,*q; + int i; + + if (s == NULL) + s=save; + for (;*s && (*s != '[');s++); + if (*s == '\0') { + save=s; + return NULL; + } else + s++; + + for (p=s,q=s;*p;p++) + switch (*p) { + case ']': if (*(p+1) == ']') + *q++=*p++; + else { + *q='\0'; + save=p+1; + goto exit; + } + break; + case '\\': if (*(p+1) == '\\') + *q++=*p++; + else { + sscanf(p+1,"%02x",&i); + *q++=i; + p+=2; + } + break; + default: *q++=*p; + break; + } +exit: + return s; +} + + + +int scanemsidat(char *buf) +{ + char *p,*q; + fa_list **tmp,*tmpa; + faddr *fa; + char *mailer_prod,*mailer_name,*mailer_version,*mailer_serial; + + Syslog('I',"got data packet: \"%s\"",buf); + + p=sel_brace(buf); + if (strcasecmp(p,"EMSI") != 0) { + Syslog('?', "This can never occur. Got \"%s\" instead of \"EMSI\"",p); + return 1; + } + p=sel_brace(NULL); + + /* + * Clear remote address list, and build a new one from EMSI data + */ + tidy_falist(&remote); + remote = NULL; + tmp = &remote; + for (q = strtok(p," "); q; q = strtok(NULL," ")) + if ((fa = parsefnode(q))) { + *tmp = (fa_list*)malloc(sizeof(fa_list)); + (*tmp)->next = NULL; + (*tmp)->addr = fa; + tmp = &((*tmp)->next); + } + + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + Syslog('+', "address : %s",ascfnode(tmpa->addr,0x1f)); + (void)nodelock(tmpa->addr); + /* + * With the loaded flag we prevent removing the noderecord + * when the remote presents us an address we don't know about. + */ + if (!Loaded) { + if (noderecord(tmpa->addr)) + Loaded = TRUE; + } + } + + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + sprintf(history.aka.domain, "%s", remote->addr->domain); + + if (emsi_remote_password) + free(emsi_remote_password); + emsi_remote_password=xstrcpy(sel_brace(NULL)); +// Syslog('+', "password: %s", MBSE_SS(emsi_remote_password)); + + p=sel_brace(NULL); + Syslog('+', "link : %s", MBSE_SS(p)); + for (q=strtok(p,",");q;q=strtok(NULL,",")) { + if (((q[0] >= '5') && (q[0] <= '8')) && + ((toupper(q[1]) == 'N') || + (toupper(q[1]) == 'O') || + (toupper(q[1]) == 'E') || + (toupper(q[1]) == 'S') || + (toupper(q[1]) == 'M')) && + ((q[2] == '1') || (q[2] == '2'))) + { + strncpy(emsi_remote_comm,q,3); + } + else if (strcasecmp(q,"PUA") == 0) emsi_remote_lcodes |= LCODE_PUA; + else if (strcasecmp(q,"PUP") == 0) emsi_remote_lcodes |= LCODE_PUP; + else if (strcasecmp(q,"NPU") == 0) emsi_remote_lcodes |= LCODE_NPU; + else if (strcasecmp(q,"HAT") == 0) emsi_remote_lcodes |= LCODE_HAT; + else if (strcasecmp(q,"HXT") == 0) emsi_remote_lcodes |= LCODE_HXT; + else if (strcasecmp(q,"HRQ") == 0) emsi_remote_lcodes |= LCODE_HRQ; + else if (strcasecmp(q,"FNC") == 0) emsi_remote_lcodes |= LCODE_FNC; + else if (strcasecmp(q,"RMA") == 0) emsi_remote_lcodes |= LCODE_RMA; + else if (strcasecmp(q,"RH1") == 0) emsi_remote_lcodes |= LCODE_RH1; + else Syslog('+', "unrecognized EMSI link code: \"%s\"",q); + } + + p=sel_brace(NULL); + Syslog('+', "comp : %s", p); + for (q=strtok(p,",");q;q=strtok(NULL,",")) + { + if (strcasecmp(q,"DZA") == 0) emsi_remote_protos |= PROT_DZA; + else if (strcasecmp(q,"ZAP") == 0) emsi_remote_protos |= PROT_ZAP; + else if (strcasecmp(q,"ZMO") == 0) emsi_remote_protos |= PROT_ZMO; + else if (strcasecmp(q,"JAN") == 0) emsi_remote_protos |= PROT_JAN; + else if (strcasecmp(q,"HYD") == 0) emsi_remote_protos |= PROT_HYD; + else if (strcasecmp(q,"KER") == 0) emsi_remote_protos |= PROT_KER; + else if (strcasecmp(q,"TCP") == 0) emsi_remote_protos |= PROT_TCP; + else if (strcasecmp(q,"NCP") == 0) emsi_remote_protos = 0; + else if (strcasecmp(q,"NRQ") == 0) emsi_remote_opts |= OPT_NRQ; + else if (strcasecmp(q,"ARC") == 0) emsi_remote_opts |= OPT_ARC; + else if (strcasecmp(q,"XMA") == 0) emsi_remote_opts |= OPT_XMA; + else if (strcasecmp(q,"FNC") == 0) emsi_remote_opts |= OPT_FNC; + else if (strcasecmp(q,"CHT") == 0) emsi_remote_opts |= OPT_CHT; + else if (strcasecmp(q,"SLK") == 0) emsi_remote_opts |= OPT_SLK; + else if (strcasecmp(q,"EII") == 0) emsi_remote_opts |= OPT_EII; + else if (strcasecmp(q,"DFB") == 0) emsi_remote_opts |= OPT_DFB; + else if (strcasecmp(q,"FRQ") == 0) emsi_remote_opts |= OPT_FRQ; + else if (strcasecmp(q,"BBS") == 0) Syslog('+', "remote has BBS activity now"); + else Syslog('+', "unrecognized EMSI proto/option code: \"%s\"",q); + } + if ((emsi_remote_opts & OPT_FNC) == 0) + remote_flags &= ~SESSION_FNC; + + mailer_prod=sel_brace(NULL); + mailer_name=sel_brace(NULL); + mailer_version=sel_brace(NULL); + mailer_serial=sel_brace(NULL); + Syslog('+', "uses : %s [%s] version %s/%s", + mailer_name,mailer_prod,mailer_version,mailer_serial); + + while ((p=sel_brace(NULL))) + if (strcasecmp(p,"IDENT") == 0) { + p=sel_brace(NULL); + Syslog('+', "system : %s",(p=sel_bracket(p))); + sprintf(history.system_name, "%s", p); + history.system_name[36] = '\0'; + Syslog('+', "location: %s",(p=sel_bracket(NULL))); + sprintf(history.location, "%s", p); + Syslog('+', "operator: %s",(p=sel_bracket(NULL))); + sprintf(history.sysop, "%s", p); + if (remote && remote->addr) + remote->addr->name=xstrcpy(p); + Syslog('+', "phone : %s",sel_bracket(NULL)); + Syslog('+', "baud : %s",sel_bracket(NULL)); + Syslog('+', "flags : %s",sel_bracket(NULL)); + } else if (strcasecmp(p, "TZUTC") == 0) { + p = sel_brace(NULL); + p = sel_bracket(p); + if ((strlen(p) == 4) || (strlen(p) == 5)) + Syslog('+', "timezone: %s", p); + else + Syslog('+', "TZUTC : %s", p); + } else if (strcasecmp(p,"TRX#") == 0) { + time_t tt, now; + char ctt[32]; + + now = time(NULL); + p=sel_brace(NULL); + p=sel_bracket(p); + if (sscanf(p,"%08lx",&tt) == 1) { + strcpy(ctt,date(sl2mtime(tt))); + Syslog('+', "time : %s",ctt); + Syslog('+', "tranx : %08lX/%08lX [%ld]", now, sl2mtime(tt), now - sl2mtime(tt)); + } else + Syslog('+', "remote TRX#: %s",p); + } else if (strcasecmp(p, "TRAF") == 0) { + unsigned long tt, tt1; + + p = sel_brace(NULL); + if (sscanf(p, "%08lx %08lx", &tt, &tt1) == 2) { + Syslog('+', "netmail : %u byte(s)", tt); + Syslog('+', "echomail: %u byte(s)", tt1); + } else { + Syslog('+', "TRAF : %s", p); + } + } else if (strcasecmp(p, "MOH#") == 0) { + unsigned long tt; + + p = sel_brace(NULL); + p = sel_bracket(p); + if (sscanf(p, "%08lx", &tt) == 1) + Syslog('+', "on hold : %u byte(s)", tt); + else + Syslog('+', "MOH# : %s", p); + } else { + q=sel_brace(NULL); + Syslog('+', "extra : \"%s\" value: \"%s\"",p,q); + } + + return 0; +} + + diff --git a/mbcico/emsidat.h b/mbcico/emsidat.h new file mode 100644 index 00000000..9fa51132 --- /dev/null +++ b/mbcico/emsidat.h @@ -0,0 +1,10 @@ +#ifndef _EMSIDAT_H +#define _EMSIDAT_H + + +char *mkemsidat(int); +int scanemsidat(char *); + + +#endif + diff --git a/mbcico/filelist.c b/mbcico/filelist.c new file mode 100644 index 00000000..5ea40f7a --- /dev/null +++ b/mbcico/filelist.c @@ -0,0 +1,500 @@ +/***************************************************************************** + * + * File ..................: mbcico/filelist.c + * Purpose ...............: fidonet mailer + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "config.h" +#include "session.h" +#include "filelist.h" + + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + +extern int master; +int made_request; + + + +static char *tmpkname(void); +static char *tmpkname(void) +{ + static char buf[16]; + + sprintf(buf,"%08lx.pkt", sequencer()); + return buf; +} + + + +char *xtodos(char *orig) +{ + int i; + char buf[8+1+3+1],*copy,*p,*q,*r; + + if (orig == NULL) + return NULL; + + if ((remote_flags & SESSION_FNC) == 0) { + Syslog('o', "No filename conversion for \"%s\"",MBSE_SS(orig)); + return xstrcpy(orig); + } + + copy=xstrcpy(orig); + if ((p=strrchr(copy,'/'))) + p++; + else + p=copy; + + if (strcmp(q=copy+strlen(copy)-strlen(".tar.gz"),".tar.gz") == 0) { + *q='\0'; + q=(char *)"tgz"; + } else if (strcmp(q=copy+strlen(copy)-strlen(".tar.z"),".tar.z") == 0) { + *q='\0'; + q=(char *)"tgz"; + } else if (strcmp(q=copy+strlen(copy)-strlen(".tar.Z"),".tar.Z") == 0) { + *q='\0'; + q=(char *)"taz"; + } else if ((q=strrchr(p,'.'))) + *q++='\0'; + else + q=NULL; + + r=buf; + for (i=0;(i<8) && (*p);i++,p++,r++) + switch (*p) { + case '.': + case '\\': *r='_'; break; + default: *r=toupper(*p); + } + + if (q) { + *r++='.'; + for (i=0;(i<3) && (*q);i++,q++,r++) + switch (*q) { + case '.': + case '\\': *r='_'; break; + default: *r=toupper(*q); + } + } + *r++='\0'; + + Syslog('o', "name \"%s\" converted to \"%s\"",MBSE_SS(orig),MBSE_SS(buf)); + + free(copy); + return xstrcpy(buf); +} + + + +/* + * Add the specified entry to the list of files which should be sent + * to the remote system. + * 1. lst file list to add entry to + * 2. local local filename + * 3. remote remote filename + * 4. disposition disposition + * 5. floff offset of entry in flo-file (-1 if this is a flo file) + * 6. flofp FILE * of flo file + * 7. toend append to end of list + */ +void add_list(file_list **lst, char *local, char *Remote, int disposition, off_t floff, FILE *flofp, int toend) +{ + file_list **tmpl; + file_list *tmp; + + Syslog('o', "add_list(\"%s\",\"%s\",%d,%s)", MBSE_SS(local),MBSE_SS(Remote),disposition,toend?"to end":"to beg"); + + if (toend) + for (tmpl = lst; *tmpl; tmpl =&((*tmpl)->next)); + else + tmpl = &tmp; + *tmpl = (file_list*)malloc(sizeof(file_list)); + if (toend) { + (*tmpl)->next = NULL; + } else { + (*tmpl)->next = *lst; + *lst = *tmpl; + } + + (*tmpl)->remote = xtodos(Remote); + (*tmpl)->local = xstrcpy(local); + (*tmpl)->disposition = disposition; + (*tmpl)->floff = floff; + (*tmpl)->flofp = flofp; + return; +} + + + +static void check_flo(file_list **, char *); +static void check_flo(file_list **lst, char *nm) +{ + FILE *fp; + off_t off; + struct flock fl; + char buf[PATH_MAX],buf2[PATH_MAX],*p,*q; + int disposition; + struct stat stbuf; + + Syslog('O', "check_flo(\"%s\")",MBSE_SS(nm)); + + if ((fp = fopen(nm,"r+")) == NULL) { + Syslog('O',"no flo file"); + return; + } + fl.l_type = F_RDLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + if (fcntl(fileno(fp), F_SETLK, &fl) != 0) { + if (errno != EAGAIN) + WriteError("$cannot read-lock \"%s\"",MBSE_SS(nm)); + else + Syslog('O',"flo file busy"); + fclose(fp); + return; + } + + if (stat(nm, &stbuf) != 0) { + WriteError("$cannot access \"%s\"",MBSE_SS(nm)); + fclose(fp); + return; + } + + while (!feof(fp) && !ferror(fp)) { + off = ftell(fp); + if (fgets(buf, sizeof(buf)-1, fp) == NULL) + continue; + if (buf[0] == '~') + continue; /* skip sent files */ + if (*(p=buf + strlen(buf) -1) == '\n') + *p-- = '\0'; + if (*p == '\r') + *p = '\0'; + + switch (buf[0]) { + case '#': p=buf+1; disposition=TFS; break; + case '-': + case '^': p=buf+1; disposition=KFS; break; + case '@': p=buf+1; disposition=LEAVE; break; + case 0: continue; + default: p=buf; disposition=LEAVE; break; + } + + memset(&buf2, 0, sizeof(buf2)); + if (strlen(CFG.dospath)) { + if (strncasecmp(p, CFG.dospath, strlen(CFG.dospath)) == 0) { + strcpy(buf2,uxoutbound); + for (p+=strlen(CFG.dospath), q=buf2+strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } + } else { + if (strncasecmp(p, CFG.uxpath, strlen(CFG.uxpath)) == 0) { + for (p=p, q=buf2+strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } + } + + if ((q=strrchr(p,'/'))) + q++; + else + q = p; + add_list(lst, p, q, disposition, off, fp, 1); + } + + /* + * Add flo file to file list + */ + add_list(lst, nm, NULL, KFS, -1L, fp, 1); + + /* here, we leave .flo file open, it will be closed by */ + /* execute_disposition */ + + return; +} + + + +file_list *create_filelist(fa_list *al, char *fl, int create) +{ + file_list *st=NULL; + file_list *tmpf; + fa_list *tmpa; + char flavor, *tmpfl; + char *nm; + char tmpreq[13]; + struct stat stbuf; + int packets = 0; + FILE *fp; + unsigned char buffer[2]; + + Syslog('o', "Create_filelist(%s,\"%s\",%d)", al?ascfnode(al->addr,0x1f):"", MBSE_SS(fl), create); + made_request = 0; + + for (tmpa = al; tmpa; tmpa = tmpa->next) { + Syslog('o', "Check address %s", ascfnode(tmpa->addr, 0x1f)); + + /* + * Check spool files. + */ + if (strchr(fl, 'o')) { + nm=splname(tmpa->addr); + if ((fp=fopen(nm,"w"))) + fclose(fp); + if ((nm != NULL) && (stat(nm,&stbuf) == 0)) + add_list(&st,nm,NULL,DSF,0L,NULL,1); + } + + /* + * Check .pol files + */ + nm = polname(tmpa->addr); + if ((nm != NULL) && (stat(nm,&stbuf) == 0)) + add_list(&st,nm,NULL,DSF,0L,NULL,1); + + /* + * Check other files, all flavors + */ + tmpfl = fl; + while ((flavor = *tmpfl++)) { + /* + * Check normal mail packets + */ + nm=pktname(tmpa->addr,flavor); + if ((nm != NULL) && (stat(nm,&stbuf) == 0)) { + packets++; + add_list(&st,nm,tmpkname(),KFS,0L,NULL,1); + } + + /* + * Check .flo files for file attaches + */ + nm=floname(tmpa->addr,flavor); + check_flo(&st,nm); + } + + if ((session_flags & SESSION_WAZOO) && + ((session_flags & SESSION_HYDRA) == 0) && + (master || ((session_flags & SESSION_IFNA) == 0))) { + /* + * we don't distinguish flavoured reqs + */ + nm=reqname(tmpa->addr); + if ((nm != NULL) && (stat(nm,&stbuf) == 0)) { + sprintf(tmpreq,"%04X%04X.REQ", tmpa->addr->net,tmpa->addr->node); + add_list(&st,nm,tmpreq,DSF,0L,NULL,1); + made_request = 1; + } + } + } + + if (((st == NULL) && (create > 1)) || ((st != NULL) && (packets == 0) && (create > 0))) { + Syslog('o',"Create packet for %s",ascfnode(al->addr,0x1f)); + if ((fp = openpkt(NULL, al->addr, 'o'))) { + memset(&buffer, 0, sizeof(buffer)); + fwrite(buffer, 1, 2, fp); + fclose(fp); + } + add_list(&st,pktname(al->addr,'o'),tmpkname(),KFS,0L,NULL,0); + } + + for (tmpf = st; tmpf; tmpf = tmpf->next) + Syslog('O',"flist: \"%s\" -> \"%s\" dsp:%d flofp:%lu floff:%lu", + MBSE_SS(tmpf->local), MBSE_SS(tmpf->remote), tmpf->disposition, + (unsigned long)tmpf->flofp, (unsigned long)tmpf->floff); + + return st; +} + + + +/* + * Create file request list for the Hydra or Binkp protocol. + */ +file_list *create_freqlist(fa_list *al) +{ + file_list *st = NULL, *tmpf; + fa_list *tmpa; + char *nm; + char tmpreq[13]; + struct stat stbuf; + + Syslog('o', "create_freqlist(%s)", al?ascfnode(al->addr, 0x1f):""); + made_request = 0; + + for (tmpa = al; tmpa; tmpa = tmpa->next) { + nm = reqname(tmpa->addr); + if ((nm != NULL) && (stat(nm, &stbuf) == 0)) { + sprintf(tmpreq, "%04X%04X.REQ", tmpa->addr->net, tmpa->addr->node); + add_list(&st, nm, tmpreq, DSF, 0L, NULL, 1); + made_request = 1; + } + } + + for (tmpf = st; tmpf; tmpf = tmpf->next) + Syslog('O', "flist: \"%s\" -> \"%s\" dsp:%d flofp:%lu floff:%lu", + MBSE_SS(tmpf->local), MBSE_SS(tmpf->remote), tmpf->disposition, + tmpf->flofp, tmpf->floff); + + return st; +} + + + +void tidy_filelist(file_list *fl, int dsf) +{ + file_list *tmp; + + if (fl == NULL) + return; + + for (tmp=fl;fl;fl=tmp) { + tmp=fl->next; + if (dsf && (fl->disposition == DSF)) { + Syslog('o',"Removing sent file \"%s\"",MBSE_SS(fl->local)); + if (unlink(fl->local) != 0) { + if (errno == ENOENT) + Syslog('o',"Cannot unlink nonexistent file \"%s\"", MBSE_SS(fl->local)); + else + WriteError("$Cannot unlink file \"%s\"", MBSE_SS(fl->local)); + } + } + if (fl->local) + free(fl->local); + if (fl->remote) + free(fl->remote); + else if (fl->flofp) + fclose(fl->flofp); + free(fl); + } + return; +} + + + +void execute_disposition(file_list *fl) +{ + FILE *fp=NULL; + char *nm; + char tpl='~'; + + Syslog('o', "execute_disposition(%s)", fl->local); + nm = fl->local; + if (fl->flofp) { + /* + * Check for special case: flo-file + */ + if (fl->floff == -1) { + /* + * We check if there are any files left for transmission + * in the flo-file to decide whether to remove or leave + * it on disk. + */ + char buf[PATH_MAX]; + int files_remain = 0; + + if (fseek(fl->flofp, 0L, 0) == 0) { + while (!feof(fl->flofp) && !ferror(fl->flofp)) { + if (fgets(buf, sizeof(buf)-1, fl->flofp) == NULL) + continue; + + /* + * Count nr of files which haven't been + * sent yet + */ + if (buf[0] != '~') + files_remain++; + } + + } else { + WriteError("$Error seeking in .flo to 0"); + files_remain = -1; /* Keep flo-file */ + } + + if (files_remain) { + Syslog('o', "Leaving flo-file \"%s\", %d files remaining", MBSE_SS(nm), files_remain); + fl->disposition = LEAVE; + } else { + fl->disposition = KFS; + } + } else { + /* + * Mark files as sent in flo-file + */ + if (fseek(fl->flofp, fl->floff, 0) == 0) { + if (fwrite(&tpl,1,1,fl->flofp) != 1) { + WriteError("$Error writing '~' to .flo at %lu", (unsigned long)fl->floff); + } + fflush(fl->flofp); + fdatasync(fileno(fl->flofp)); + } else + WriteError("$error seeking in .flo to %lu", (unsigned long)fl->floff); + } + } + + switch (fl->disposition) { + case DSF: + case LEAVE: + break; + case TFS: + Syslog('o', "Truncating sent file \"%s\"",MBSE_SS(nm)); + if ((fp=fopen(nm,"w"))) + fclose(fp); + else + WriteError("$Cannot truncate file \"%s\"",MBSE_SS(nm)); + break; + case KFS: + Syslog('o', "Removing sent file \"%s\"",MBSE_SS(nm)); + if (unlink(nm) != 0) { + if (errno == ENOENT) + Syslog('o', "Cannot unlink nonexistent file \"%s\"", MBSE_SS(nm)); + else + WriteError("$Cannot unlink file \"%s\"", MBSE_SS(nm)); + } + break; + default: WriteError("execute_disposition: unknown disp %d for \"%s\"", + fl->disposition,MBSE_SS(nm)); + break; + } + + return; +} + + diff --git a/mbcico/filelist.h b/mbcico/filelist.h new file mode 100644 index 00000000..83afe41d --- /dev/null +++ b/mbcico/filelist.h @@ -0,0 +1,12 @@ +#ifndef _FILELIST_H +#define _FILELIST_H + +char *xtodos(char *); +void add_list(file_list **, char *, char *, int, off_t, FILE *, int); +file_list *create_filelist(fa_list *, char *, int); +file_list *create_freqlist(fa_list *); +void tidy_filelist(file_list *, int); +void execute_disposition(file_list *); + +#endif + diff --git a/mbcico/filetime.c b/mbcico/filetime.c new file mode 100644 index 00000000..e1385746 --- /dev/null +++ b/mbcico/filetime.c @@ -0,0 +1,121 @@ +/***************************************************************************** + * + * File ..................: mbcico/filetime.c + * Purpose ...............: Fidonet mailer + * Last modification date : 06-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "filetime.h" + + + +time_t gmtoff(time_t); +time_t gmtoff(time_t tt) +{ + struct tm lt; +#ifndef HAVE_TM_GMTOFF + struct tm gt; + time_t offset; + + lt = *localtime(&tt); + gt = *gmtime(&tt); + offset = gt.tm_yday - lt.tm_yday; + if (offset > 1) + offset =- 24; + else + if (offset < -1) + offset = 24; + else + offset *= 24; + + offset += gt.tm_hour - lt.tm_hour; + offset *= 60; + offset += gt.tm_min - lt.tm_min; + offset *= 60; + offset += gt.tm_sec - lt.tm_sec; + return offset; +#else + lt = *localtime(&tt); + return -lt.tm_gmtoff; +#endif +} + + + +/* + * SEAlink time conversion + * FIXME: I think there is one year difference, spec starts at 1 jan 1979, mtime starts at 1 jan 1980 + */ +time_t mtime2sl(time_t tt) +{ + return tt - gmtoff(tt); +} + + + +time_t sl2mtime(time_t tt) +{ + return tt + gmtoff(tt); +} + + + +/* + * Telink time conversion + */ +time_t mtime2tl(time_t tt) +{ + time_t tlt=0L; + struct tm *tm; + + tm=localtime(&tt); + tlt |= ((tm->tm_year)-1980) << 25; + tlt |= (tm->tm_mon) << 21; + tlt |= (tm->tm_mday) << 16; + tlt |= (tm->tm_hour) << 11; + tlt |= (tm->tm_min) << 5; + tlt |= (tm->tm_sec) >> 1; + return tlt; +} + + + +time_t tl2mtime(time_t tt) +{ + struct tm tm; + + tm.tm_year = ((tt >> 25) & 0x7f) + 1980; + tm.tm_mon = (tt >> 21) & 0x0f; + tm.tm_mday = (tt >> 16) & 0x1f; + tm.tm_hour = (tt >> 11) & 0x1f; + tm.tm_min = (tt >> 5 ) & 0x3f; + tm.tm_sec = ((tt ) & 0x1f) * 2; + + return mktime(&tm); +} + diff --git a/mbcico/filetime.h b/mbcico/filetime.h new file mode 100644 index 00000000..7e09c072 --- /dev/null +++ b/mbcico/filetime.h @@ -0,0 +1,11 @@ +#ifndef _FILETIME_H +#define _FILETIME_H + +time_t mtime2sl(time_t); +time_t sl2mtime(time_t); +time_t mtime2tl(time_t); +time_t tl2mtime(time_t); + + +#endif + diff --git a/mbcico/ftsc.c b/mbcico/ftsc.c new file mode 100644 index 00000000..caa74fc6 --- /dev/null +++ b/mbcico/ftsc.c @@ -0,0 +1,486 @@ +/***************************************************************************** + * + * File ..................: mbcico/ftsc.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "ttyio.h" +#include "statetbl.h" +#include "config.h" +#include "ftsc.h" +#include "rdoptions.h" +#include "recvbark.h" +#include "filelist.h" +#include "sendbark.h" +#include "respfreq.h" +#include "xmrecv.h" +#include "xmsend.h" + + + +extern int master; +extern int made_request; +static int rxftsc(void); +static int txftsc(void); +static int recvfiles(void); +static file_list *tosend; +extern int Loaded; + + +int rx_ftsc(void) +{ + int rc; + + Syslog('+', "Start inbound FTS-0001 session"); + IsDoing("FTS-0001 inbound"); + + session_flags |= SESSION_BARK; + if ((rc = rxftsc())) { + WriteError("Session failed: rc=%d",rc); + PUTCHAR(CAN); + PUTCHAR(CAN); + PUTCHAR(CAN); + } else + Syslog('+', "FTS-0001 session completed"); + + tidy_filelist(tosend, (rc == 0)); + tosend = NULL; + return rc; +} + + + + +int tx_ftsc(void) +{ + int rc; + + Syslog('+', "Start outbound FTS-0001 session with %s", ascfnode(remote->addr,0x1f)); + IsDoing("FTS-0001 to %s", ascfnode(remote->addr, 0x0f)); + + if ((rc = txftsc())) { + WriteError("Session failed: rc=%d",rc); + PUTCHAR(CAN); + PUTCHAR(CAN); + PUTCHAR(CAN); + } else + Syslog('+', "FTS-0001 session completed"); + + tidy_filelist(tosend, (rc == 0)); + tosend = NULL; + return rc; +} + + + +SM_DECL(txftsc,(char *)"txftsc") +SM_STATES + wait_command, + recv_mail, + send_req, + recv_req +SM_NAMES + (char *)"wait_command", + (char *)"recv_mail", + (char *)"send_req", + (char *)"recv_req" +SM_EDECL + int c,rc; + char *nonhold_mail; + int mailsent = FALSE, mailrcvd = FALSE; + + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + tosend = create_filelist(remote,nonhold_mail,2); + + Syslog('s', "txftsc SEND_MAIL"); + if ((rc = xmsndfiles(tosend))) + return rc; + mailsent = TRUE; + +SM_START(wait_command) + +SM_STATE(wait_command) + + Syslog('s', "txftsc WAIT_COMMAND"); + c = GETCHAR(30); + if (c == TIMEOUT) { + Syslog('+', "timeout waiting for remote action, try receive"); + SM_PROCEED(recv_mail); + } else if (c < 0) { + if (mailrcvd && mailsent) { + /* + * Some systems hangup after sending mail, so if we did + * send and receive mail we consider the session OK. + */ + Syslog('+', "Lost carrier, FTSC session looks complete"); + SM_SUCCESS; + } else { + Syslog('+', "got error waiting for TSYNC: received %d",c); + SM_ERROR; + } + } else switch (c) { + case TSYNC: SM_PROCEED(recv_mail); + break; + case SYN: SM_PROCEED(recv_req); + break; + case ENQ: SM_PROCEED(send_req); + break; + case 'C': + case NAK: PUTCHAR(EOT); + SM_PROCEED(wait_command); + break; + case CAN: SM_SUCCESS; /* this is not in BT */ + break; + default: Syslog('s', "got '%s' waiting command", printablec(c)); + PUTCHAR(SUB); + SM_PROCEED(wait_command); + break; + } + +SM_STATE(recv_mail) + + Syslog('s', "txftsc RECV_MAIL"); + if (recvfiles()) { + SM_ERROR; + } else { + mailrcvd = TRUE; + SM_PROCEED(wait_command); + } + +SM_STATE(send_req) + + Syslog('s', "txftsc SEND_BARK"); + if (sendbark()) { + SM_ERROR; + } else { + SM_SUCCESS; + } + +SM_STATE(recv_req) + + Syslog('s', "txftsc RECV_BARK"); + if (recvbark()) { + SM_ERROR; + } else { + SM_PROCEED(wait_command); + } + +SM_END +SM_RETURN + + + +SM_DECL(rxftsc,(char *)"rxftsc") +SM_STATES + recv_mail, + send_mail, + send_req, + recv_req +SM_NAMES + (char *)"recv_mail", + (char *)"send_mail", + (char *)"send_req", + (char *)"recv_req" +SM_EDECL + int c, count = 0, didwazoo = FALSE; + int sentmail = FALSE, rcvdmail = FALSE; + file_list *request = NULL, *tmpfl; + +SM_START(recv_mail) + +SM_STATE(recv_mail) + + Syslog('s', "rxftsc RECV_MAIL"); + if (recvfiles()) { + SM_ERROR; + } else { + rcvdmail = TRUE; + SM_PROCEED(send_mail); + } + +SM_STATE(send_mail) + + Syslog('s', "rxftsc SEND_MAIL count=%d", count); + if (count++ > 45) { + SM_ERROR; + } + + /* + * If we got a wazoo request, add files now. + */ + request = respond_wazoo(); + if (request != NULL) { + didwazoo = TRUE; + tmpfl = tosend; + tosend = request; + for (; request->next; request = request->next); + request->next = tmpfl; + + request = NULL; + } + + if (tosend == NULL) { + count = 0; + SM_PROCEED(send_req); + } + + PUTCHAR(TSYNC); + c = GETCHAR(1); + Syslog('x', "Got char 0x%02x", c); + if (c == TIMEOUT) { + Syslog('x', " timeout"); + SM_PROCEED(send_mail); + } else if (c < 0) { + Syslog('+', "got error waiting for NAK: received %d",c); + SM_ERROR; + } else switch (c) { + case 'C': + case NAK: if (xmsndfiles(tosend)) { + SM_ERROR; + } else { + sentmail = TRUE; + count = 0; + SM_PROCEED(send_req); + } + break; + case CAN: Syslog('+', "Remote refused to pickup mail"); + SM_SUCCESS; + break; + case EOT: PUTCHAR(ACK); + SM_PROCEED(send_mail); + break; + default: Syslog('s', "Got '%s' waiting NAK", printablec(c)); + SM_PROCEED(send_mail); + break; + } + +SM_STATE(send_req) + + Syslog('s', "rxftsc SEND_REQ count=%d", count); + + if (didwazoo) { + SM_SUCCESS; + } + + if (count > 15) { + SM_ERROR; + } + + if (!made_request) { + SM_PROCEED(recv_req); + } + + PUTCHAR(SYN); + c = GETCHAR(5); + Syslog('x', "Got char 0x%02x", c); + count++; + if (c == TIMEOUT) { + Syslog('x', " timeout"); + SM_PROCEED(send_req); + } else if (c < 0) { + Syslog('+', "got error waiting for ENQ: received %d",c); + SM_ERROR; + } else switch (c) { + case ENQ: if (sendbark()) { + SM_ERROR; + } else { + SM_PROCEED(recv_req); + } + break; + case CAN: Syslog('+', "Remote refused to accept request"); + SM_PROCEED(recv_req); + break; + case 'C': + case NAK: PUTCHAR(EOT); + SM_PROCEED(send_req); + break; + case SUB: SM_PROCEED(send_req); + break; + default: Syslog('s', "got '%s' waiting ENQ", printablec(c)); + SM_PROCEED(send_req); + break; + } + +SM_STATE(recv_req) + + Syslog('s', "rxftsc RECV_REQ"); + if (recvbark()) { + if (sentmail && rcvdmail) { + Syslog('+', "Consider session OK"); + SM_SUCCESS; + } else { + SM_ERROR; + } + } else { + SM_SUCCESS; + } + +SM_END +SM_RETURN + + + +SM_DECL(recvfiles,(char *)"recvfiles") +SM_STATES + recv_packet, + scan_packet, + recv_file +SM_NAMES + (char *)"recv_packet", + (char *)"scan_packet", + (char *)"recv_file" +SM_EDECL + int rc=0; + char recvpktname[16]; + char *fpath; + FILE *fp; + faddr f,t; + fa_list **tmpl; + +SM_START(recv_packet) + Loaded = FALSE; + +SM_STATE(recv_packet) + + sprintf(recvpktname,"%08lx.pkt",(unsigned long)sequencer()); + if ((rc = xmrecv(recvpktname)) == 1) { + SM_SUCCESS; + } else if (rc == 0) { + if (master) { + SM_PROCEED(recv_file); + } else { + SM_PROCEED(scan_packet); + } + } else { + SM_ERROR; + } + +SM_STATE(scan_packet) + + fpath = xstrcpy(inbound); + fpath = xstrcat(fpath,(char *)"/"); + fpath = xstrcat(fpath,recvpktname); + fp = fopen(fpath,"r"); + free(fpath); + if (fp == NULL) { + WriteError("$cannot open received packet"); + SM_ERROR; + } + switch (getheader(&f , &t, fp, recvpktname)) { + case 3: Syslog('+', "remote mistook us for %s",ascfnode(&t,0x1f)); + fclose(fp); + SM_ERROR; + case 0: Syslog('+', "accepting session"); + fclose(fp); + for (tmpl=&remote;*tmpl;tmpl=&((*tmpl)->next)); + (*tmpl)=(fa_list*)malloc(sizeof(fa_list)); + (*tmpl)->next=NULL; + (*tmpl)->addr=(faddr*)malloc(sizeof(faddr)); + (*tmpl)->addr->zone=f.zone; + (*tmpl)->addr->net=f.net; + (*tmpl)->addr->node=f.node; + (*tmpl)->addr->point=f.point; + (*tmpl)->addr->name=NULL; + (*tmpl)->addr->domain=NULL; + for (tmpl=&remote;*tmpl;tmpl=&((*tmpl)->next)) { + (void)nodelock((*tmpl)->addr); + /* try lock all remotes, ignore locking result */ + if (!Loaded) + if (noderecord((*tmpl)->addr)) + Loaded = TRUE; + } + + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + if (remote->addr->domain && strlen(remote->addr->domain)) + sprintf(history.aka.domain, "%s", remote->addr->domain); + + if (((nlent=getnlent(remote->addr))) && (nlent->pflag != NL_DUMMY)) { + Syslog('+', "remote is a listed system"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); + sprintf(history.system_name, "%s", nlent->name); + sprintf(history.location, "%s", nlent->location); + } else { + sprintf(history.system_name, "Unknown"); + sprintf(history.location, "Somewhere"); + } + + if (nlent) + rdoptions(Loaded); + + /* + * It appears that if the remote gave no password, the + * getheader function fills in a password itself. Maybe + * that's the reason why E.C did not switch to protected + * inbound, because of the failing password check. MB. + */ + if (f.name) { + Syslog('+', "Password correct, protected FTS-0001 session"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); + } + + tosend = create_filelist(remote,(char *)ALL_MAIL,1); + if (rc == 0) { + SM_PROCEED(recv_file); + } else { + SM_SUCCESS; + } + default: Syslog('+', "received bad packet apparently from",ascfnode(&f,0x1f)); + fclose(fp); + SM_ERROR; + } + +SM_STATE(recv_file) + + switch (xmrecv(NULL)) { + case 0: SM_PROCEED(recv_file); + break; + case 1: SM_SUCCESS; + break; + default: SM_ERROR; + break; + } + +SM_END +SM_RETURN + diff --git a/mbcico/ftsc.h b/mbcico/ftsc.h new file mode 100644 index 00000000..ddad502c --- /dev/null +++ b/mbcico/ftsc.h @@ -0,0 +1,10 @@ +#ifndef _FTSC_H +#define _FTSC_H + + +int rx_ftsc(void); +int tx_ftsc(void); + + +#endif + diff --git a/mbcico/hydra.c b/mbcico/hydra.c new file mode 100644 index 00000000..e4046007 --- /dev/null +++ b/mbcico/hydra.c @@ -0,0 +1,1690 @@ +/***************************************************************************** + * + * File ..................: mbcico/hydra.c + * Purpose ...............: Fidonet mailer + * Last modification date : 30-Dec-2000 + * Remark ................: See below for more copyright details and credits. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * ifcico v3.0.cm - hydra protocol module + * Copyright (C) 1996-98 Christof Meerwald. + * + * $RCSfile$ - $Author$ + * $Revision$ - $Date$ + */ + +/* + * The HYDRA protocol was designed by + * Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT and + * Joaquim H. Homrighausen + * COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED + */ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "filelist.h" +#include "filetime.h" +#include "ttyio.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "openfile.h" +#include "lutil.h" +#include "respfreq.h" +#include "mbcico.h" +#include "hydra.h" + + + +#define H_RXWINDOW 0L +#define H_TXWINDOW 0L + + + +static int put_binbyte(char *outbuf, char c); +static int put_hexbyte(char *outbuf, char c); +static enum HyPktTypes hyrxpkt(char *rxbuf, int *rxlen, int tot); +static void hytxpkt(enum HyPktTypes pkttype, char *txbuf, int txlen); +static int put_flags(char *buf, unsigned long Flags); +static unsigned long get_flags(char *buf); +static int resync(off_t off); +static int hydra_batch(int role, file_list *to_send); + +extern unsigned long sentbytes; +extern unsigned long rcvdbytes; + + + +static struct h_flags_struct { + char *str; + unsigned long val; +} h_flags[] = + { + { (char *)"XON", HOPT_XONXOFF }, + { (char *)"TLN", HOPT_TELENET }, + { (char *)"CTL", HOPT_CTLCHRS }, + { (char *)"HIC", HOPT_HIGHCTL }, + { (char *)"HI8", HOPT_HIGHBIT }, + { (char *)"BRK", HOPT_CANBRK }, + { (char *)"ASC", HOPT_CANASC }, + { (char *)"UUE", HOPT_CANUUE }, + { (char *)"C32", HOPT_CRC32 }, + { (char *)"DEV", HOPT_DEVICE }, + { (char *)"FPT", HOPT_FPT }, + { NULL , 0x0L } +}; + +static int txoptions, rxoptions; + + +static char *put_long(char *buffer, long val) +{ +#if defined(__i386__) + *(unsigned long *) buffer = (unsigned long) val; +#else + 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; +#endif + + return buffer; +} + + + +static long get_long(char *buffer) +{ +#if defined(__i386__) + return *(long *) buffer; +#else + 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); +#endif +} + + + +char *PktS(int); +char *PktS(int c) +{ + switch (c) { + case 'A' : return (char *)"START"; + case 'B' : return (char *)"INIT"; + case 'C' : return (char *)"INITACK"; + case 'D' : return (char *)"FINFO"; + case 'E' : return (char *)"FINFOACK"; + case 'F' : return (char *)"DATA"; + case 'G' : return (char *)"DATAACK"; + case 'H' : return (char *)"RPOS"; + case 'I' : return (char *)"EOF"; + case 'J' : return (char *)"EOFACK"; + case 'K' : return (char *)"END"; + case 'L' : return (char *)"IDLE"; + case 'M' : return (char *)"DEVDATA"; + case 'N' : return (char *)"DEVDACK"; + case 'a' : return (char *)"PKTEND"; + case 'b' : return (char *)"BINPKT"; + case 'c' : return (char *)"HEXPKT"; + case 'd' : return (char *)"ASCPKT"; + case 'e' : return (char *)"UUEPKT"; + default: break; + } + return (char *)""; +} + + + +int put_binbyte(char *outbuf, char c) +{ + static int lastc = -1; + register int count = 0; + register char n; + + + n = c; + if (txoptions & HOPT_HIGHCTL) { + n &= 0x7f; + } + + if ((n == H_DLE) + || ((txoptions & HOPT_XONXOFF) && ((n == XON) || (n == XOFF))) + || ((txoptions & HOPT_TELENET) && (n == '\r') && (lastc == '@')) + || ((txoptions & HOPT_CTLCHRS) && ((n < 32) || (n == 127)))) { + *outbuf++ = H_DLE; + c ^= 0x40; + count++; + } + + *outbuf++ = c; + lastc = n; + + return count + 1; +} + + + +int put_hexbyte(char *outbuf, char c) +{ + static const char hexdigit[] = "0123456789abcdef"; + register int count = 0; + + if (c & 0x80) { + *outbuf++ = '\\'; + *outbuf++ = hexdigit[(c >> 4) & 0x0f]; + *outbuf++ = hexdigit[c & 0x0f]; + count = 3; + } else if ((c < 32) || (c == 127)) { + *outbuf++ = H_DLE; + *outbuf++ = c ^ 0x40; + count = 2; + } else if (c == '\\') { + *outbuf++ = '\\'; + *outbuf++ = '\\'; + count = 2; + } else { + *outbuf++ = c; + count = 1; + } + + return count; +} + + + +/* TODO: code cleanup */ +/* TODO: error handling */ +enum HyPktTypes hyrxpkt(char *rxbuf, int *rxlen, int tot) +{ + static char rxencbuf[H_BUFLEN]; + static enum HyPktTypes pkttype = H_NOPKT; + static char *inbuf = rxencbuf, *outbuf; + int c, i, n; + static int rxdle = 0; + static enum HyPktFormats format; + + while ((c = GETCHAR(tot)) >= 0) { + if (rxoptions & HOPT_HIGHBIT) + c &= 0x7f; + + n = c; + if (rxoptions & HOPT_HIGHCTL) + n &= 0x7f; + + if ((n != H_DLE) + && (((rxoptions & HOPT_XONXOFF) && ((n == XON) || (n == XOFF))) + || ((rxoptions & HOPT_CTLCHRS) && ((n < 32) || (n == 127))))) + continue; + + + if ((rxdle) || (c == H_DLE)) { + switch (c) { + case H_DLE: + rxdle++; + if (rxdle >= 5) { + inbuf = rxencbuf; + return H_CANCEL; + } + break; + + case HCHR_PKTEND: + switch (format) { + case HCHR_BINPKT: + *rxlen = inbuf - rxencbuf; + memcpy(rxbuf, rxencbuf, *rxlen); + break; + + case HCHR_HEXPKT: + outbuf = rxencbuf; + *rxlen = 0; + + while (outbuf < inbuf) { + if ((*outbuf == '\\') && (*++outbuf != '\\')) { + i = *outbuf++; + n = *outbuf++; + + if ((i -= '0') > 9) + i -= ('a' - ':'); + if ((n -= '0') > 9) + n -= ('a' - ':'); + + if ((i & ~0x0f) || (n & ~ 0x0f)) { + Syslog('+', "Hydra: RXPKT assert"); + die(1); + break; + } + + rxbuf[*rxlen] = (i << 4) | n; + *rxlen += 1; + } else { + rxbuf[*rxlen] = *outbuf++; + *rxlen += 1; + } + } + break; + + case HCHR_ASCPKT: + case HCHR_UUEPKT: + default: + Syslog('+', "Hydra: RXPKT assert"); + die(1); + } + + if ((format != HCHR_HEXPKT) && (rxoptions & HOPT_CRC32)) { + n = h_crc32test(crc32ccitt(rxbuf, *rxlen)); + *rxlen -= 4; /* remove CRC-32 */ + } else { + n = h_crc16test(crc16ccitt(rxbuf, *rxlen)); + *rxlen -= 2; /* remove CRC-16 */ + } + + *rxlen -= 1; /* remove packet type */ + pkttype = rxbuf[*rxlen]; + + /* check if CRC test succeeded */ + if (n) { + inbuf = rxencbuf; + Syslog('h', "Hydra: RXPKT rcvd %s", PktS(pkttype)); + return pkttype; + } else { + Syslog('+', "Hydra: RXPKT CRC test failed"); + } + break; + + case HCHR_BINPKT: + case HCHR_HEXPKT: + case HCHR_ASCPKT: + case HCHR_UUEPKT: + format = c; + inbuf = rxencbuf; + rxdle = 0; + break; + + default: + *inbuf++ = c ^ 0x40; + rxdle = 0; + break; + } + } else { + *inbuf++ = c; + } + } + + Syslog('h', "GETCHAR returned %i", c); + + if ((c == TERROR) || (c == EOFILE) || (c == HANGUP)) { + return H_CARRIER; + } + + return H_NOPKT; +} + + + +/* TODO: support packet prefix string */ +void hytxpkt(enum HyPktTypes pkttype, char *txbuf, int txlen) +{ + static char txencbuf[H_BUFLEN]; + char *outbuf, *inbuf; + enum HyPktFormats format; + + if (pkttype == 'G') + Syslog('h', "ACK 0x%02x%02x%02x%02x", txbuf[0], txbuf[1], txbuf[2], txbuf[3]); + + /* + * some packets have to be transferred in HEX mode + */ + if ((pkttype == HPKT_START) || (pkttype == HPKT_INIT) || + (pkttype == HPKT_INITACK) || (pkttype == HPKT_END) || + (pkttype == HPKT_IDLE)) { + format = HCHR_HEXPKT; + } else { + /* do we need to strip high bit */ + if (txoptions & HOPT_HIGHBIT) { + if ((txoptions & HOPT_CTLCHRS) && (txoptions & HOPT_CANUUE)) { + format = HCHR_UUEPKT; /* use UUE packet encoding */ + } else if (txoptions & HOPT_CANASC) { + format = HCHR_ASCPKT; /* we can use ASCII packet encoding */ + } else { + format = HCHR_HEXPKT; /* fall back to hex packet encoding */ + } + } else { + format = HCHR_BINPKT; /* we can use binary packet encoding */ + } + } + + /* + * Append format byte to data + */ + txbuf[txlen] = pkttype; + txlen++; + + /* + * check if we can use 32-bit CRC's + */ + if ((format != HCHR_HEXPKT) && (txoptions & HOPT_CRC32)) { + unsigned long crc; + + /* + * Calc CRC-32 of data + pkttype + */ + crc = ~crc32ccitt(txbuf, txlen); + + /* + * Append one's complement of CRC to data, lowbyte first + */ + txbuf[txlen++] = crc; + txbuf[txlen++] = crc >> 8; + txbuf[txlen++] = crc >> 16; + txbuf[txlen++] = crc >> 24; + } else { + unsigned short crc; + + /* + * Calc CRC-16 of data + pkttype + */ + crc = ~crc16ccitt(txbuf, txlen); + + /* + * Append one's complement of CRC to data, lowbyte first + */ + txbuf[txlen++] = crc; + txbuf[txlen++] = crc >> 8; + } + + inbuf = txbuf; + + outbuf = txencbuf; + *outbuf++ = H_DLE; + *outbuf++ = format; + + /* encode packet data */ + switch (format) { + case HCHR_BINPKT: + while (txlen > 0) { + outbuf += put_binbyte(outbuf, *inbuf); + inbuf++; + txlen--; + } + break; + + case HCHR_HEXPKT: + while (txlen > 0) { + outbuf += put_hexbyte(outbuf, *inbuf); + inbuf++; + txlen--; + } + break; + + /* ASCII and UUE packets are not yet supported */ + case HCHR_ASCPKT: + case HCHR_UUEPKT: + default: + Syslog('+', "Hydra: TXPKT assert"); + die(1); + } + + *outbuf++ = H_DLE; + *outbuf++ = HCHR_PKTEND; + + if ((pkttype != HPKT_DATA) && (format != HCHR_BINPKT)) { + *outbuf++ = '\r'; + *outbuf++ = '\n'; + } + + Syslog('h', "Hydra: TXPKT send %s", PktS(pkttype)); + PUT(txencbuf, outbuf - txencbuf); + + return; +} + + + +int put_flags(char *buf, unsigned long Flags) +{ + int i, count = 0; + + for (i = 0; h_flags[i].val; i++) { + if (Flags & h_flags[i].val) { + if (count > 0) { + *buf++ = ','; + count++; + } + + strcpy(buf, h_flags[i].str); + buf += H_FLAGLEN; + count += H_FLAGLEN; + } + } + + *buf = 0; + return count; +} + + + +unsigned long get_flags(char *buf) +{ + unsigned long Flags = 0L; + char *p; + int i; + + + for (p = strtok(buf, ","); p != NULL; p = strtok(NULL, ",")) { + for (i = 0; h_flags[i].val; i++) { + if (!strcmp(p, h_flags[i].str)) { + Flags |= h_flags[i].val; + break; + } + } + } + + return Flags; +} + + + +int resync(off_t off) +{ + return 0; +} + + + +int hydra_batch(int role, file_list *to_send) +{ + static char txbuf[H_BUFLEN], rxbuf[H_BUFLEN]; + struct stat txstat; /* file stat being transmitted */ + FILE *txfp = NULL; /* file currently being transmitted */ + FILE *rxfp = NULL; /* file currently being received */ + char *inbuf, *outbuf; + int rxlen, txlen; /* length of receive/transmit buffer */ + long txwindow, rxwindow; /* window sizes */ + long txpos, rxpos; /* file positions */ + long stxpos, srxpos; + long longnum; + int hdxlink = FALSE; + int txretries, rxretries; + int txlastack, txsyncid; + int rxlastsync, rxsyncid; + int rxlastdatalen; + int blksize; + int goodbytes; + int goodneeded; + enum HyTxStates txstate; + enum HyRxStates rxstate; + int txwaitpkt, rxwaitpkt; + enum HyPktTypes pkttype; + int waitputget = 0; + time_t rxstarttime, rxendtime; + time_t txstarttime, txendtime; + int sverr; + + Syslog('h', "Hydra: resettimers"); + RESETTIMERS(); + + txpos = rxpos = 0; + stxpos = srxpos = 0; + txretries = rxretries = 0; + txlastack = txsyncid = 0; + rxlastsync = rxsyncid = 0; + rxlastdatalen = 0; + blksize = 512; + goodbytes = 0; + goodneeded = 1024; + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + txstate = HTX_START; + txoptions = HTXI_OPTIONS; + + rxstate = HRX_INIT; + rxoptions = HRXI_OPTIONS; + + while ((txstate != HTX_DONE) && (txstate != HTX_Abort)) { + /* + * Is transmitter waiting for packet? + */ + txwaitpkt = ((txstate == HTX_SWAIT) || (txstate == HTX_INITACK) + || ((txstate == HTX_RINIT) && (rxstate == HRX_INIT)) + || (txstate == HTX_FINFOACK) || (txstate == HTX_DATA) + || (txstate == HTX_DATAACK) + || ((txstate == HTX_XWAIT) && (rxstate != HRX_DONE)) + || (txstate == HTX_EOFACK) || (txstate == HTX_ENDACK) + || (txstate == HTX_REND)); + + /* + * Is receiver waiting for packet? + */ + rxwaitpkt = ((rxstate == HRX_INIT) || (rxstate == HRX_FINFO) || + (rxstate == HRX_DATA) || (rxstate == HRX_DONE)); + + /* + * Do we have to wait for a packet? + */ + if (txwaitpkt && rxwaitpkt) { + /* + * Don't wait for a packet if transmitter is in DATA state + */ + if ((txstate == HTX_DATA) || ((txstate == HTX_REND) && (rxstate == HRX_DONE))) { + if (txstate == HTX_DATA) { + waitputget = WAITPUTGET(-1); + if (waitputget & 1) { + pkttype = hyrxpkt(rxbuf, &rxlen, 0); + } else { + pkttype = H_NOPKT; + } + } else { + pkttype = hyrxpkt(rxbuf, &rxlen, 0); + } + } else { + pkttype = hyrxpkt(rxbuf, &rxlen, -1); + } + + if ((pkttype == H_CARRIER) || (EXPIRED(TIMERNO_BRAIN))) { + Syslog('h', "Hydra: BRAIN timer expired"); + txstate = HTX_Abort; + break; + } + } else { + pkttype = H_NOPKT; + } + + /* + * Special handling for RPOS packet + */ + if ((pkttype == HPKT_RPOS) && (rxlen == 12) + && ((txstate == HTX_DATA) || (txstate == HTX_DATAACK) + || (txstate == HTX_XWAIT) || (txstate == HTX_EOFACK))) { + long rpos_pos = get_long(rxbuf); + long rpos_blksize = get_long(rxbuf + 4); + long rpos_id = get_long(rxbuf + 8); + + if (rpos_pos < 0) { + /* + * this differs from the protocol definition: txpos is used + * instead of rxpos (I think it's wrong in the protocol + * definition as in the example source also txpos is used) + */ + if ((rpos_pos == -2) && (txpos != -2) && (txstate == HTX_EOFACK)) { + txpos = -2; + txstate = HTX_EOF; + } else { + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + txstate = HTX_SkipFile; + } + } + + if (rpos_id == txsyncid) { + txretries++; + + if (txretries >= 10) { + Syslog('+', "Hydra: too many errors"); + txstate = HTX_Abort; + break; + } + } else { + if (rpos_pos >= 0) { + txpos = rpos_pos; + txsyncid = rpos_id; + txretries = 1; + blksize = rpos_blksize; + goodbytes = 0; + goodneeded += 1024; + if (goodneeded > 8192) + goodneeded = 8192; + + /* if we receive an RPOS packet in EOFACK-state we have to + change back to DATA-state */ + if (txstate == HTX_EOFACK) + txstate = HTX_DATA; + + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + } + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } + + + switch (txstate) { + /* + * initiate Hydra session + */ + case HTX_START: + Syslog('h', "SM 'HTX' entering 'START'"); + if (txretries < 10) { + PUT((char *)"hydra\r", 6); /* send AutoStart string */ + hytxpkt(HPKT_START, txbuf, 0); + Syslog('h', "Hydra: set TX timer %d", H_START); + SETTIMER(TIMERNO_TX, H_START); + txstate = HTX_SWAIT; + } else { + Syslog('+', "Hydra: transmitter start TIMEOUT"); + txstate = HTX_Abort; + break; + } + break; + + /* + * wait for START packet + */ + case HTX_SWAIT: + Syslog('h', "SM 'HTX' entering 'SWAIT'"); + if (((pkttype == HPKT_START) && (rxlen == 0)) || (pkttype == HPKT_INIT)) { + txretries = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + txstate = HTX_INIT; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: transmitter timeout (HTX_SWAIT)"); + txretries++; + txstate = HTX_START; + } + break; + + /* + * send INIT packet + */ + case HTX_INIT: + Syslog('h', "SM 'HTX' entering 'INIT'"); + if (txretries < 10) { + outbuf = txbuf; + + /* Application ID string */ + outbuf += sprintf(outbuf, "%08lx%s,%s", H_REVSTAMP, "mbcico", VERSION) + 1; + + /* Supported options */ + outbuf += put_flags(outbuf, HCAN_OPTIONS) + 1; + Syslog('h', "Hydra: supported options: %08lx", HCAN_OPTIONS); + + /* Desired options */ + outbuf += put_flags(outbuf, HDEF_OPTIONS & HCAN_OPTIONS & ~HUNN_OPTIONS) + 1; + Syslog('h', "Hydra: desired options : %08lx", HDEF_OPTIONS & HCAN_OPTIONS & ~HUNN_OPTIONS); + + /* Desired transmitter and receiver window size */ + outbuf += sprintf(outbuf, "%08lx%08lx", H_TXWINDOW, H_RXWINDOW) + 1; + + /* Packet prefix string */ + *outbuf++ = 0; + + hytxpkt(HPKT_INIT, txbuf, outbuf - txbuf); + + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + txstate = HTX_INITACK; + } else { + Syslog('+', "Hydra: too many errors waiting for INITACK"); + txstate = HTX_Abort; + break; + } + break; + + /* + * wait for an INIT acknowledge packet + */ + case HTX_INITACK: + Syslog('h', "SM 'HTX' entering 'INITACK'"); + if ((pkttype == HPKT_INITACK) && (rxlen == 0)) { + txretries = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + txstate = HTX_RINIT; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: tx timeout"); + txretries++; + txstate = HTX_INIT; + } + break; + + /* + * wait for receiver to leave INIT state + */ + case HTX_RINIT: + Syslog('h', "SM 'HTX' entering 'RINIT'"); + if (rxstate != HRX_INIT) + txstate = HTX_NextFile; + break; + + /* + * prepare next file for transmitting + */ + case HTX_NextFile: + Syslog('h', "SM 'HTX' entering 'NextFile'"); + /* + * skip file with NULL remote name + */ + while (to_send && (to_send->remote == NULL)) { + execute_disposition(to_send); + to_send = to_send->next; + } + + if (to_send) { + struct flock txflock; + + if (to_send->remote == NULL) + break; + + txflock.l_type=F_RDLCK; + txflock.l_whence=0; + txflock.l_start=0L; + txflock.l_len=0L; + + txfp = fopen(to_send->local, "r"); + if (txfp == NULL) { + sverr = errno; + if ((sverr == ENOENT) || (sverr == EINVAL)) { + Syslog('+', "File %s doesn't exist, removing", MBSE_SS(to_send->local)); + execute_disposition(to_send); // Added 18-10-99 MB. + } else { + WriteError("$Hydra: cannot open file %s, skipping", MBSE_SS(to_send->local)); + } + to_send = to_send->next; + break; + } + + if (fcntl(fileno(txfp), F_SETLK, &txflock) != 0) { + WriteError("$Hydra: cannot lock file %s, skipping", MBSE_SS(to_send->local)); + fclose(txfp); + to_send = to_send->next; + break; + } + + if (stat(to_send->local, &txstat) != 0) { + WriteError("$Hydra: cannot access \"%s\", skipping",MBSE_SS(to_send->local)); + fclose(txfp); + to_send = to_send->next; + break; + } + + Syslog('+', "Hydra: send \"%s\" as \"%s\"", MBSE_SS(to_send->local), MBSE_SS(to_send->remote)); + Syslog('+', "Hydra: size %lu bytes, dated %s",(unsigned long)txstat.st_size, date(txstat.st_mtime)); + (void) time(&txstarttime); + } + + txstate = HTX_ToFName; + break; /* TODO: fallthrough */ + + case HTX_ToFName: + Syslog('h', "SM 'HTX' entering 'ToFName'"); + txsyncid = 0; + txretries = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + txstate = HTX_FINFO; + break; /* TODO: fallthrough */ + + /* + * transmit File Information packet + */ + case HTX_FINFO: + Syslog('h', "SM 'HTX' entering 'FINFO'"); + if (txretries >= 10) { + txstate = HTX_Abort; + break; + } else { + if (to_send) { + txlen = sprintf(txbuf, "%08lx%08lx%08lx%08lx%08lx", + mtime2sl(txstat.st_mtime+(txstat.st_mtime%2)), + txstat.st_size, 0UL, 0UL, 0UL); + + /* + * convert file name to DOS-format + */ + outbuf = xtodos(to_send->remote); + strcpy(txbuf + txlen, outbuf); + free(outbuf); + for(; txbuf[txlen]; txlen++) { + txbuf[txlen] = tolower(txbuf[txlen]); + } + txlen++; + + strcpy(txbuf + txlen, to_send->remote); + txlen += strlen(to_send->remote) + 1; + } else { + txbuf[0] = 0; + txlen = 1; + } + + hytxpkt(HPKT_FINFO, txbuf, txlen); + + if (txretries > 0) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + } else { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + } + + txstate = HTX_FINFOACK; + } + break; + + /* + * get FINFOACK packet + */ + case HTX_FINFOACK: + Syslog('h', "SM 'HTX' entering 'FINFOACK'"); + if ((pkttype == HPKT_FINFOACK) && (rxlen == 4)) { + txpos = get_long(rxbuf); + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + + if (to_send == NULL) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + txstate = HTX_REND; + } else if (txpos >= 0L) { + if (txpos > 0L) + Syslog('+', "Hydra: restart from %lu", txpos); + stxpos = txpos; + txretries = 0; + txlastack = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + txstate = HTX_DATA; + } else if (txpos == -1) { + Syslog('+', "Hydra: Receiver already has this file, skipping"); + fclose(txfp); + execute_disposition(to_send); + to_send = to_send->next; + txstate = HTX_NextFile; + } else if (txpos == -2) { + Syslog('+', "Hydra: receiver requested to skip this file for now"); + fclose(txfp); + to_send = to_send->next; + txstate = HTX_NextFile; + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: transmitter timeout (HTX_FINFOACK)"); + txretries++; + txstate = HTX_FINFO; + } + break; + + case HTX_DATA: + Syslog('h', "SM 'HTX' entering 'DATA'"); + Syslog('h', "txwindow=%d txpos=%d txlastack=%d", txwindow, txpos, txlastack); + if ((rxstate != HRX_DONE) && (hdxlink)) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + txstate = HTX_XWAIT; + } else if ((pkttype == HPKT_DATAACK) && (rxlen == 4)) { + longnum = get_long(rxbuf); + + Syslog('h', "received 'DATAACK' (0x%08lx)", longnum); + + if (longnum > txlastack) { + txlastack = longnum; + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((txwindow) && (txpos >= txlastack + txwindow)) { + /* + * We have to wait for an ACK before we can continue + */ + if (txretries > 0) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + } else { + Syslog('H', "HYDRA: SET TX TIMER %D", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + } + txstate = HTX_DATAACK; + break; + } else { + /* + * check if there is enough room in output + */ + if ((waitputget & 2) == 0) { + break; + } + + fseek(txfp, txpos, SEEK_SET); + put_long(txbuf, txpos); + Nopper(); + Syslog('h', "Check for more frames here?"); + txlen = fread(txbuf + 4, 1, blksize, txfp); + Syslog('h', "Hydra: send DATA (0x%08lx) %lu", txpos, txlen); + + if (txlen == 0) { + if (ferror(txfp)) { + WriteError("$Hydra: error reading from file"); + txstate = HTX_SkipFile; + } else { + txstate = HTX_EOF; + } + } else { + txpos += txlen; + sentbytes += txlen; + goodbytes += txlen; + txlen += 4; + hytxpkt(HPKT_DATA, txbuf, txlen); + + if (goodbytes > goodneeded) { + blksize *= 2; + if (blksize > H_MAXBLKLEN) { + blksize = H_MAXBLKLEN; + } + } + } + } + break; + + case HTX_SkipFile: + Syslog('h', "SM 'HTX' entering 'SkipFile'"); + /* + * this differs from the protocol definition: -2 is used + * instead of -1 (I think it's wrong in the protocol + * definition as in the example source also -2 is used) + * MB: No, I don't think this is wrong, -1 means file already + * there, -2 means skip for now, try another time. + */ + txpos = -2; + txretries = 0; + txstate = HTX_EOF; + break; + + case HTX_DATAACK: + Syslog('h', "SM 'HTX' entering 'DATAACK'"); + if ((pkttype == HPKT_DATAACK) && (rxlen == 4)) { + longnum = get_long(rxbuf); + + if ((longnum > txlastack) && (txpos < longnum + txwindow)) { + txlastack = longnum; + txretries = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + txstate = HTX_DATA; + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (txretries >= 10) { + Syslog('+', "Hydra: too many errors"); + txstate = HTX_Abort; + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: tx timeout"); + txretries++; + txstate = HTX_DATA; + } + break; + + case HTX_XWAIT: + Syslog('h', "SM 'HTX' entering 'XWAIT'"); + if (rxstate == HRX_DONE) { + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + txstate = HTX_DATA; + } else if ((pkttype == HPKT_DATAACK) && (rxlen == 4)) { + longnum = get_long(rxbuf); + if (longnum > txlastack) { + txlastack = longnum; + } + pkttype = H_NOPKT; /* packet has already been processed */ + + } else if (pkttype == HPKT_RPOS) { + /* + * Handle RPOS in state DATA but stay in this state + */ + pkttype = H_NOPKT; /* packet has already been processed */ + + } else if ((pkttype == HPKT_IDLE) && (rxlen == 0)) { + hdxlink = FALSE; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + txstate = HTX_DATA; + pkttype = H_NOPKT; /* packet has already been processed */ + + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('h', "Hydra: TX timer expired"); + hytxpkt(HPKT_IDLE, txbuf, 0); + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + } + break; + + case HTX_EOF: + Syslog('h', "SM 'HTX' entering 'EOF'"); + if (txretries >= 10) { + txstate = HTX_Abort; + break; + } else { + put_long(txbuf, txpos); + hytxpkt(HPKT_EOF, txbuf, 4); + + if (txretries > 0) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + } else { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + } + Syslog('h', "Hydra: entering TX EOFACK"); + txstate = HTX_EOFACK; + } + break; + + case HTX_EOFACK: + Syslog('h', "SM 'HTX' entering 'EOFACK'"); + if ((pkttype == HPKT_EOFACK) && (rxlen == 0)) { + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + + /* + * calculate time needed and bytes transferred + */ + (void) time(&txendtime); + txstarttime = txendtime - txstarttime; + + if (txstarttime <= 0L) + txstarttime = 1L; + + /* close transmitter file */ + fclose(txfp); + + if (txpos >= 0) { + stxpos = txpos - stxpos; + Syslog('+', "Hydra: OK %lu bytes in %s (%ld cps)", + stxpos, str_time(txstarttime), stxpos/txstarttime); + execute_disposition(to_send); + } else { + Syslog('+', "Hydra: transmitter skipped file after %ld seconds", txstarttime); + } + + to_send = to_send->next; + txstate = HTX_NextFile; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_DATAACK) && (rxlen == 4)) { + longnum = get_long(rxbuf); + txlastack = longnum; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: transmitter timeout (HTX_EOFACK)"); + txretries++; + txstate = HTX_EOF; + } + break; + + case HTX_REND: + Syslog('h', "SM 'HTX' entering 'REND'"); + if (rxstate == HRX_DONE) { + txretries = 0; + txstate = HTX_END; + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('h', "Hydra: TX timer expired"); + hytxpkt(HPKT_IDLE, txbuf, 0); + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + } + break; + + case HTX_END: + Syslog('h', "SM 'HTX' entering 'END'"); + if (txretries >= 10) { + txstate = HTX_Abort; + break; + } else { + hytxpkt(HPKT_END, txbuf, 0); + hytxpkt(HPKT_END, txbuf, 0); + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + txstate = HTX_ENDACK; + } + break; + + case HTX_ENDACK: + Syslog('h', "SM 'HTX' entering 'ENDACK'"); + if ((pkttype == HPKT_END) && (rxlen == 0)) { + hytxpkt(HPKT_END, txbuf, 0); + hytxpkt(HPKT_END, txbuf, 0); + hytxpkt(HPKT_END, txbuf, 0); + txstate = HTX_DONE; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: transmitter timeout (HTX_ENDACK)"); + txretries++; + txstate = HTX_END; + } + break; + + case HTX_DONE: + case HTX_Abort: + /* nothing to do */ + break; + + default: + die(1); + } /* switch (txstate) */ + + switch (rxstate) { + case HRX_INIT: + Syslog('h', "SM 'HRX' entering 'INIT'"); + if (pkttype == HPKT_INIT) { + /* TODO: some checking, error handling */ + + /* Skip application ID */ + Syslog('+', "Hydra: remote \"%s\"", rxbuf+8); + inbuf = rxbuf + strlen(rxbuf) + 1; +// Syslog('+', "Hydra: inbuf=\"%s\"", inbuf); + + inbuf += strlen(inbuf) + 1; + + rxoptions = (HDEF_OPTIONS & HCAN_OPTIONS) | HUNN_OPTIONS; + + /* + * get supported options + */ + rxoptions |= get_flags(inbuf); + inbuf += strlen(inbuf) + 1; + + /* + * get desired options + */ + rxoptions &= get_flags(rxbuf + strlen(rxbuf) + 1); + rxoptions &= HCAN_OPTIONS; + + /* + * set options + */ + txoptions = rxoptions; + put_flags(txbuf, rxoptions); + Syslog('h', "Hydra: options: %s (%08lx)", txbuf, rxoptions); + + /* + * get desired window sizes + */ + txwindow = rxwindow = 0; + sscanf(inbuf, "%08lx%08lx", &rxwindow, &txwindow); + + if (rxwindow < 0) + rxwindow = 0; + + if (H_RXWINDOW && ((rxwindow == 0) || (rxwindow > H_RXWINDOW))) + rxwindow = H_RXWINDOW; + + if (txwindow < 0) + txwindow = 0; + + if (H_TXWINDOW && ((txwindow == 0) || (txwindow > H_TXWINDOW))) + txwindow = H_TXWINDOW; + + Syslog('h', "Hydra: txwindow=%d, rxwindow=%d", txwindow, rxwindow); + + hytxpkt(HPKT_INITACK, txbuf, 0); + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + rxstate = HRX_FINFO; + + pkttype = H_NOPKT; /* packet has already been processed */ + } + break; + + case HRX_FINFO: + Syslog('h', "SM 'HRX' entering 'FINFO'"); + if (pkttype == HPKT_FINFO) { + /* + * check if we have received an `End of batch' FINFO packet + */ + if ((rxlen == 1) && (rxbuf[0] == 0)) { + put_long(txbuf, 0); + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + rxstate = HRX_DONE; + } + /* + * check if FINFO packet is at least long enough to contain + * file information + */ + else if ((rxlen > 41) && (rxbuf[rxlen - 1] == 0)) { + time_t timestamp; + time_t orgstamp; + long filesize; + char dosname[8 + 1 + 3 + 1], *Name; + + sscanf(rxbuf, "%08lx%08lx%*08x%*08x%*08x", ×tamp, &filesize); + + /* convert timestamp to UNIX time */ + orgstamp = timestamp; + timestamp = sl2mtime(timestamp); + + /* + * check if DOS conforming file name is max. 8+1+3 chars long + */ + if (strlen(rxbuf + 40) <= 12) { + strcpy(dosname, rxbuf + 40); + } else { + strcpy(dosname, "BadWazoo"); + } + + /* + * check if real file name is specified + */ + if ((strlen(rxbuf + 40) + 41) < rxlen) { + Name = rxbuf + strlen(rxbuf + 40) + 41; + + /* + * use DOS-filename if real- and DOS-name only + * differ in case sensitivity + */ + if (strcasecmp(Name, dosname) == 0) { + Name = dosname; + } + } else { + Name = dosname; + } + + Syslog('+', "Hydra: receive \"%s\" (%ld bytes) dated %s", + Name, filesize, date(timestamp)); + + rxfp = openfile(Name, timestamp, filesize, &rxpos, resync); + (void) time(&rxstarttime); + + /* check for error opening file */ + if (rxfp) { + srxpos = rxpos; + rxstate = HRX_ToData; + } else { + if (filesize == rxpos) { + /* Skip this file, it's already here */ + Syslog('+', "Hydra: Skipping file %s", Name); + put_long(txbuf, -1); + } else { + /* Skip this file for now if error opening file */ + put_long(txbuf, -2); + } + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + } + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (pkttype == HPKT_INIT) { + hytxpkt(HPKT_INITACK, txbuf, 0); + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_EOF) && (rxlen == 4)) { + hytxpkt(HPKT_EOFACK, txbuf, 0); + + pkttype = H_NOPKT; /* packet has already been processed */ + } + break; + + case HRX_ToData: + Syslog('h', "SM 'HRX' entering 'ToData'"); + put_long(txbuf, rxpos); + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + rxsyncid = 0; + rxlastsync = 0; + rxretries = 0; + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + rxstate = HRX_DATA; + break; + + case HRX_DATA: + Syslog('h', "SM 'HRX' entering 'DATA'"); + if ((pkttype == HPKT_DATA) && (rxlen > 4)) { + longnum = get_long(rxbuf); + Syslog('h', "Hydra: rcvd DATA (0x%08lx, 0x%08lx) %lu", longnum, rxpos, rxlen-4); + Nopper(); + + if (longnum == rxpos) { + if (fwrite(rxbuf + 4, 1, rxlen - 4, rxfp) != (rxlen - 4)) { + WriteError("$Hydra: error writing to file"); + rxpos = -2; + } else { + rxlastdatalen = rxlen - 4; + rxpos += rxlen - 4; + rcvdbytes += rxlen - 4; + rxretries = 0; + rxlastsync = rxpos; + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + if (rxwindow) { + put_long(txbuf, rxpos); + hytxpkt(HPKT_DATAACK, txbuf, 4); + } + } + } else { + if (rxpos >= 0) { + Syslog('+', "Hydra: received bad rxpos"); + } + rxstate = HRX_BadPos; + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_EOF) && (rxlen == 4)) { + longnum = get_long(rxbuf); + + if (longnum == rxpos) { + /* + * calculate time and CPU usage needed + */ + (void) time(&rxendtime); + + if (rxpos >= 0) { + rxfp = NULL; + if (!closefile(1)) { + srxpos = rxpos - srxpos; + + rxstarttime = rxendtime - rxstarttime; + if (rxstarttime <= 0) + rxstarttime = 1L; + + Syslog('+', "Hydra: OK %lu bytes in %s (%ld cps)", + srxpos, str_time(rxstarttime), srxpos/rxstarttime); + + rxstate = HRX_OkEOF; + } else { + Syslog('+', "Hydra: error closing file"); + rxpos = -2; + + /* + * Note: the following state change isn't 100 % + * conformant with the Hydra protocol specification. + */ + rxstate = HRX_BadPos; + } + } else { + Syslog('+', "Hydra: receiver skipped file after %ld seconds", + rxendtime - rxstarttime); + + if (rxfp) { + closefile(0); + rxfp = NULL; + } + + rxstate = HRX_OkEOF; + } + } else if (longnum == -2) { + if (rxfp) { + closefile(0); + rxfp = NULL; + } + + rxstate = HRX_OkEOF; + } else { + if (longnum >= 0) { + Syslog('+', "Hydra: received bad rxpos"); + } + rxstate = HRX_BadPos; /* TODO: fallthrough */ + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (pkttype == HPKT_FINFO) { + put_long(txbuf, rxpos); + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_IDLE) && (rxlen == 0) && (hdxlink == FALSE)) { + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_RX)) { + Syslog('h', "Hydra: RX timer expired"); + rxstate = HRX_HdxLink; + } + break; + + case HRX_BadPos: + Syslog('h', "SM 'HRX' entering 'BadPos'"); + longnum = get_long(rxbuf); + + if (longnum <= rxlastsync) { + rxretries = 0; + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + } + rxlastsync = longnum; + rxstate = HRX_Timer; + break; + + case HRX_Timer: + Syslog('h', "SM 'HRX' entering 'Timer'"); + if ((!RUNNING(TIMERNO_RX)) || (EXPIRED(TIMERNO_RX))) { + Syslog('h', "Hydra: RX timer expired"); + rxstate = HRX_HdxLink; + } else { + rxstate = HRX_DATA; + } + break; + + case HRX_HdxLink: + Syslog('h', "SM 'HRX' entering 'HdxLink'"); + if ((rxretries > 4) && (txstate != HTX_REND) && (role == 0) && (hdxlink == FALSE)) { + rxretries = 0; + hdxlink = TRUE; + } + rxstate = HRX_Retries; + break; /* TODO: fallthrough */ + + case HRX_Retries: + Syslog('h', "SM 'HRX' entering 'Retries'"); + rxretries++; + if (rxretries >= 10) { + Syslog('+', "Hydra: too many errors"); + txstate = HTX_Abort; + } else if (rxretries == 1) { + rxsyncid++; + } + rxstate = HRX_RPos; + break; /* TODO: fallthrough */ + + case HRX_RPos: + Syslog('h', "SM 'HRX' entering 'RPos'"); + rxlastdatalen /= 2; + if (rxlastdatalen < 64) + rxlastdatalen = 64; + + put_long(txbuf, rxpos); + put_long(txbuf + 4, rxlastdatalen); + put_long(txbuf + 8, rxsyncid); + + hytxpkt(HPKT_RPOS, txbuf, 12); + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_RX, H_MINTIMER); + rxstate = HRX_DATA; + break; + + case HRX_OkEOF: + Syslog('h', "SM 'HRX' entering 'OkEOF'"); + hytxpkt(HPKT_EOFACK, txbuf, 0); + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + rxstate = HRX_FINFO; + break; + + case HRX_DONE: + Syslog('h', "SM 'HRX' entering 'DONE'"); + if (pkttype == HPKT_FINFO) { + put_long(txbuf, -2); + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_IDLE) && (rxlen == 0)) { + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + + pkttype = H_NOPKT; /* packet has already been processed */ + } + break; + + } /* switch(rxstate) */ + + if (pkttype != H_NOPKT) { + Syslog('h', "Hydra: rcvd packet %s - ignored", PktS(pkttype)); + pkttype = H_NOPKT; /* ignore received packet */ + } + + } /* while() */ + + Syslog('h', "Hydra: resettimers"); + RESETTIMERS(); + + if (txstate == HTX_Abort) { + /* check if file is still open */ + if (rxfp) { + rxfp = NULL; + closefile(0); + } + + Syslog('+', "Hydra: signal CAN to remote"); + FLUSHOUT(); + /* 8 times CAN and 10 times BS */ + PUT((char *)"\030\030\030\030\030\030\030\030\010\010\010\010\010\010\010\010\010\010", 18); + sleep(4); /* wait a few seconds... */ + FLUSHIN(); + + return 2; + } + + return 0; +} + + + +int hydra(int role) +{ + int rc; + fa_list *eff_remote, tmpl; + file_list *tosend = NULL, *request = NULL, *respond = NULL, *tmpfl; + char *nonhold_mail; + + Syslog('+', "Hydra: start transfer"); + session_flags |= SESSION_HYDRA; /* Hydra special file requests */ + + if (emsi_remote_lcodes & LCODE_NPU) { + Syslog('+', "Hydra: remote requested \"no pickup\", no send"); + eff_remote = NULL; + } else if (emsi_remote_lcodes & LCODE_PUP) { + Syslog('+', "Hydra: remote requested \"pickup primary\""); + tmpl.addr = remote->addr; + tmpl.next = NULL; + eff_remote = &tmpl; + } else { + eff_remote = remote; + } + + if (role) { + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + } else { + nonhold_mail = (char *)ALL_MAIL; + } + + if (emsi_remote_lcodes & LCODE_HAT) { + Syslog('+', "Hydra: remote requested \"hold all traffic\", no send"); + tosend = NULL; + } else { + tosend = create_filelist(eff_remote, nonhold_mail, 0); + } + + if (session_flags & SESSION_WAZOO) + request = create_freqlist(remote); + + + /* + * Send only file requests during first batch if remote supports + * "RH1" flag. + */ + if (emsi_remote_lcodes & LCODE_RH1) { + rc = hydra_batch(role, request); + } else { + if (request != NULL) { + tmpfl = tosend; + tosend = request; + for (; request->next; request = request->next); + request->next = tmpfl; + + request = NULL; + } + + rc = hydra_batch(role, tosend); + } + + Syslog('+', "Hydra: start second batch"); + + if (rc == 0) { + if ((emsi_local_opts & OPT_NRQ) == 0) + respond = respond_wazoo(); + + if (emsi_remote_lcodes & LCODE_RH1) { + for (tmpfl = tosend; tmpfl->next; tmpfl = tmpfl->next); + tmpfl->next = respond; + + rc = hydra_batch(role, tosend); + tmpfl->next = NULL; /* split filelist into tosend + and respond again */ + } else { + rc = hydra_batch(role, respond); + } + } + + tidy_filelist(request, (rc == 0)); + tidy_filelist(tosend, (rc == 0)); + tidy_filelist(respond, 0); + + Syslog('+', "Hydra: end transfer"); + + return rc; +} + + diff --git a/mbcico/hydra.h b/mbcico/hydra.h new file mode 100644 index 00000000..156aef6f --- /dev/null +++ b/mbcico/hydra.h @@ -0,0 +1,206 @@ +/* As this file has been derived from the HydraCom source, here is the + * original copyright information: + * + * Note that you can find the file LICENSE.DOC from HydraCom in + * misc/HYDRACOM-LICENSE + */ +/*============================================================================= + + HydraCom Version 1.00 + + A sample implementation of the + HYDRA Bi-Directional File Transfer Protocol + + HydraCom was written by + Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT + COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED + + The HYDRA protocol was designed by + Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT and + Joaquim H. Homrighausen + COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED + + + Revision history: + 06 Sep 1991 - (AGL) First tryout + .. ... .... - Internal development + 11 Jan 1993 - HydraCom version 1.00, Hydra revision 001 (01 Dec 1992) + + + For complete details of the Hydra and HydraCom licensing restrictions, + please refer to the license agreements which are published in their entirety + in HYDRACOM.C and LICENSE.DOC, and also contained in the documentation file + HYDRACOM.DOC + + Use of this file is subject to the restrictions contained in the Hydra and + HydraCom licensing agreements. If you do not find the text of this agreement + in any of the aforementioned files, or if you do not have these files, you + should immediately contact LENTZ SOFTWARE-DEVELOPMENT and/or Joaquim + Homrighausen at one of the addresses listed below. In no event should you + proceed to use this file without having accepted the terms of the Hydra and + HydraCom licensing agreements, or such other agreement as you are able to + reach with LENTZ SOFTWARE-DEVELOMENT and Joaquim Homrighausen. + + + Hydra protocol design and HydraCom driver: Hydra protocol design: + Arjen G. Lentz Joaquim H. Homrighausen + LENTZ SOFTWARE-DEVELOPMENT 389, route d'Arlon + Langegracht 7B L-8011 Strassen + 3811 BT Amersfoort Luxembourg + The Netherlands + FidoNet 2:283/512, AINEX-BBS +31-33-633916 FidoNet 2:270/17 + arjen_lentz@f512.n283.z2.fidonet.org joho@ae.lu + + Please feel free to contact us at any time to share your comments about our + software and/or licensing policies. + +=============================================================================*/ + +#ifndef _HYDRA_H +#define _HYDRA_H + +/* HYDRA Specification Revision/Timestamp ---------Revision------Date------- */ +#define H_REVSTAMP 0x2b1aab00L /* 001 01 Dec 1992 */ +#define H_REVISION 1 + +/* HYDRA Basic Values ------------------------------------------------------ */ +#ifndef XON +#define XON ('Q' - '@') /* Ctrl-Q (^Q) xmit-on character */ +#define XOFF ('S' - '@') /* Ctrl-S (^S) xmit-off character */ +#endif +#define H_DLE ('X' - '@') /* Ctrl-X (^X) HYDRA DataLinkEscape */ +#define H_MINBLKLEN 64 /* Min. length of a HYDRA data block */ +#define H_MAXBLKLEN 2048 /* Max. length of a HYDRA data block */ +#define H_OVERHEAD 8 /* Max. no. control bytes in a pkt */ +#define H_MAXPKTLEN ((H_MAXBLKLEN + H_OVERHEAD + 5) * 3) /* Encoded pkt */ +#define H_BUFLEN (H_MAXPKTLEN + 16) /* Buffer sizes: max.enc.pkt + slack */ +#define H_PKTPREFIX 31 /* Max length of pkt prefix string */ +#define H_FLAGLEN 3 /* Length of a flag field */ +#define H_RETRIES 10 /* No. retries in case of an error */ +#define H_MINTIMER 10 /* Minimum timeout period */ +#define H_MAXTIMER 60 /* Maximum timeout period */ +#define H_START 5 /* Timeout for re-sending startstuff */ +#define H_IDLE 20 /* Idle? tx IDLE pkt every 20 secs */ +#define H_BRAINDEAD 120 /* Braindead in 2 mins (120 secs) */ + +/* HYDRA Return codes ------------------------------------------------------ */ +#define XFER_ABORT (-1) /* Failed on this file & abort xfer */ +#define XFER_SKIP 0 /* Skip this file but continue xfer */ +#define XFER_OK 1 /* File was sent, continue transfer */ + + +/* HYDRA Transmitter States ------------------------------------------------ */ +enum HyTxStates +{ + HTX_DONE, /* All over and done */ + HTX_START, /* Send start autostr + START pkt */ + HTX_SWAIT, /* Wait for any pkt or timeout */ + HTX_INIT, /* Send INIT pkt */ + HTX_INITACK, /* Wait for INITACK pkt */ + HTX_RINIT, /* Wait for HRX_INIT -> HRX_FINFO */ + HTX_NextFile, + HTX_ToFName, + HTX_FINFO, /* Send FINFO pkt */ + HTX_FINFOACK, /* Wait for FINFOACK pkt */ + HTX_DATA, /* Send next packet with file data */ + HTX_SkipFile, + HTX_DATAACK, /* Wait for DATAACK packet */ + HTX_XWAIT, /* Wait for HRX_END */ + HTX_EOF, /* Send EOF pkt */ + HTX_EOFACK, /* End of file, wait for EOFACK pkt */ + HTX_REND, /* Wait for HRX_END && HTD_DONE */ + HTX_END, /* Send END pkt (finish session) */ + HTX_ENDACK, /* Wait for END pkt from other side */ + HTX_Abort, +}; + +/* HYDRA Receiver States --------------------------------------------------- */ +enum HyRxStates +{ + HRX_DONE, /* All over and done */ + HRX_INIT, /* Wait for INIT pkt */ + HRX_FINFO, /* Wait for FINFO pkt of next file */ + HRX_ToData, + HRX_DATA, /* Wait for next DATA pkt */ + HRX_BadPos, + HRX_Timer, + HRX_HdxLink, + HRX_Retries, + HRX_RPos, + HRX_OkEOF, +}; + +/* HYDRA Packet Types ------------------------------------------------------ */ +enum HyPktTypes +{ + HPKT_START = 'A', /* Startup sequence */ + HPKT_INIT = 'B', /* Session initialisation */ + HPKT_INITACK = 'C', /* Response to INIT pkt */ + HPKT_FINFO = 'D', /* File info (name, size, time) */ + HPKT_FINFOACK = 'E', /* Response to FINFO pkt */ + HPKT_DATA = 'F', /* File data packet */ + HPKT_DATAACK = 'G', /* File data position ACK packet */ + HPKT_RPOS = 'H', /* Transmitter reposition packet */ + HPKT_EOF = 'I', /* End of file packet */ + HPKT_EOFACK = 'J', /* Response to EOF packet */ + HPKT_END = 'K', /* End of session */ + HPKT_IDLE = 'L', /* Idle - just saying I'm alive */ + HPKT_DEVDATA = 'M', /* Data to specified device */ + HPKT_DEVDACK = 'N', /* Response to DEVDATA pkt */ + + HPKT_HIGHEST = 'N' /* Highest known pkttype in this imp */ +}; + +/* HYDRA Internal Pseudo Packet Types -------------------------------------- */ +#define H_NOPKT 0 /* No packet (yet) */ +#define H_CANCEL (-1) /* Received cancel sequence 5*Ctrl-X */ +#define H_CARRIER (-2) /* Lost carrier */ +#define H_SYSABORT (-3) /* Aborted by operator on this side */ +#define H_TXTIME (-4) /* Transmitter timeout */ +#define H_DEVTXTIME (-5) /* Device transmitter timeout */ +#define H_BRAINTIME (-6) /* Braindead timeout (quite fatal) */ + +/* HYDRA Packet Format: START[]END ------------------------ */ +enum HyPktFormats +{ + HCHR_PKTEND = 'a', /* End of packet (any format) */ + HCHR_BINPKT = 'b', /* Start of binary packet */ + HCHR_HEXPKT = 'c', /* Start of hex encoded packet */ + HCHR_ASCPKT = 'd', /* Start of shifted 7bit encoded pkt */ + HCHR_UUEPKT = 'e', /* Start of uuencoded packet */ +}; + +/* HYDRA Local Storage of INIT Options (Bitmapped) ------------------------- */ +#define HOPT_XONXOFF (0x00000001L) /* Escape XON/XOFF */ +#define HOPT_TELENET (0x00000002L) /* Escape CR-'@'-CR (Telenet escape) */ +#define HOPT_CTLCHRS (0x00000004L) /* Escape ASCII 0-31 and 127 */ +#define HOPT_HIGHCTL (0x00000008L) /* Escape above 3 with 8th bit too */ +#define HOPT_HIGHBIT (0x00000010L) /* Escape ASCII 128-255 + strip high */ +#define HOPT_CANBRK (0x00000020L) /* Can transmit a break signal */ +#define HOPT_CANASC (0x00000040L) /* Can transmit/handle ASC packets */ +#define HOPT_CANUUE (0x00000080L) /* Can transmit/handle UUE packets */ +#define HOPT_CRC32 (0x00000100L) /* Packets with CRC-32 allowed */ +#define HOPT_DEVICE (0x00000200L) /* DEVICE packets allowed */ +#define HOPT_FPT (0x00000400L) /* Can handle filenames with paths */ + +/* What we can do */ +#define HCAN_OPTIONS (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT | HOPT_CRC32) +/* Vital options if we ask for any; abort if other side doesn't support them */ +#define HNEC_OPTIONS (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT | HOPT_CANBRK) +/* Non-vital options; nice if other side supports them, but doesn't matter */ +#define HUNN_OPTIONS (HOPT_CANASC | HOPT_CANUUE | HOPT_CRC32) +/* Default options */ +#define HDEF_OPTIONS (HOPT_CRC32) +/* rxoptions during init (needs to handle ANY link yet unknown at that point */ +#define HRXI_OPTIONS (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT) +/* ditto, but this time txoptions */ +#define HTXI_OPTIONS (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT) + + +#define h_crc16test(crc) (((crc) == 0xf0b8 ) ? 1 : 0) +#define h_crc32test(crc) (((crc) == 0xdebb20e3L) ? 1 : 0) + +int hydra(int); + +#endif + diff --git a/mbcico/lutil.c b/mbcico/lutil.c new file mode 100644 index 00000000..b78f6b74 --- /dev/null +++ b/mbcico/lutil.c @@ -0,0 +1,94 @@ +/***************************************************************************** + * + * File ..................: mbcico/lutil.c + * Purpose ...............: Fidonet mailer + * Last modification date : 12-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "lutil.h" + + +char *myname=(char *)"unknown"; + + +void setmyname(char *arg) +{ + if ((myname = strrchr(arg, '/'))) + myname++; + else + myname = arg; +} + + + +static char *mon[] = { +(char *)"Jan",(char *)"Feb",(char *)"Mar", +(char *)"Apr",(char *)"May",(char *)"Jun", +(char *)"Jul",(char *)"Aug",(char *)"Sep", +(char *)"Oct",(char *)"Nov",(char *)"Dec" +}; + + + +char *date(time_t t) +{ + struct tm ptm; + time_t now; + static char buf[20]; + + if (t) + now=t; + else + time(&now); + ptm=*localtime(&now); + sprintf(buf,"%s %02d %02d:%02d:%02d", + mon[ptm.tm_mon],ptm.tm_mday, + ptm.tm_hour,ptm.tm_min,ptm.tm_sec); + return(buf); +} + + + +int IsZMH() +{ + static char buf[81]; + + sprintf(buf, "SBBS:0;"); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:2,2", 7) == 0) + return TRUE; + } + return FALSE; +} + + + diff --git a/mbcico/lutil.h b/mbcico/lutil.h new file mode 100644 index 00000000..b8f648a8 --- /dev/null +++ b/mbcico/lutil.h @@ -0,0 +1,9 @@ +#ifndef LUTIL_H +#define LUTIL_H + + +void setmyname(char *); +char *date(long); +int IsZMH(void); + +#endif diff --git a/mbcico/m7recv.c b/mbcico/m7recv.c new file mode 100644 index 00000000..c8e7b686 --- /dev/null +++ b/mbcico/m7recv.c @@ -0,0 +1,190 @@ +/***************************************************************************** + * + * File ..................: mbcico/m7recv.c + * Purpose ...............: Fidonet mailer + * Last modification date : 02-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "statetbl.h" +#include "ttyio.h" +#include "m7recv.h" + + + +static int m7_recv(void); +static char* fn; +static int last; + +int m7recv(char *fname) +{ + int rc; + + fn = fname; + last = 0; + rc = m7_recv(); + if (rc) + return -1; + else if (last) + return 1; + else + return 0; +} + + + +SM_DECL(m7_recv,(char *)"m7recv") +SM_STATES + sendnak, + waitack, + waitchar, + sendack, + sendcheck, + waitckok +SM_NAMES + (char *)"sendnak", + (char *)"waitack", + (char *)"waitchar", + (char *)"sendack", + (char *)"sendcheck", + (char *)"waitckok" +SM_EDECL + + int count = 0; + int c, i = 0; + char *p = fn; + char cs = SUB; + +SM_START(waitchar) + +SM_STATE(sendnak) + + Syslog('X', "m7recv SENDNAK count=%d", count); + if (count++ > 20) { + Syslog('+', "Too many tries getting modem7 name"); + SM_ERROR; + } + p = fn; + cs = SUB; + i = 0; + PUTCHAR(NAK); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + +SM_STATE(waitack) + + Syslog('X', "m7recv WAITACK"); + c = GETCHAR(5); + if (c == TIMEOUT) { + Syslog('X', "m7 got timeout waiting for ACK"); + SM_PROCEED(sendnak); + } else if (c < 0) { + SM_ERROR; + } else { + Syslog('X', "Got 0x%02x %s", c, printablec(c)); + switch (c) { + case ACK: SM_PROCEED(waitchar); + break; + case EOT: last=1; + SM_SUCCESS; + break; + default: Syslog('X', "m7 got '%s' waiting for ACK", printablec(c)); + break; + } + } + +SM_STATE(waitchar) + + Syslog('X', "m7recv WAITCHAR"); + c = GETCHAR(1); + if (c == TIMEOUT) { + Syslog('X', "m7 got timeout waiting for char",c); + SM_PROCEED(sendnak); + } else if (c < 0) { + SM_ERROR; + } else { + Syslog('X', "Got 0x%02x %s", c, printablec(c)); + switch (c) { + case EOT: last=1; + SM_SUCCESS; + break; + case SUB: *p='\0'; + SM_PROCEED(sendcheck); + break; + case 'u': SM_PROCEED(sendnak); + break; + default: cs += c; + if (i < 15) { + if (c != ' ') { + if (i == 8) + *p++='.'; + *p++ = tolower(c); + } + i++; + } + SM_PROCEED(sendack); + break; + } + } + +SM_STATE(sendack) + + Syslog('X', "m7recv SENDACK"); + PUTCHAR(ACK); + SM_PROCEED(waitchar); + +SM_STATE(sendcheck) + + Syslog('X', "m7recv SENDCHECK cs=%d", cs); + PUTCHAR(cs); + SM_PROCEED(waitckok); + +SM_STATE(waitckok) + + Syslog('X', "m7recv WAITCKOK"); + c = GETCHAR(1); + if (c == TIMEOUT) { + Syslog('X', "m7 got timeout waiting for ack ACK"); + SM_PROCEED(sendnak); + } else if (c < 0) { + SM_ERROR; + } else if (c == ACK) { + SM_SUCCESS; + } else { + SM_PROCEED(sendnak); + } + +SM_END +SM_RETURN + + diff --git a/mbcico/m7recv.h b/mbcico/m7recv.h new file mode 100644 index 00000000..818210c4 --- /dev/null +++ b/mbcico/m7recv.h @@ -0,0 +1,8 @@ +#ifndef _M7RECV_H +#define _M7RECV_H + +int m7recv(char *); + + +#endif + diff --git a/mbcico/m7send.c b/mbcico/m7send.c new file mode 100644 index 00000000..254caff4 --- /dev/null +++ b/mbcico/m7send.c @@ -0,0 +1,191 @@ +/***************************************************************************** + * + * File ..................: mbcico/m7send.c + * Purpose ...............: Fidonet mailer + * Last modification date : 02-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "statetbl.h" +#include "ttyio.h" +#include "m7send.h" + +static int m7_send(void); + +static char *fn; + +int m7send(char *fname) +{ + fn=fname; + return m7_send(); +} + + + +SM_DECL(m7_send,(char *)"m7send") +SM_STATES + waitnak, + sendack, + sendchar, + waitack, + sendsub, + waitcheck, + ackcheck +SM_NAMES + (char *)"waitnak", + (char *)"sendack", + (char *)"sendchar", + (char *)"waitack", + (char *)"sendsub", + (char *)"waitcheck", + (char *)"ackcheck" +SM_EDECL + + char buf[12],*p; + int i,c,count=0; + char cs=SUB; + + memset(buf,' ',sizeof(buf)); + for (i=0,p=fn; (i<8) && (*p) && (*p != '.'); i++,p++) + buf[i] = toupper(*p); + if (*p == '.') + p++; + for (; (i<11) && (*p); i++,p++) + buf[i] = toupper(*p); + for (i=0; i<11; i++) + cs += buf[i]; + buf[11]='\0'; + Syslog('x', "modem7 filename \"%s\", checksum %02x", buf,(unsigned char)cs); + +SM_START(sendack) + +SM_STATE(waitnak) + + Syslog('x', "m7send WAITNAK"); + if (count++ > 20) { + Syslog('+', "too many tries sending modem7 name"); + SM_ERROR; + } + + c=GETCHAR(5); + if (c == TIMEOUT) { + Syslog('x', "m7 got timeout waiting NAK"); + SM_PROCEED(waitnak); + } else if (c < 0) { + SM_ERROR; + } else if (c == NAK) { + SM_PROCEED(sendack); + } else { + Syslog('x', "m7 got '%s' waiting NAK", printablec(c)); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } + +SM_STATE(sendack) + + Syslog('x', "m7send SENDACK"); + i = 0; + PUTCHAR(ACK); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(sendchar); + } + +SM_STATE(sendchar) + + Syslog('x', "m7send SENDCHAR"); + if (i > 11) { + SM_PROCEED(sendsub); + } + + PUTCHAR(buf[i++]); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + +SM_STATE(waitack) + + Syslog('x', "m7send WAITACK"); + c = GETCHAR(1); + if (c == TIMEOUT) { + Syslog('x', "m7 got timeout waiting ACK for char %d",i); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } else if (c < 0) { + SM_ERROR; + } else if (c == ACK) { + SM_PROCEED(sendchar); + } else { + Syslog('x', "m7 got '%s' waiting ACK for char %d", printablec(c),i); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } + +SM_STATE(sendsub) + + Syslog('x', "m7send SENDSUB"); + PUTCHAR(SUB); + SM_PROCEED(waitcheck); + +SM_STATE(waitcheck) + + Syslog('x', "m7send WAITCHECK"); + c = GETCHAR(1); + if (c == TIMEOUT) { + Syslog('x', "m7 got timeout waiting check"); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } else if (c < 0) { + SM_ERROR; + } else if (c == cs) { + SM_PROCEED(ackcheck); + } else { + Syslog('x', "m7 got %02x waiting check %02x", (unsigned char)c,(unsigned char)cs); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } + +SM_STATE(ackcheck) + + Syslog('x', "m7send ACKCHECK"); + PUTCHAR(ACK); + if (STATUS) { + SM_ERROR; + } else { + SM_SUCCESS; + } + +SM_END +SM_RETURN + + diff --git a/mbcico/m7send.h b/mbcico/m7send.h new file mode 100644 index 00000000..8a9984ef --- /dev/null +++ b/mbcico/m7send.h @@ -0,0 +1,7 @@ +#ifndef M7SEND_H +#define M7SEND_H + +int m7send(char *); + +#endif + diff --git a/mbcico/mbcico.c b/mbcico/mbcico.c new file mode 100644 index 00000000..5d832f5c --- /dev/null +++ b/mbcico/mbcico.c @@ -0,0 +1,413 @@ +/***************************************************************************** + * + * File ..................: mbcico/mbcico.c + * Purpose ...............: Fidonet mailer + * Last modification date : 07-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "config.h" +#include "answer.h" +#include "portsel.h" +#include "call.h" +#include "callall.h" +#include "lutil.h" +#include "mbcico.h" +#include "session.h" + + + +int master = 0; +int forcedcalls = 0; +int immediatecall = FALSE; +char *forcedphone = NULL; +char *forcedline = NULL; +char *inetaddr = NULL; +char *envptr = NULL; +time_t t_start; +time_t t_end; +time_t c_start; +time_t c_end; +int online = 0; +unsigned long sentbytes = 0; +unsigned long rcvdbytes = 0; +int tcp_mode = TCPMODE_NONE; +int Loaded = FALSE; + + +extern char *myname; +char *inbound; +char *uxoutbound; +char *name; +char *phone; +char *flags; +extern int gotfiles; +extern int mypid; + + + +void usage(void) +{ + fprintf(stderr,"ifcico; (c) Eugene G. Crosser, 1993-1997\n"); + fprintf(stderr,"mbcico ver. %s; (c) %s\n\n", VERSION, ShortRight); + fprintf(stderr,"-r -a ...\n"); + fprintf(stderr,"-r 0|1 1 - master, 0 - slave [0]\n"); + fprintf(stderr,"-n forced phone number\n"); + fprintf(stderr,"-l forced tty device\n"); + fprintf(stderr,"-t must be one of ifc|itn|ibn, forces TCP/IP\n"); + fprintf(stderr,"-a supply internet hostname if not in nodelist\n"); + fprintf(stderr," should be in domain form, e.g. f11.n22.z3\n"); + fprintf(stderr," (this implies master mode)\n"); + fprintf(stderr,"\n or: %s tsync|yoohoo|**EMSI_INQC816|-t ibn|-t ifc|-t itn\n",myname); + fprintf(stderr," (this implies slave mode)\n"); +} + + + +void free_mem(void) +{ + free(inbound); + if (name) + free(name); + if (phone) + free(phone); + if (flags) + free(flags); + if (uxoutbound) + free(uxoutbound); +} + + + +void die(int onsig) +{ + int total = 0; + + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + Syslog('+', "Terminated with error %d", onsig); + } + + if (sentbytes || rcvdbytes) { + total = (int)(c_end - c_start); + if (!total) + total = 1; + Syslog('+', "Sent %lu bytes, received %lu bytes, avg %d cps", + sentbytes, rcvdbytes, (sentbytes + rcvdbytes) / total); + } + + if (online) + Syslog('+', "Connected %s", str_time(online)); + + if (gotfiles) + CreateSema((char *)"mailin"); + + time(&t_end); + Syslog(' ', "MBCICO finished in %s", t_elapsed(t_start, t_end)); + free_mem(); + if (envptr) + free(envptr); + ExitClient(onsig); +} + + + +int main(int argc, char *argv[]) +{ + int i, c, uid; + fa_list *callist = NULL, **tmpl; + faddr *tmp; + int rc, maxrc, callno = 0, succno = 0; + char *answermode = NULL, *p = NULL, *cmd = NULL; + struct passwd *pw; + char temp[81]; + FILE *fp; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * The next trick is to supply a fake environment variable + * MBSE_ROOT in case we are started from inetd or mgetty, + * this will setup the variable so InitConfig() will work. + * The /etc/passwd must point to the correct homedirectory. + */ + pw = getpwuid(getuid()); + if (getenv("MBSE_ROOT") == NULL) { + envptr = xstrcpy((char *)"MBSE_ROOT="); + envptr = xstrcat(envptr, pw->pw_dir); + putenv(envptr); + } + + if (argc < 2) { + usage(); + if (envptr) + free(envptr); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(101); + } + + InitConfig(); + InitNode(); + InitFidonet(); + TermInit(1); + time(&t_start); + time(&c_start); + time(&c_end); + + InitClient(pw->pw_name, (char *)"mbcico", CFG.location, CFG.logfile, CFG.cico_loglevel, CFG.error_log); + Syslog(' ', " "); + Syslog(' ', "MBCICO v%s", VERSION); + + /* + * Catch all signals we can, and handle the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGINT) || (i == SIGBUS) || + (i == SIGFPE) || (i == SIGSEGV)) { + signal(i, (void (*))die); + } else + signal(i, SIG_DFL); + } + + /* + * Check if history file exists, if not create a new one. + */ + cmd = calloc(128, sizeof(char)); + sprintf(cmd, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fp = fopen(cmd, "r")) == NULL) { + if ((fp = fopen(cmd, "a")) == NULL) { + WriteError("$Can't create %s", cmd); + } else { + memset(&history, 0, sizeof(history)); + history.online = time(NULL); + history.offline = time(NULL); + fwrite(&history, sizeof(history), 1, fp); + fclose(fp); + Syslog('+', "Created new %s", cmd); + } + } else { + fclose(fp); + } + free(cmd); + memset(&history, 0, sizeof(history)); + + cmd = xstrcpy((char *)"Cmd: mbcico"); + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + } + Syslog(' ', cmd); + free(cmd); + + setmyname(argv[0]); + + while ((c=getopt(argc,argv,"r:n:l:t:a:I:h")) != -1) + switch (c) { + case 'r': master = atoi(optarg); + if ((master != 0) && (master != 1)) { + usage(); + die(101); + } + break; + + case 'l': forcedline = optarg; + break; + + case 't': p = xstrcpy(optarg); + if (strncmp(p, "ifc", 3) == 0) + tcp_mode = TCPMODE_IFC; + else if (strncmp(p, "itn", 3) == 0) + tcp_mode = TCPMODE_ITN; + else if (strncmp(p, "ibn", 3) == 0) + tcp_mode = TCPMODE_IBN; + else { + usage(); + die(101); + } + free(p); + break; + + case 'a': inetaddr = optarg; + break; + + case 'n': forcedphone = optarg; + break; + + default: usage(); + die(101); + } + + /* + * Load rest of the configuration + */ + inbound = xstrcpy(CFG.inbound); + uxoutbound = xstrcpy(CFG.uxpath); + name = xstrcpy(CFG.bbs_name); + phone = xstrcpy(CFG.Phone); + flags = xstrcpy(CFG.Flags); + + tmpl = &callist; + + while (argv[optind]) { + for (p = argv[optind]; (*p) && (*p == '*'); p++); + + if (strncasecmp(p, "EMSI_NAKEEC3", 12) == 0) { + + Syslog('+', "Detected IEMSI client, starting BBS"); + sprintf(temp, "%s/bin/mbsebbs", getenv("MBSE_ROOT")); + socket_shutdown(mypid); + + if (execl(temp, "mbsebbs", (char *)NULL) == -1) + perror("FATAL: Error loading BBS!"); + + /* + * If this happens, nothing is logged! + */ + printf("\n\nFATAL: Loading of the BBS failed!\n\n"); + sleep(3); + free_mem(); + if (envptr) + free(envptr); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(100); + } + + if ((strcasecmp(argv[optind],"tsync") == 0) || + (strcasecmp(argv[optind],"yoohoo") == 0) || + (strcasecmp(argv[optind],"ibn") == 0) || + (strncasecmp(p,"EMSI_",5) == 0)) { + master = 0; + answermode = argv[optind]; + Syslog('S', "Inbound \"%s\" mode", MBSE_SS(answermode)); + } else { + Syslog('-', "Callist entry \"%s\"", argv[optind]); + if ((tmp = parsefaddr(argv[optind]))) { + *tmpl = (fa_list *)malloc(sizeof(fa_list)); + (*tmpl)->next = NULL; + (*tmpl)->addr = tmp; + tmpl = &((*tmpl)->next); + immediatecall = TRUE; + } else + WriteError("Unrecognizable address \"%s\"", argv[optind]); + } + optind++; + } + + if (callist) { + master = 1; + forcedcalls = 1; + } + + /* + The following witchkraft about uid-s is necessary to make + access() work right. Unforunately, access() checks the real + uid, if mbcico is invoked with supervisor real uid (as when + called by uugetty) it returns X_OK for the magic files that + even do not have `x' bit set. Therefore, `reference' magic + file requests are taken for `execute' requests (and the + actual execution natually fails). Here we set real uid equal + to effective. If real uid is not zero, all these fails, but + in this case it is not necessary anyway. + */ + + uid=geteuid(); + seteuid(0); + setuid(uid); + seteuid(uid); + + umask(066); /* packets may contain confidential information */ + + p = xstrcpy(inbound); + p = xstrcat(p,(char *)"/tmp/fooinb"); + mkdirs(p); + free(p); + + maxrc=0; + if (master) { + /* + * Don't do outbound calls if low diskspace + */ + if (!diskfree(CFG.freespace)) + die(101); + + if (callist == NULL) + callist = callall(); + + for (tmpl = &callist; *tmpl; tmpl = &((*tmpl)->next)) { + callno++; + forcedcalls = (*tmpl)->force; + rc = call((*tmpl)->addr); + Syslog('+', "Call to %s %s (rc=%d)", ascfnode((*tmpl)->addr,0x1f), rc?"failed":"successful",rc); + if (rc > maxrc) + maxrc=rc; + if (rc == 0) { + succno++; + break; + } + } + if (callist == NULL) + if (IsSema((char *)"scanout")) + RemoveSema((char *)"scanout"); + } else { + /* slave */ + if (!answermode && tcp_mode == TCPMODE_IBN) + answermode = xstrcpy((char *)"ibn"); + maxrc = answer(answermode); + callno = 1; + succno = (maxrc == 0); + } + + if (callno) + Syslog('+', "%d of %d calls, maxrc=%d",succno,callno,maxrc); + + tidy_falist(&callist); + + if (maxrc) + die(maxrc+100); + else + die(0); + return 0; +} + + diff --git a/mbcico/mbcico.h b/mbcico/mbcico.h new file mode 100644 index 00000000..caaaaf8a --- /dev/null +++ b/mbcico/mbcico.h @@ -0,0 +1,9 @@ +#ifndef _MBCICO_H +#define _MBCICO_H + +void usage(void); +void free_mem(void); +void die(int); + +#endif + diff --git a/mbcico/mbout.c b/mbcico/mbout.c new file mode 100644 index 00000000..fd3ffcdb --- /dev/null +++ b/mbcico/mbout.c @@ -0,0 +1,344 @@ +/***************************************************************************** + * + * File ..................: mbcico/mbout.c + * Purpose ...............: MBSE BBS Outbound Manager + * Last modification date : 31-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "outstat.h" +#include "nlinfo.h" + + +extern int do_quiet; /* Supress screen output */ +int do_attach = FALSE; /* Send file attaches */ +int do_node = FALSE; /* Query the nodelist */ +int do_poll = FALSE; /* Poll a node */ +int do_req = FALSE; /* Request files from a node */ +int do_stat = FALSE; /* Show outbound status */ +int do_stop = FALSE; /* Stop polling a node */ +int e_pid = 0; /* Pid of child */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ + + + +void ProgName(void); +void ProgName() +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBOUT: MBSE BBS %s Outbound Manager\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int); +void die(int onsig) +{ + /* + * First check if a child is running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeded", e_pid); + else + WriteError("$Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode... + */ + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (show_log) + do_quiet = FALSE; + + if (!do_quiet) + colour(3, 0); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBOUT finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +void Help(void); +void Help() +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbout [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" a att Attach a file to a node\n"); + printf(" n node Show nodelist information\n"); + printf(" p poll [node..node] Poll node(s) (always crash)\n"); + printf(" r req [file..file] Request file(s) from node\n"); + printf(" sta stat Show outbound status\n"); + printf(" sto stop [node..node] Stop polling node(s)\n"); + printf("\n"); + printf(" Should be in domain form, e.g. f16.n2801.z2.domain\n"); + printf(" Flavor's are: crash | immediate | normal | hold\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -quiet Quiet mode\n"); + colour(7, 0); + die(0); +} + + + +void Fatal(char *); +void Fatal(char *msg) +{ + show_log = TRUE; + if (!do_quiet) { + colour(12, 0); + printf("%s\n", msg); + } + WriteError(msg); + die(100); +} + + + +int main(int argc, char *argv[]) +{ + char *cmd, flavor = 'x'; + int i, j, rc = 0; + struct passwd *pw; + faddr *addr = NULL; + node *nlent; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + InitNode(); + InitFidonet(); + TermInit(1); + time(&t_start); + umask(002); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM) || + (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line: mbout"); + + if (argc > 1) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[1]); + + if (!strncasecmp(argv[1], "a", 1)) + do_attach = TRUE; + if (!strncasecmp(argv[1], "n", 1)) + do_node = TRUE; + if (!strncasecmp(argv[1], "p", 1)) + do_poll = TRUE; + if (!strncasecmp(argv[1], "r", 1)) + do_req = TRUE; + if (!strncasecmp(argv[1], "sta", 3)) + do_stat = TRUE; + if (!strncasecmp(argv[1], "sto", 3)) + do_stop = TRUE; + } + + for (i = 2; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + + if (!strncasecmp(argv[i], "-q", 2)) + do_quiet = TRUE; + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbout", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + Syslog(' ', " "); + Syslog(' ', "MBOUT v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + colour(3, 0); + printf("\n"); + } + + if (do_stat) { + rc = outstat(); + if (rc) + rc += 100; + die(rc); + } + + /* + * Get node number from commandline + */ + if (do_attach || do_node || do_poll || do_stop || do_req) { + if (argc < 3) + Fatal((char *)"Not enough parameters"); + } + + if (do_attach || do_node || do_req) { + if ((addr = parsefaddr(argv[2])) == NULL) + Fatal((char *)"Unrecognizable address"); + } + + if (do_node) { + rc = nlinfo(addr); + tidy_faddr(addr); + if (rc) + rc += 100; + die(rc); + } + + if (do_poll || do_stop) { + for (i = 3; i <= argc; i++) { + if (strncasecmp(argv[i-1], "-q", 2)) { + if ((addr = parsefaddr(argv[i-1])) == NULL) + Fatal((char *)"Unrecognizable address"); + j = poll(addr, do_stop); + tidy_faddr(addr); + if (j > rc) + rc = j; + } + } + if (rc) + rc = 100; + die(rc); + } + + if (do_attach) { + if (argc < 5) + Fatal((char *)"Not enough parameters"); + flavor = tolower(argv[3][0]); + switch (flavor) { + case 'n' : flavor = 'f'; break; + case 'i' : flavor = 'i'; break; + case 'c' : flavor = 'c'; break; + case 'h' : flavor = 'h'; break; + default : Fatal((char *)"Invalid flavor, must be: immediate, crash, normal or hold"); + } + + nlent = getnlent(addr); + if (nlent->pflag == NL_DUMMY) + Fatal((char *)"Node is not in nodelist"); + if (nlent->pflag == NL_DOWN) + Fatal((char *)"Node has status Down"); + if (nlent->pflag == NL_HOLD) + Fatal((char *)"Node has status Hold"); + if (((nlent->oflags & OL_CM) == 0) && (flavor == 'c')) + Fatal((char *)"Node is not CM, must use Immediate, Normal or Hold flavor"); + + if (argv[4][0] == '-') + Fatal((char *)"Invalid filename given"); + if (file_exist(argv[4], R_OK) != 0) + Fatal((char *)"File doesn't exist"); + + if (attach(*addr, argv[4], LEAVE, flavor)) { + Syslog('+', "File attach %s is successfull", argv[4]); + if (!do_quiet) + printf("File attach %s is successfull", argv[4]); + CreateSema((char *)"scanout"); + die(0); + } else { + Fatal((char *)"File attach failed"); + } + } + + if (do_req) { + if (argc < 4) + Fatal((char *)"Not enough parameters"); + for (i = 4; i <= argc; i++) { + if (strncasecmp(argv[i-1], "-q", 2)) { + rc = freq(addr, argv[i-1]); + if (rc) + break; + } + } + if (rc) + rc += 100; + die(rc); + } + + Help(); +#ifdef MEMWATCH + mwTerm(); +#endif + return 0; +} + + diff --git a/mbcico/nlinfo.c b/mbcico/nlinfo.c new file mode 100644 index 00000000..cc882a8e --- /dev/null +++ b/mbcico/nlinfo.c @@ -0,0 +1,129 @@ +/***************************************************************************** + * + * File ..................: mbcico/nlinfo.c + * Purpose ...............: MBSE BBS Outbound Manager + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "nlinfo.h" + + + +int nlinfo(faddr *addr) +{ + node *nlent; + int i; + char flagbuf[256]; + + if (addr == NULL) + return 0; + + Syslog('s', "Search nodelist info for %s", ascfnode(addr, 0x1f)); + nlent = getnlent(addr); + + if (nlent->pflag != NL_DUMMY) { + colour(3, 0); + printf("System : %s\n", nlent->name); + printf("Sysop : %s@%s\n", nlent->sysop, ascinode(addr, 0x3f)); + printf("Location : %s\n", nlent->location); + if (nlent->phone) + printf("Phone : %s\n", nlent->phone); + else + printf("Phone : -Unpublished-\n"); + printf("Speed : %d\n", nlent->speed); + + flagbuf[0] = 0; + + /* + * Get all normal nodelist flags + */ + for (i = 0; fkey[i].flag != 0; i++) + if ((nlent->mflags & fkey[i].flag) == fkey[i].flag) + sprintf(flagbuf + strlen(flagbuf), "%s,", fkey[i].key); + for (i = 0; dkey[i].flag != 0; i++) + if ((nlent->dflags & dkey[i].flag) == dkey[i].flag) + sprintf(flagbuf + strlen(flagbuf), "%s,", dkey[i].key); + for (i = 0; ikey[i].flag != 0; i++) + if ((nlent->iflags & ikey[i].flag) == ikey[i].flag) + sprintf(flagbuf + strlen(flagbuf), "%s,", ikey[i].key); + + + switch (nlent->xflags) { + case RQ_XA: sprintf(flagbuf + strlen(flagbuf), "XA"); break; + case RQ_XB: sprintf(flagbuf + strlen(flagbuf), "XB"); break; + case RQ_XC: sprintf(flagbuf + strlen(flagbuf), "XC"); break; + case RQ_XP: sprintf(flagbuf + strlen(flagbuf), "XP"); break; + case RQ_XR: sprintf(flagbuf + strlen(flagbuf), "XR"); break; + case RQ_XW: sprintf(flagbuf + strlen(flagbuf), "XW"); break; + case RQ_XX: sprintf(flagbuf + strlen(flagbuf), "XX"); break; + } + + printf("Flags : %s\n", flagbuf); + + /* + * Show User flags + */ + flagbuf[0] = 0; + for (i = 0; nlent->uflags[i]; i++) { + sprintf(flagbuf + strlen(flagbuf), "%s,", nlent->uflags[i]); + } + if (strlen(flagbuf)) { + flagbuf[strlen(flagbuf) - 1] = 0; + printf("U-Flags : %s\n", flagbuf); + } + + /* + * Show P flags + */ + printf("P Flag :"); + if (nlent->pflag & 0x01) + printf(" Down"); + if (nlent->pflag & 0x02) + printf(" Hold"); + if (nlent->pflag & 0x04) + printf(" Pvt"); + if (nlent->pflag & 0x10) + printf(" ISDN"); + if (nlent->pflag & 0x20) + printf(" TCP/IP"); + printf("\n"); + printf("Uplink : %u/%u\n", nlent->upnet, nlent->upnode); + printf("Region : %u\n", nlent->region); + } + + if (nlent->addr.domain) + free(nlent->addr.domain); + + return 0; +} + + + diff --git a/mbcico/nlinfo.h b/mbcico/nlinfo.h new file mode 100644 index 00000000..9b08810f --- /dev/null +++ b/mbcico/nlinfo.h @@ -0,0 +1,9 @@ +#ifndef _NLINFO_H +#define _NLINFO_H + + +int nlinfo(faddr *); + + +#endif + diff --git a/mbcico/openfile.c b/mbcico/openfile.c new file mode 100644 index 00000000..b82c4c5d --- /dev/null +++ b/mbcico/openfile.c @@ -0,0 +1,282 @@ +/***************************************************************************** + * + * File ..................: mbcico/openfile.c + * Purpose ...............: Fidonet mailer + * Last modification date : 12-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "config.h" +#include "lutil.h" +#include "openfile.h" + + +static FILE *infp=NULL; +static char *infpath=NULL; +static time_t intime; +static int isfreq; +char *freqname=NULL; +int gotfiles = FALSE; + + +/* + * Try to find present (probably incomplete) file with the same timestamp + * (it might be renamed), open it for append and store resync offset. + * Store 0 in resync offset if the file is new. Return FILE* or NULL. + * resync() must accept offset in bytes and return 0 on success, nonzero + * otherwise (and then the file will be open for write). For Zmodem, + * resync is always possible, but for SEAlink it is not. Do not try + * any resyncs if remsize == 0. + */ +FILE *openfile(char *fname, time_t remtime, off_t remsize, off_t *resofs, int(*resync)(off_t)) +{ + char *opentype; + char *p, x; + char ctt[32]; + int rc, ncount; + struct stat st; + struct flock fl; + char tmpfname[16]; + + fl.l_type = F_WRLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + strcpy(ctt,date(remtime)); + + Syslog('S', "openfile(\"%s\",%s,%lu,...)", MBSE_SS(fname), MBSE_SS(ctt),(unsigned long)remsize); + + if ((fname == NULL) || (fname[0] == '\0')) { + sprintf(tmpfname,"%08lx.pkt",(unsigned long)sequencer()); + fname=tmpfname; + } + + if ((strlen(fname) == 12) && (strspn(fname,"0123456789abcdefABCDEF") == 8) && (strcasecmp(fname+8,".req") == 0)) { + Syslog('s', "Received wazoo freq file"); + isfreq = TRUE; + } else + isfreq = FALSE; + + /* + * First check if the file is already in the real inbound directory. + * If it's there, resoffs will be set equal to remsize to signal the + * receiving protocol to skip the file. + */ + if (infpath) + free(infpath); + infpath = xstrcpy(inbound); + infpath = xstrcat(infpath, (char *)"/"); + infpath = xstrcat(infpath, fname); + if (stat(infpath, &st) == 0) { + Syslog('S', "remtine=%ld, st_time=%ld, remsize=%ld, st_size=%ld", remtime, st.st_mtime, remsize, st.st_size); + + if ((remtime == st.st_mtime) && (remsize == st.st_size)) { + Syslog('+', "File %s is already here", fname); + *resofs = st.st_size; + free(infpath); + infpath = NULL; + return NULL; + } + } + + /* + * If the file is not already in the inbound, but there is a file + * with the same name, the new file will be renamed. + * + * If the file is 0 bytes, erase it so it can be received again. + * + * Renaming algorythm is as follows: start with the present name, + * increase the last character of the file name, jumping from + * '9' to 'a', from 'z' to 'A', from 'Z' to '0'. If _all_ these + * names are occupied, create random name. + */ + if (infpath) + free(infpath); + infpath = xstrcpy(inbound); + infpath = xstrcat(infpath, (char *)"/tmp/"); + infpath = xstrcat(infpath, fname); + + if (((rc = stat(infpath, &st)) == 0) && (st.st_size == 0)) { + Syslog('+', "Zero bytes file in the inbound, unlinking"); + unlink(infpath); + } + + p = infpath + strlen(infpath) -1; + x = *p; + ncount = 0; + while (((rc = stat(infpath, &st)) == 0) && (remtime != st.st_mtime) && (ncount++ < 62)) { + if (x == '9') + x = 'a'; + else if (x == 'z') + x = 'A'; + else if (x == 'Z') + x = '0'; + else + x++; + *p = x; + } + + if (ncount >= 62) { /* names exhausted */ + rc = 1; + p = strrchr(infpath,'/'); + *p = '\0'; + sprintf(ctt,"%08lx.doe",(unsigned long)sequencer()); + free(infpath); + infpath = xstrcpy(p); + infpath = xstrcat(infpath, ctt); + } + + *resofs = 0L; + opentype = (char *)"w"; + if ((rc == 0) && (remsize != 0)) { + Syslog('+', "Resyncing at offset %lu of \"%s\"", (unsigned long)st.st_size, infpath); + if (resync(st.st_size) == 0) { + opentype = (char *)"a"; + *resofs = st.st_size; + } + } + + Syslog('S', "try fopen(\"%s\",\"%s\")",infpath,opentype); + + /* + * If first attempt doesn't succeed, create tmp directory + * and try again. + */ + if ((infp = fopen(infpath,opentype)) == NULL) { + mkdirs(infpath); + if ((infp = fopen(infpath, opentype)) == NULL) { + WriteError("$Cannot open local file \"%s\" for \"%s\"", infpath,opentype); + free(infpath); + infpath=NULL; + return NULL; + } + } + + fl.l_pid = getpid(); + if (fcntl(fileno(infp),F_SETLK,&fl) != 0) { + Syslog('+', "$cannot lock local file \"%s\"",infpath); + fclose(infp); + infp = NULL; + free(infpath); + infpath = NULL; + return NULL; + } + intime=remtime; + + if (isfreq) { + if (freqname) + free(freqname); + freqname = xstrcpy(infpath); + } + + Syslog('S', "opened file \"%s\" for \"%s\", restart at %lu", infpath,opentype,(unsigned long)*resofs); + return infp; +} + + + +/* + * close file and if (success) { move it to the final location } + */ +int closefile(int success) +{ + char *newpath, *p, ctt[32]; + int rc=0,ncount; + char x; + struct stat st; + struct utimbuf ut; + + Syslog('S', "closefile(%d), for file \"%s\"",success, MBSE_SS(infpath)); + + if ((infp == NULL) || (infpath == NULL)) { + WriteError("Internal error: try close unopened file!"); + return 1; + } + + rc = fclose(infp); + infp = NULL; + + if (rc == 0) { + ut.actime = intime; + ut.modtime = intime; + if ((rc = utime(infpath,&ut))) + WriteError("$utime failed"); + } + + if (isfreq) { + if ((rc != 0) || (!success)) { + Syslog('+', "Removing unsuccessfuly received wazoo freq"); + unlink(freqname); + free(freqname); + freqname=NULL; + } + isfreq = FALSE; + } else if ((rc == 0) && success) { + newpath = xstrcpy(inbound); + newpath = xstrcat(newpath, strrchr(infpath,'/')); + + p = newpath + strlen(newpath) - 1; + x = *p; + ncount = 0; + while (((rc = stat(newpath, &st)) == 0) && (ncount++ < 62)) { + if (x == '9') + x = 'a'; + else if (x == 'z') + x = 'A'; + else if (x == 'Z') + x = '0'; + else + x++; + *p = x; + } + if (ncount >= 62) { /* names exhausted */ + rc = 1; + p = strrchr(newpath,'/'); + *p = '\0'; + sprintf(ctt,"%08lx.doe",(unsigned long)sequencer()); + free(newpath); + newpath = xstrcpy(p); + newpath = xstrcat(newpath, ctt); + } + + Syslog('S', "moving \"%s\" -> \"%s\"", MBSE_SS(infpath), MBSE_SS(newpath)); + rc = rename(infpath, newpath); + if (rc) + WriteError("$error renaming \"%s\" -> \"%s\"", MBSE_SS(infpath),MBSE_SS(newpath)); + else + gotfiles = TRUE; + free(newpath); + } + free(infpath); + infpath = NULL; + return rc; +} + + diff --git a/mbcico/openfile.h b/mbcico/openfile.h new file mode 100644 index 00000000..3d1ee023 --- /dev/null +++ b/mbcico/openfile.h @@ -0,0 +1,9 @@ +#ifndef _OPENFILE_H +#define _OPENFILE_H + +FILE *openfile(char *, time_t, off_t, off_t *, int(*)(off_t)); +int closefile(int); + + +#endif + diff --git a/mbcico/openport.c b/mbcico/openport.c new file mode 100644 index 00000000..7d945a89 --- /dev/null +++ b/mbcico/openport.c @@ -0,0 +1,617 @@ +/***************************************************************************** + * + * File ..................: mbcico/openport.c + * Purpose ...............: Fidonet mailer + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ulock.h" +#include "ttyio.h" +#include "openport.h" + + +static char *openedport = NULL, *pname; +static int need_detach = 1; +extern int f_flags; +static speed_t transpeed(int); +int hanged_up = 0; + + + +void linedrop(int sig) +{ + Syslog('+', "openport: Lost Carrier"); + hanged_up=1; + return; +} + + + +void sigpipe(int sig) +{ + Syslog('+', "openport: Got SIGPIPE"); + hanged_up=1; + return; +} + + + +void interrupt(int sig) +{ + Syslog('+', "openport: Got SIGINT"); + signal(SIGINT,interrupt); + return; +} + + + +int openport(char *port, int speed) +{ + int rc, rc2; + char *errtty=NULL; + int fd; + int outflags; + + Syslog('t', "Try opening port \"%s\" at %d",MBSE_SS(port),speed); + if (openedport) + free(openedport); + openedport = NULL; + if (port[0] == '/') + openedport = xstrcpy(port); + else { + openedport = xstrcpy((char *)"/dev/"); + openedport = xstrcat(openedport, port); + } + pname = strrchr(openedport, '/'); + + if ((rc = lock(pname))) { + Syslog('+', "Port %s is locked (rc = %d)", port, rc); + free(openedport); + openedport = NULL; + return rc; + } + + if (need_detach) { + fflush(stdin); + fflush(stdout); + setbuf(stdin, NULL); + setbuf(stdout, NULL); + close(0); + close(1); + + /* + * If we were manual started the error tty must be closed. + */ + if ((errtty = ttyname(2))) { + Syslog('t', "openport: stderr was on \"%s\", closing",errtty); + fflush(stderr); + close(2); + } + +// if (setpgrp() < 0) { +// WriteError("$openport: setpgrp failed"); +// ulock(pname); +// return 1; +// } + } + tty_status = 0; + hanged_up = 0; + signal(SIGHUP, linedrop); + signal(SIGPIPE, sigpipe); + signal(SIGINT, interrupt); + rc = 0; + rc2 = 0; + + Syslog('T', "Try open %s", MBSE_SS(openedport)); + if ((fd = open(openedport,O_RDONLY|O_NONBLOCK)) != 0) { + rc = 1; + Syslog('+', "$Cannot open \"%s\" as stdin",MBSE_SS(openedport)); + fd = open("/dev/null",O_RDONLY); + } + + if ((fd = open(openedport,O_WRONLY|O_NONBLOCK)) != 1) { + rc = 1; + Syslog('+', "$Cannot open \"%s\" as stdout",MBSE_SS(openedport)); + fd = open("/dev/null",O_WRONLY); + } + + clearerr(stdin); + clearerr(stdout); + if (need_detach) { +#ifdef TIOCSCTTY + if ((rc2 = ioctl(0,TIOCSCTTY,1L)) < 0) { + Syslog('t', "$TIOCSCTTY failed rc = %d", rc2); + } +#endif + if (errtty) { + rc = rc || (open(errtty,O_WRONLY) != 2); + } + need_detach=0; + } + + Syslog('T', "after open rc=%d",rc); + + if (rc) + Syslog('+', "cannot switch i/o to port \"%s\"",MBSE_SS(openedport)); + else { + if (tty_raw(speed)) { + WriteError("$cannot set raw mode for \"%s\"",MBSE_SS(openedport)); + rc=1; + } + + if (((f_flags = fcntl(0, F_GETFL, 0L)) == -1) || ((outflags = fcntl(1, F_GETFL, 0L)) == -1)) { + rc = 1; + WriteError("$GETFL error"); + f_flags = 0; + outflags = 0; + } else { + Syslog('t', "Return to blocking mode"); + f_flags &= ~O_NONBLOCK; + outflags &= ~O_NONBLOCK; + if ((fcntl(0, F_SETFL, f_flags) != 0) || (fcntl(1, F_SETFL, outflags) != 0)) { + rc = 1; + WriteError("$SETFL error"); + } + } + Syslog('T', "File flags: stdin: 0x%04x, stdout: 0x%04x", f_flags,outflags); + } + + if (rc) + closeport(); + else + SetTTY(port); + + return rc; +} + + + +/* + * Set port to local, hangup using DTR drop. + */ +void localport(void) +{ + Syslog('t', "Setting port \"%s\" local",MBSE_SS(openedport)); + signal(SIGHUP,SIG_IGN); + signal(SIGPIPE,SIG_IGN); + if (isatty(0)) + tty_local(); + return; +} + + + +void nolocalport(void) +{ + Syslog('t', "Setting port \"%s\" non-local",MBSE_SS(openedport)); + if (isatty(0)) + tty_nolocal(); + return; +} + + + +int rawport(void) +{ + tty_status = 0; + signal(SIGHUP,linedrop); + signal(SIGPIPE,sigpipe); + + if (isatty(0)) + return tty_raw(0); + else + return 0; +} + + + +int cookedport(void) +{ + signal(SIGHUP,SIG_IGN); + signal(SIGPIPE,SIG_IGN); + if (isatty(0)) + return tty_cooked(); + else + return 0; +} + + + +void closeport(void) +{ + if (openedport == NULL) + return; + + Syslog('t', "Closing port \"%s\"",MBSE_SS(openedport)); + fflush(stdin); + fflush(stdout); + tty_cooked(); + close(0); + close(1); + ulock(pname); + if (openedport) + free(openedport); + openedport = NULL; + SetTTY((char *)"-"); + return; +} + + + +void sendbrk(void) +{ + Syslog('t', "Send break"); + if (isatty(0)) +#if (defined(TIOCSBRK)) + Syslog('t', "TIOCSBRK"); + ioctl(0, TIOCSBRK, 0L); +#elif (defined(TCSBRK)) + Syslog('t', "TCSBRK"); + ioctl(0, TCSBRK, 0L); +#else /* any ideas about BSD? */ + ; +#endif +} + + +static struct termios savetios; +static struct termios tios; + + +char *bstr(speed_t); +char *bstr(speed_t sp) +{ + switch(sp & CBAUD) { + case 0: return (char *)"0"; +#if defined(B50) + case B50: return (char *)"50"; +#endif +#if defined(B75) + case B75: return (char *)"75"; +#endif +#if defined(B110) + case B110: return (char *)"110"; +#endif +#if defined(B134) + case B134: return (char *)"134"; +#endif +#if defined(B150) + case B150: return (char *)"150"; +#endif +#if defined(B200) + case B200: return (char *)"200"; +#endif +#if defined(B300) + case B300: return (char *)"300"; +#endif +#if defined(B600) + case B600: return (char *)"600"; +#endif +#if defined(B1200) + case B1200: return (char *)"1.200"; +#endif +#if defined(B1800) + case B1800: return (char *)"1.800"; +#endif +#if defined(B2400) + case B2400: return (char *)"2.400"; +#endif +#if defined(B4800) + case B4800: return (char *)"4.800"; +#endif +#if defined(B9600) + case B9600: return (char *)"9.600"; +#endif +#if defined(B19200) + case B19200: return (char *)"19.200"; +#endif +#if defined(B38400) + case B38400: return (char *)"38.400"; +#endif +#if defined(B57600) + case B57600: return (char *)"57.600"; +#endif +#if defined(B115200) + case B115200: return (char *)"115.200"; +#endif +#if defined(B230400) + case B230400: return (char *)"230.400"; +#endif +#if defined(B460800) + case B460800: return (char *)"460.800"; +#endif +#if defined(B500000) + case B500000: return (char *)"500.000"; +#endif +#if defined(B576000) + case B576000: return (char *)"576.000"; +#endif +#if defined(B921600) + case B921600: return (char *)"921.600"; +#endif +#if defined(B1000000) + case B1000000: return (char *)"1.000.000"; +#endif +#if defined(B1152000) + case B1152000: return (char *)"1.152.000"; +#endif +#if defined(B1500000) + case B1500000: return (char *)"1.500.000"; +#endif +#if defined(B2000000) + case B2000000: return (char *)"2.000.000"; +#endif +#if defined(B2500000) + case B2500000: return (char *)"2.500.000"; +#endif +#if defined(B3000000) + case B3000000: return (char *)"3.000.000"; +#endif +#if defined(B3500000) + case B3500000: return (char *)"3.500.000"; +#endif +#if defined(B4000000) + case B4000000: return (char *)"4.000.000"; +#endif + default: return (char *)"Unknown"; + } +} + + + + +int tty_raw(int speed) +{ + int rc; + speed_t tspeed, is, os; + + Syslog('t', "Set tty raw"); + tspeed = transpeed(speed); + + if ((rc = tcgetattr(0,&savetios))) { + WriteError("$tcgetattr(0,save) return %d",rc); + return rc; + } else { + Syslog('T', "savetios.c_iflag=0x%08x",savetios.c_iflag); + Syslog('T', "savetios.c_oflag=0x%08x",savetios.c_oflag); + Syslog('T', "savetios.c_cflag=0x%08x",savetios.c_cflag); + Syslog('T', "savetios.c_lflag=0x%08x",savetios.c_lflag); + Syslog('T', "savetios.c_cc=\"%s\"",printable(savetios.c_cc,NCCS)); + Syslog('T', "file flags: stdin: 0x%04x, stdout: 0x%04x", fcntl(0,F_GETFL,0L),fcntl(1,F_GETFL,0L)); + } + + tios = savetios; + tios.c_iflag = 0; + tios.c_oflag = 0; + tios.c_cflag &= ~(CSTOPB | PARENB | PARODD); + tios.c_cflag |= CS8 | CREAD | HUPCL | CLOCAL; + tios.c_lflag = 0; + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; + + if (tspeed) { + cfsetispeed(&tios,tspeed); + cfsetospeed(&tios,tspeed); + } + + if ((rc = tcsetattr(0,TCSADRAIN,&tios))) + WriteError("$tcsetattr(0,TCSADRAIN,raw) return %d",rc); + + is = cfgetispeed(&tios); + os = cfgetospeed(&tios); + + return rc; +} + + + +int tty_local(void) +{ + struct termios Tios; + tcflag_t cflag; + speed_t ispeed, ospeed; + int rc; + + if ((rc = tcgetattr(0,&Tios))) { + WriteError("$tcgetattr(0,save) return %d",rc); + return rc; + } + Syslog('-', "Dropping DTR"); + + cflag = Tios.c_cflag | CLOCAL; + + ispeed = cfgetispeed(&tios); + ospeed = cfgetospeed(&tios); + cfsetispeed(&Tios,0); + cfsetospeed(&Tios,0); + if ((rc = tcsetattr(0,TCSADRAIN,&Tios))) + WriteError("$tcsetattr(0,TCSADRAIN,hangup) return %d",rc); + + sleep(1); /* as far as I notice, DTR goes back high on next op. */ + + Tios.c_cflag = cflag; + cfsetispeed(&Tios,ispeed); + cfsetospeed(&Tios,ospeed); + if ((rc = tcsetattr(0,TCSADRAIN,&Tios))) + Syslog('t', "$tcsetattr(0,TCSADRAIN,clocal) return %d",rc); + return rc; +} + + + +int tty_nolocal(void) +{ + struct termios Tios; + int rc; + + if ((rc = tcgetattr(0,&Tios))) { + WriteError("$tcgetattr(0,save) return %d",rc); + return rc; + } + Tios.c_cflag &= ~CLOCAL; + Tios.c_cflag |= CRTSCTS; + + if ((rc = tcsetattr(0,TCSADRAIN,&Tios))) + Syslog('t', "$tcsetattr(0,TCSADRAIN,clocal) return %d",rc); + return rc; +} + + + +int tty_cooked(void) +{ + int rc; + + if ((rc = tcsetattr(0,TCSAFLUSH,&savetios))) + Syslog('t', "$tcsetattr(0,TCSAFLUSH,save) return %d",rc); + return rc; +} + + + +speed_t transpeed(int speed) +{ + speed_t tspeed; + + switch (speed) + { + case 0: tspeed=0; break; +#if defined(B50) + case 50: tspeed=B50; break; +#endif +#if defined(B75) + case 75: tspeed=B75; break; +#endif +#if defined(B110) + case 110: tspeed=B110; break; +#endif +#if defined(B134) + case 134: tspeed=B134; break; +#endif +#if defined(B150) + case 150: tspeed=B150; break; +#endif +#if defined(B200) + case 200: tspeed=B200; break; +#endif +#if defined(B300) + case 300: tspeed=B300; break; +#endif +#if defined(B600) + case 600: tspeed=B600; break; +#endif +#if defined(B1200) + case 1200: tspeed=B1200; break; +#endif +#if defined(B1800) + case 1800: tspeed=B1800; break; +#endif +#if defined(B2400) + case 2400: tspeed=B2400; break; +#endif +#if defined(B4800) + case 4800: tspeed=B4800; break; +#endif +#if defined(B7200) + case 7200: tspeed=B7200; break; +#endif +#if defined(B9600) + case 9600: tspeed=B9600; break; +#endif +#if defined(B12000) + case 12000: tspeed=B12000; break; +#endif +#if defined(B14400) + case 14400: tspeed=B14400; break; +#endif +#if defined(B19200) + case 19200: tspeed=B19200; break; +#elif defined(EXTA) + case 19200: tspeed=EXTA; break; +#endif +#if defined(B38400) + case 38400: tspeed=B38400; break; +#elif defined(EXTB) + case 38400: tspeed=EXTB; break; +#endif +#if defined(B57600) + case 57600: tspeed=B57600; break; +#endif +#if defined(B115200) + case 115200: tspeed=B115200; break; +#endif +#if defined(B230400) + case 230400: tspeed=B230400; break; +#endif +#if defined(B460800) + case 460800: tspeed=B460800; break; +#endif +#if defined(B500000) + case 500000: tspeed=B500000; break; +#endif +#if defined(B576000) + case 576000: tspeed=B576000; break; +#endif +#if defined(B921600) + case 921600: tspeed=B921600; break; +#endif +#if defined(B1000000) + case 1000000: tspeed=B1000000; break; +#endif +#if defined(B1152000) + case 1152000: tspeed=B1152000; break; +#endif +#if defined(B1500000) + case 1500000: tspeed=B1500000; break; +#endif +#if defined(B2000000) + case 2000000: tspeed=B2000000; break; +#endif +#if defined(B2500000) + case 2500000: tspeed=B2500000; break; +#endif +#if defined(B3000000) + case 3000000: tspeed=B3000000; break; +#endif +#if defined(B3500000) + case 3500000: tspeed=B3500000; break; +#endif +#if defined(B4000000) + case 4000000: tspeed=B4000000; break; +#endif + default: WriteError("requested invalid speed %d",speed); + tspeed=0; break; + } + + return tspeed; +} + + diff --git a/mbcico/openport.h b/mbcico/openport.h new file mode 100644 index 00000000..50a71a70 --- /dev/null +++ b/mbcico/openport.h @@ -0,0 +1,25 @@ +#ifndef _OPENPORT_H +#define _OPENPORT_H + + +void linedrop(int); +void interrupt(int); +#ifdef TIOCWONLINE +void alarmsig(int); +#endif +int openport(char *, int); +void localport(void); +void nolocalport(void); +int rawport(void); +int cookedport(void); +void closeport(void); +void sendbrk(void); + +int tty_raw(int); +int tty_local(void); +int tty_nolocal(void); +int tty_cooked(void); + + +#endif + diff --git a/mbcico/opentcp.c b/mbcico/opentcp.c new file mode 100644 index 00000000..fae29c40 --- /dev/null +++ b/mbcico/opentcp.c @@ -0,0 +1,303 @@ +/***************************************************************************** + * + * File ..................: mbcico/opentcp.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "session.h" +#include "ttyio.h" +#include "openport.h" +#include "opentcp.h" + + +#define BINKPORT 24554 +#define TELNPORT 23 +#define FIDOPORT 60179 /* Eugene G. Crossers birthday */ + + +static int fd=-1; +extern int f_flags; +extern int tcp_mode; +extern time_t c_start; +extern time_t c_end; +extern int online; +extern int master; +extern int carrier; +extern long sentbytes; +extern long rcvdbytes; +extern int Loaded; + + +char telnet_options[256]; +char do_dont_resp[256]; +char will_wont_resp[256]; + +void tel_enter_binary(int rw); +void tel_leave_binary(int rw); +void send_do(register int); +void send_dont(register int); +void send_will(register int); +void send_wont(register int); + +static int tcp_is_open = FALSE; + + +/* opentcp() was rewritten by Martin Junius */ +/* telnet mode was written by T.Tanaka */ + +int opentcp(char *name) +{ + struct servent *se; + struct hostent *he; + int a1,a2,a3,a4; + char *errmsg; + char *portname; + int Fd; + short portnum; + struct sockaddr_in server; + + Syslog('d', "Try open tcp connection to %s",MBSE_SS(name)); + + tcp_is_open = FALSE; + memset(&telnet_options, 0, sizeof(telnet_options)); + server.sin_family = AF_INET; + + if ((portname = strchr(name,':'))) { + *portname++='\0'; + if ((portnum = atoi(portname))) + server.sin_port=htons(portnum); + else if ((se = getservbyname(portname, "tcp"))) + server.sin_port = se->s_port; + else + server.sin_port = htons(FIDOPORT); + } else { + switch (tcp_mode) { + case TCPMODE_IFC: if ((se = getservbyname("fido", "tcp"))) + server.sin_port = se->s_port; + else + server.sin_port = htons(FIDOPORT); + break; + case TCPMODE_ITN: if ((se = getservbyname("tfido", "tcp"))) + server.sin_port = se->s_port; + else + server.sin_port = htons(TELNPORT); + break; + case TCPMODE_IBN: if ((se = getservbyname("binkd", "tcp"))) + server.sin_port = se->s_port; + else + server.sin_port = htons(BINKPORT); + break; + default: server.sin_port = htons(FIDOPORT); + } + } + + if (sscanf(name,"%d.%d.%d.%d",&a1,&a2,&a3,&a4) == 4) + server.sin_addr.s_addr = inet_addr(name); + else if ((he = gethostbyname(name))) + memcpy(&server.sin_addr,he->h_addr,he->h_length); + else { + switch (h_errno) { + case HOST_NOT_FOUND: errmsg=(char *)"Authoritative: Host not found"; break; + case TRY_AGAIN: errmsg=(char *)"Non-Authoritive: Host not found"; break; + case NO_RECOVERY: errmsg=(char *)"Non recoverable errors"; break; + default: errmsg=(char *)"Unknown error"; break; + } + Syslog('+', "No IP address for %s: %s\n", name, errmsg); + return -1; + } + + Syslog('d', "Trying %s at port %d", + inet_ntoa(server.sin_addr),(int)ntohs(server.sin_port)); + + signal(SIGPIPE,linedrop); + fflush(stdin); + fflush(stdout); + setbuf(stdin,NULL); + setbuf(stdout,NULL); + close(0); + close(1); + if ((Fd = socket(AF_INET,SOCK_STREAM,0)) != 0) { + WriteError("$Cannot create socket (got %d, expected 0"); + open("/dev/null",O_RDONLY); + open("/dev/null",O_WRONLY); + return -1; + } + if (dup(Fd) != 1) { + WriteError("$Cannot dup socket"); + open("/dev/null",O_WRONLY); + return -1; + } + clearerr(stdin); + clearerr(stdout); + if (connect(Fd,(struct sockaddr *)&server,sizeof(server)) == -1) { + Syslog('+', "Cannot connect %s",inet_ntoa(server.sin_addr)); + return -1; + } + + f_flags=0; + + switch (tcp_mode) { + case TCPMODE_ITN: tel_enter_binary(3); + Syslog('+', "Established ITN/TCP connection with %s", inet_ntoa(server.sin_addr)); + break; + case TCPMODE_IFC: Syslog('+', "Established IFC/TCP connection with %s", inet_ntoa(server.sin_addr)); + break; + case TCPMODE_IBN: Syslog('+', "Established IBN/TCP connection with %s", inet_ntoa(server.sin_addr)); + break; + default: WriteError("Established TCP connection with unknow protocol"); + } + c_start = time(NULL); + carrier = TRUE; + tcp_is_open = TRUE; + return 0; +} + + + +void closetcp(void) +{ + FILE *fph; + char *tmp; + + if (!tcp_is_open) + return; + + Syslog('d', "Closing TCP connection"); + + if (tcp_mode == TCPMODE_ITN) + tel_leave_binary(3); + + shutdown(fd,2); + signal(SIGPIPE,SIG_DFL); + + if (carrier) { + c_end = time(NULL); + online += (c_end - c_start); + Syslog('+', "Connection time %s", t_elapsed(c_start, c_end)); + carrier = FALSE; + history.offline = c_end; + history.online = c_start; + history.sent_bytes = sentbytes; + history.rcvd_bytes = rcvdbytes; + history.inbound = ~master; + tmp = calloc(128, sizeof(char)); + sprintf(tmp, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fph = fopen(tmp, "a")) == NULL) + WriteError("$Can't open %s", tmp); + else { + Syslog('s', "closetcp() write history"); + fwrite(&history, sizeof(history), 1, fph); + fclose(fph); + } + free(tmp); + memset(&history, 0, sizeof(history)); + if (Loaded) { + Syslog('s', "Updateing noderecord %s", aka2str(nodes.Aka[0])); + nodes.LastDate = time(NULL); + UpdateNode(); + } + } + tcp_is_open = FALSE; +} + + + +void tel_enter_binary(int rw) +{ + Syslog('d', "Telnet enter binary %d", rw); + if (rw & 1) + send_do(TELOPT_BINARY); + if (rw & 2) + send_will(TELOPT_BINARY); + + send_dont(TELOPT_ECHO); + send_do(TELOPT_SGA); + send_dont(TELOPT_RCTE); + send_dont(TELOPT_TTYPE); + + send_wont(TELOPT_ECHO); + send_will(TELOPT_SGA); + send_wont(TELOPT_RCTE); + send_wont(TELOPT_TTYPE); +} + + + +void tel_leave_binary(int rw) +{ + Syslog('d', "Telnet leave binary %d", rw); + if (rw & 1) + send_dont(TELOPT_BINARY); + if (rw & 2) + send_wont(TELOPT_BINARY); +} + + + +/* + * These routines are in charge of sending option negotiations + * to the other side. + * The basic idea is that we send the negotiation if either side + * is in disagreement as to what the current state should be. + */ + +void send_do(register int c) +{ + NET2ADD(IAC, DO); + NETADD(c); +} + + +void send_dont(register int c) +{ + NET2ADD(IAC, DONT); + NETADD(c); +} + + +void send_will(register int c) +{ + NET2ADD(IAC, WILL); + NETADD(c); +} + + +void send_wont(register int c) +{ + NET2ADD(IAC, WONT); + NETADD(c); +} + + + diff --git a/mbcico/opentcp.h b/mbcico/opentcp.h new file mode 100644 index 00000000..431c8311 --- /dev/null +++ b/mbcico/opentcp.h @@ -0,0 +1,81 @@ +#ifndef _OPENTCP_H +#define _OPENTCP_H + +int opentcp(char *); +void closetcp(void); + +#define PUTCHAR(x) tty_putc(x) + +#define ClearArray(x) memset((char *)x, 0, sizeof x) + +#define NETADD(c) { PUTCHAR(c); } +#define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } + +#define MY_STATE_WILL 0x01 +#define MY_WANT_STATE_WILL 0x02 +#define MY_STATE_DO 0x04 +#define MY_WANT_STATE_DO 0x08 +#define my_state_is_do(opt) (telnet_options[opt]&MY_STATE_DO) +#define my_state_is_will(opt) (telnet_options[opt]&MY_STATE_WILL) +#define my_want_state_is_do(opt) (telnet_options[opt]&MY_WANT_STATE_DO) +#define my_want_state_is_will(opt) (telnet_options[opt]&MY_WANT_STATE_WILL) +#define my_state_is_dont(opt) (!my_state_is_do(opt)) +#define my_state_is_wont(opt) (!my_state_is_will(opt)) +#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt)) +#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt)) +#define set_my_want_state_do(opt) {telnet_options[opt] |= MY_WANT_STATE_DO;} +#define set_my_want_state_will(opt) {telnet_options[opt] |= MY_WANT_STATE_WILL;} +#define set_my_want_state_dont(opt) {telnet_options[opt] &= ~MY_WANT_STATE_DO;} +#define set_my_want_state_wont(opt) {telnet_options[opt] &= ~MY_WANT_STATE_WILL;} + +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_XDISPLOC 35 /* X Display Location */ +#define TELOPT_ENVIRON 36 /* Environment variables */ +#define TELOPT_AUTHENTICATION 37/* Authenticate */ +#define TELOPT_ENCRYPT 38 /* Encryption option */ +#define TELOPT_EXOPL 255 /* extended-options-list */ + + +#endif + diff --git a/mbcico/outstat.c b/mbcico/outstat.c new file mode 100644 index 00000000..50c6507e --- /dev/null +++ b/mbcico/outstat.c @@ -0,0 +1,354 @@ +/***************************************************************************** + * + * File ..................: mbcico/outstat.c + * Purpose ...............: Show mail outbound status + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "scanout.h" +#include "callstat.h" +#include "outstat.h" + + +extern int do_quiet; + + +static struct _alist +{ + struct _alist *next; + faddr addr; + int flavors; + time_t time; + off_t size; +} *alist = NULL; + + +#define F_NORMAL 1 +#define F_CRASH 2 +#define F_IMM 4 +#define F_HOLD 8 +#define F_FREQ 16 +#define F_POLL 32 + + + +int outstat() +{ + int rc; + struct _alist *tmp, *old; + char flstr[6]; + time_t age; + char temp[81]; + + if ((rc = scanout(each))) { + WriteError("Error scanning outbound, aborting"); + return rc; + } + + if (!do_quiet) { + colour(10, 0); + printf("flavor size age address\n"); + colour(3, 0); + } + + Syslog('+', "Flavor Size Age Address"); + for (tmp = alist; tmp; tmp = tmp->next) { + if ((tmp->flavors & F_FREQ) || (tmp->size) || 1) { + strcpy(flstr,"......"); + if ((tmp->flavors) & F_IMM ) flstr[0]='I'; + if ((tmp->flavors) & F_CRASH ) flstr[1]='C'; + if ((tmp->flavors) & F_NORMAL) flstr[2]='N'; + if ((tmp->flavors) & F_HOLD ) flstr[3]='H'; + if ((tmp->flavors) & F_FREQ ) flstr[4]='R'; + if ((tmp->flavors) & F_POLL ) flstr[5]='P'; + + (void)time(&age); + age -= tmp->time; + sprintf(temp, "%s %8lu %s %s", flstr, (long)tmp->size, str_time(age), ascfnode(&(tmp->addr), 0x1f)); + + if (!do_quiet) + printf("%s\n", temp); + Syslog('+', "%s", temp); + } + } + + for (tmp = alist; tmp; tmp = old) { + old = tmp->next; + free(tmp->addr.domain); + free(tmp); + } + alist = NULL; + + return 0; +} + + + +int each(faddr *addr, char flavor, int isflo, char *fname) +{ + struct _alist **tmp; + struct stat st; + FILE *fp; + char buf[256], *p; + + if ((isflo != OUT_PKT) && (isflo != OUT_FLO) && (isflo != OUT_REQ) && (isflo != OUT_POL)) + return 0; + + for (tmp = &alist; *tmp; tmp = &((*tmp)->next)) + if (((*tmp)->addr.zone == addr->zone) && ((*tmp)->addr.net == addr->net) && + ((*tmp)->addr.node == addr->node) && ((*tmp)->addr.point == addr->point) && + (((*tmp)->addr.domain == NULL) || (addr->domain == NULL) || + (strcasecmp((*tmp)->addr.domain,addr->domain) == 0))) + break; + if (*tmp == NULL) { + *tmp = (struct _alist *)malloc(sizeof(struct _alist)); + (*tmp)->next = NULL; + (*tmp)->addr.name = NULL; + (*tmp)->addr.zone = addr->zone; + (*tmp)->addr.net = addr->net; + (*tmp)->addr.node = addr->node; + (*tmp)->addr.point = addr->point; + (*tmp)->addr.domain = xstrcpy(addr->domain); + (*tmp)->flavors = 0; + time(&((*tmp)->time)); + (*tmp)->size = 0L; + } + + if ((isflo == OUT_FLO) || (isflo == OUT_PKT)) + switch (flavor) { + case '?': break; + case 'i': (*tmp)->flavors |= F_IMM; break; + case 'o': (*tmp)->flavors |= F_NORMAL; break; + case 'c': (*tmp)->flavors |= F_CRASH; break; + case 'h': (*tmp)->flavors |= F_HOLD; break; + default: WriteError("Unknown flavor: '%c'\n",flavor); break; + } + + if (stat(fname,&st) != 0) { + WriteError("$Can't stat %s", fname); + st.st_size = 0L; + (void)time(&st.st_mtime); + } + + /* + * Find the oldest time + */ + if (st.st_mtime < (*tmp)->time) + (*tmp)->time = st.st_mtime; + + if (isflo == OUT_FLO) { + if ((fp = fopen(fname,"r"))) { + while (fgets(buf, sizeof(buf) - 1, fp)) { + if (*(p = buf + strlen(buf) - 1) == '\n') + *p-- = '\0'; + while (isspace(*p)) + *p-- = '\0'; + for (p = buf; *p; p++) + if (*p == '\\') + *p='/'; + for (p = buf; *p && isspace(*p); p++); + if (*p == '~') continue; + if ((*p == '#') || (*p == '-') || (*p == '^') || (*p == '@')) + p++; + if (stat(p, &st) != 0) { + if (strlen(CFG.dospath)) { + if (stat(Dos2Unix(p), &st) != 0) { + /* + * Fileattach dissapeared, maybe + * the node doesn't poll enough and + * is losing mail or files. + */ + st.st_size = 0L; + (void)time(&st.st_mtime); + } + } else { + if (stat(p, &st) != 0) { + st.st_size = 0L; + (void)time(&st.st_mtime); + } + } + } + + if ((p = strrchr(fname,'/'))) + p++; + else + p = fname; + if ((strlen(p) == 12) && (strspn(p,"0123456789abcdefABCDEF") == 8) && (p[8] == '.')) { + if (st.st_mtime < (*tmp)->time) + (*tmp)->time = st.st_mtime; + } + (*tmp)->size += st.st_size; + } + fclose(fp); + } else + WriteError("Can't open %s", fname); + + } else if (isflo == OUT_PKT) { + (*tmp)->size += st.st_size; + } else if (isflo == OUT_REQ) { + (*tmp)->flavors |= F_FREQ; + } else if (isflo == OUT_POL) { + (*tmp)->flavors |= F_POLL; + } + + return 0; +} + + + +int IsZMH(void); +int IsZMH() +{ + static char buf[81]; + + sprintf(buf, "SBBS:0;"); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:2,2", 7) == 0) + return TRUE; + } + return FALSE; +} + + + +int poll(faddr *addr, int stop) +{ + char *pol; + int rc = 0; + FILE *fp; + callstat *cst; + node *nlent; + + if (addr == NULL) + return 0; + + pol = polname(addr); + + if (stop) { + if (access(pol, R_OK) == 0) { + rc = unlink(pol); + if (rc == 0) { + Syslog('+', "Removed poll for %s", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Removed poll for %s\n", ascfnode(addr, 0x1f)); + } + } else { + Syslog('+', "No poll found for %s", ascfnode(addr, 0x1f)); + } + } else { + nlent = getnlent(addr); + if (nlent->pflag == NL_DUMMY) { + Syslog('+', "Node %s not in nodelist", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Node %s not in nodelist", ascfnode(addr, 0x1f)); + return 1; + } + if (nlent->pflag == NL_DOWN) { + Syslog('+', "Node %s has status Down", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Node %s has status Down", ascfnode(addr, 0x1f)); + return 1; + } + if (nlent->pflag == NL_HOLD) { + Syslog('+', "Node %s has status Hold", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Node %s has status Hold", ascfnode(addr, 0x1f)); + return 1; + } + + if ((fp = fopen(pol, "w+")) == NULL) { + WriteError("$Can't create poll for %s", ascfnode(addr, 0x1f)); + rc = 1; + } else { + fclose(fp); + if (((nlent->oflags & OL_CM) == 0) && (!IsZMH())) { + Syslog('+', "Created poll for %s, non-CM node outside ZMH", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Created poll for %s, non-CM node outside ZMH\n", ascfnode(addr, 0x1f)); + } else { + Syslog('+', "Created poll for %s", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Created poll for %s\n", ascfnode(addr, 0x1f)); + } + cst = getstatus(addr); + if ((cst->trystat == 5) || + (cst->trystat == ST_NOTZMH) || + (cst->trystat == ST_NOCONN) || + (cst->trystat == ST_NOCALL7) || + (cst->trystat == ST_NOCALL8) || + (cst->trystat > 10)) { + putstatus(addr, 0, 0); + } + CreateSema((char *)"scanout"); + } + } + + return 0; +} + + + +int freq(faddr *addr, char *fname) +{ + char *req; + FILE *fp; + + Syslog('o', "Freq %s %s", ascfnode(addr, 0x1f), fname); + + /* + * Append filename to .req file + */ + req = xstrcpy(reqname(addr)); + if ((fp = fopen(req, "a")) == NULL) { + WriteError("$Can't append to %s", req); + if (!do_quiet) + printf("File request failed\n"); + free(req); + return 1; + } + fprintf(fp, "%s\r\n", fname); + fclose(fp); + + Syslog('+', "File request \"%s\" from %s", fname, ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("File request \"%s\" from %s\n", fname, ascfnode(addr, 0x1f)); + + free(req); + return 0; +} + + + diff --git a/mbcico/outstat.h b/mbcico/outstat.h new file mode 100644 index 00000000..d6b600cd --- /dev/null +++ b/mbcico/outstat.h @@ -0,0 +1,12 @@ +#ifndef _OUTSTAT_H +#define _OUTSTAT_H + + +int each(faddr *, char, int, char *); +int outstat(void); +int poll(faddr *, int); +int freq(faddr *, char *); + + +#endif + diff --git a/mbcico/portsel.c b/mbcico/portsel.c new file mode 100644 index 00000000..c24bb3b1 --- /dev/null +++ b/mbcico/portsel.c @@ -0,0 +1,254 @@ +/***************************************************************************** + * + * File ..................: mbcico/portsel.c + * Purpose ...............: Fidonet mailer + * Last modification date : 06-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "portsel.h" + + +extern char *name, *phone, *flags; + + +/* + * Tidy the portlist array + */ +void tidy_pplist(pp_list ** fdp) +{ + pp_list *tmp, *old; + int i; + + Syslog('D', "tidy_pplist"); + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + for (i = 0; i < MAXUFLAGS; i++) + if (tmp->uflags[i]) + free(tmp->uflags[i]); + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a port to the array + */ +void fill_pplist(pp_list **fdp, pp_list *new) +{ + pp_list *tmp, *ta; + int i; + + tmp = (pp_list *)malloc(sizeof(pp_list)); + tmp->next = NULL; + sprintf(tmp->tty, "%s", new->tty); + tmp->mflags = new->mflags; + tmp->dflags = new->dflags; + tmp->iflags = new->iflags; + moflags(new->mflags); + diflags(new->dflags); + ipflags(new->iflags); + tmp->match = TRUE; + for (i = 0; i < MAXUFLAGS; i++) + tmp->uflags[i] = xstrcpy(new->uflags[i]); + + if (*fdp == NULL) + *fdp = tmp; + else { + for (ta = *fdp; ta; ta = ta->next) + if (ta->next == NULL) { + ta->next = (pp_list *)tmp; + break; + } + } +} + + + +/* + * Make a list of available ports to use for dialout. The ports + * are selected on the available modem flags and the remote node + * modem type. + */ +int make_portlist(node *nlent, pp_list **tmp) +{ + char *temp, *p, *q; + FILE *fp; + int count = 0, j, ixflag, stdflag; + pp_list new; + + tidy_pplist(tmp); + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return 0; + } + + Syslog('d', "Building portlist..."); + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fp); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fp) == 1) { + + if (((ttyinfo.type == POTS) || (ttyinfo.type == ISDN)) && (ttyinfo.available) && (ttyinfo.callout)) { + memset(&new, 0, sizeof(new)); + sprintf(new.tty, "%s", ttyinfo.tty); + stdflag = TRUE; + ixflag = 0; + q = xstrcpy(ttyinfo.flags); + for (p = q; p; p = q) { + if ((q = strchr(p, ','))) + *q++ = '\0'; + if ((strncasecmp(p, "U", 1) == 0) && (strlen(p) == 1)) { + stdflag = FALSE; + } else { + for (j = 0; fkey[j].key; j++) + if (strcasecmp(p, fkey[j].key) == 0) + new.mflags |= fkey[j].flag; + for (j = 0; dkey[j].key; j++) + if (strcasecmp(p, dkey[j].key) == 0) + new.dflags |= dkey[j].flag; + if (!stdflag) { + if (ixflag < MAXUFLAGS) { + new.uflags[ixflag++] = p; + } + } + } + } + Syslog('d', "flags: nodelist port %s", new.tty); + Syslog('d', "modem %08lx %08lx", nlent->mflags, new.mflags); + Syslog('d', "ISDN %08lx %08lx", nlent->dflags, new.dflags); + + if ((nlent->mflags & new.mflags) || (nlent->dflags & new.dflags)) { + fill_pplist(tmp, &new); + count++; + Syslog('d', "make_portlist add %s", ttyinfo.tty); + } + } + } + + fclose(fp); + free(temp); + + /* FIXME: sort ports on priority and remove ports with low speed. */ + + Syslog('d', "make_portlist %d ports", count); + return count; +} + + + +int load_port(char *tty) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return FALSE; + } + + free(temp); + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fp); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fp) == 1) { + if ((strcmp(ttyinfo.tty, tty) == 0) && (ttyinfo.available)) { + fclose(fp); + + /* + * Override EMSI parameters. + */ + if (strlen(ttyinfo.phone)) { + free(phone); + phone = xstrcpy(ttyinfo.phone); + } + if (strlen(ttyinfo.flags)) { + free(flags); + flags = xstrcpy(ttyinfo.flags); + } + if (strlen(ttyinfo.name)) { + free(name); + name = xstrcpy(ttyinfo.name); + } + + if ((ttyinfo.type == POTS) || (ttyinfo.type == ISDN)) + return load_modem(ttyinfo.modem); + else + return TRUE; + } + } + + fclose(fp); + memset(&ttyinfo, 0, sizeof(ttyinfo)); + return FALSE; +} + + + +int load_modem(char *ModemName) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/modem.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return FALSE; + } + + free(temp); + fread(&modemhdr, sizeof(modemhdr), 1, fp); + + while (fread(&modem, modemhdr.recsize, 1, fp) == 1) { + if ((strcmp(modem.modem, ModemName) == 0) && (modem.available)) { + fclose(fp); + return TRUE; + } + } + + fclose(fp); + memset(&modem, 0, sizeof(modem)); + return FALSE; +} + + diff --git a/mbcico/portsel.h b/mbcico/portsel.h new file mode 100644 index 00000000..22b60c25 --- /dev/null +++ b/mbcico/portsel.h @@ -0,0 +1,24 @@ +#ifndef _PORTSEL_H +#define _PORTSEL_H + + +typedef struct _pp_list { + struct _pp_list *next; + char tty[7]; /* tty name of the port */ + unsigned long mflags; /* Analogue Modem flags */ + unsigned long dflags; /* ISDN flags */ + unsigned long iflags; /* TCP-IP flags */ + char *uflags[MAXUFLAGS]; /* User flags */ + int match; /* Does port match */ +} pp_list; + + +void tidy_pplist(pp_list **); +void fill_pplist(pp_list **, pp_list *); +int make_portlist(node *, pp_list **); +int load_port(char *); +int load_modem(char *); + + +#endif + diff --git a/mbcico/rdoptions.c b/mbcico/rdoptions.c new file mode 100644 index 00000000..65ea7f56 --- /dev/null +++ b/mbcico/rdoptions.c @@ -0,0 +1,138 @@ +/***************************************************************************** + * + * File ..................: mbcico/rdoptions.c + * Purpose ...............: Fidonet mailer + * Last modification date : 13-Jul-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "portsel.h" +#include "session.h" +#include "config.h" + +int localoptions; + + +static struct _ktab { + char *key; + int flag; +} ktab[] = { + {(char *)"Call", NOCALL}, + {(char *)"Hold", NOHOLD}, + {(char *)"PUA", NOPUA}, + {(char *)"WaZOO", NOWAZOO}, + {(char *)"EMSI", NOEMSI}, + {(char *)"Freqs", NOFREQS}, + {(char *)"Zmodem", NOZMODEM}, + {(char *)"ZedZap", NOZEDZAP}, + {(char *)"Hydra", NOHYDRA}, + {(char *)"Tcp", NOTCP}, + {NULL, 0} +}; + + + +void logoptions(void) +{ + int i; + char *s = NULL; + + for (i=0;ktab[i].key;i++) { + s=xstrcat(s,(char *)" "); + if (localoptions & ktab[i].flag) + s=xstrcat(s,(char *)"No"); + s=xstrcat(s,ktab[i].key); + } + + Syslog('+', "Options:%s",s); + free(s); +} + + + +void rdoptions(int Loaded) +{ + localoptions=0; + if (CFG.NoFreqs) + localoptions |= NOFREQS; + if (CFG.NoCall) + localoptions |= NOCALL; + if (CFG.NoHold) + localoptions |= NOHOLD; + if (CFG.NoPUA) + localoptions |= NOPUA; + if (CFG.NoEMSI) + localoptions |= NOEMSI; + if (CFG.NoWazoo) + localoptions |= NOWAZOO; + if (CFG.NoZmodem) + localoptions |= NOZMODEM; + if (CFG.NoZedzap) + localoptions |= NOZEDZAP; + if (CFG.NoHydra) + localoptions |= NOHYDRA; + if (CFG.NoTCP) + localoptions |= NOTCP; + + if (nodes.Aka[0].zone == 0) { + if (Loaded) + Syslog('s', "Node not in setup, using default options"); + logoptions(); + return; + } + + Syslog('s', "rdoptions node %s %s", nodes.Sysop, aka2str(nodes.Aka[0])); + + if (nodes.NoEMSI) + localoptions |= NOEMSI; + if (nodes.NoWaZOO) + localoptions |= NOWAZOO; + if (nodes.NoFreqs) + localoptions |= NOFREQS; + if (nodes.NoCall) + localoptions |= NOCALL; + if (nodes.NoHold) + localoptions |= NOHOLD; + if (nodes.NoPUA) + localoptions |= NOPUA; + if (nodes.NoZmodem) + localoptions |= NOZMODEM; + if (nodes.NoZedzap) + localoptions |= NOZEDZAP; + if (nodes.NoHydra) + localoptions |= NOHYDRA; + if (nodes.NoTCP) + localoptions |= NOTCP; + + logoptions(); +} + diff --git a/mbcico/rdoptions.h b/mbcico/rdoptions.h new file mode 100644 index 00000000..759d625e --- /dev/null +++ b/mbcico/rdoptions.h @@ -0,0 +1,7 @@ +#ifndef _RDOPTIONS_H +#define _RDOPTIONS_H + +void rdoptions(int); + +#endif + diff --git a/mbcico/recvbark.c b/mbcico/recvbark.c new file mode 100644 index 00000000..dcafdf9d --- /dev/null +++ b/mbcico/recvbark.c @@ -0,0 +1,230 @@ +/***************************************************************************** + * + * File ..................: mbcico/recvbark.c + * Purpose ...............: Fidonet mailer + * Last modification date : 01-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "recvbark.h" +#include "respfreq.h" +#include "filelist.h" + + +static int recv_bark(void); +extern int xmsndfiles(file_list*); + + +int recvbark(void) +{ + if ((session_flags & SESSION_BARK) && !(localoptions & NOFREQS)) { + return recv_bark(); + } else { /* deny requests */ + PUTCHAR(CAN); + return STATUS; + } +} + + + +SM_DECL(recv_bark,(char *)"recvbark") +SM_STATES + sendenq, + waitack, + waitchar, + scanreq, + sendack, + waitnak, + sendfiles +SM_NAMES + (char *)"sendenq", + (char *)"waitack", + (char *)"waitchar", + (char *)"scanreq", + (char *)"sendack", + (char *)"waitnak", + (char *)"sendfiles" +SM_EDECL + + int c, c1, c2; + short lcrc, rcrc; + char buf[256], *p = NULL; + int count = 0,rc = 0; + file_list *tosend = NULL; + +SM_START(sendenq) + +SM_STATE(sendenq) + + Syslog('s', "recvbark SENDINQ"); + + count = 0; + PUTCHAR(ENQ); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + +SM_STATE(waitack) + + Syslog('s', "recvbark WAITACK"); + + if (count++ > 10) { + Syslog('+', "Wait for Bark Request: timeout"); + PUTCHAR(ETB); + SM_SUCCESS; /* Yes, this is allright. */ + } + + c = GETCHAR(2); + if (c == TIMEOUT) { + Syslog('s', " timeout, send ENQ"); + PUTCHAR(ENQ); + SM_PROCEED(waitack); + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case ACK: p = buf; + SM_PROCEED(waitchar); + break; + case ETB: SM_SUCCESS; + break; + case ENQ: PUTCHAR(ETB); + SM_PROCEED(sendenq); + break; + case EOT: PUTCHAR(ACK); + SM_PROCEED(waitack); + break; + default: Syslog('s', "Recvbark got '%s' waiting for ACK", printablec(c)); + SM_PROCEED(waitack); + break; + } + +SM_STATE(waitchar) + + Syslog('s', "recvbark WAITCHAR"); + c=GETCHAR(15); + if (c == TIMEOUT) { + Syslog('s', "Recvbark got timeout waiting for char"); + SM_PROCEED(sendenq); + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case ACK: SM_PROCEED(waitchar); + break; + case ETX: *p = '\0'; + SM_PROCEED(scanreq); + break; + case SUB: SM_PROCEED(sendenq); + break; + default: if ((p - buf) < sizeof(buf)) + *p++= c; + SM_PROCEED(waitchar); + break; + } + +SM_STATE(scanreq) + + Syslog('s', "recvbark SCANREQ"); + lcrc = crc16xmodem(buf, strlen(buf)); + c1 = GETCHAR(15); + if (c1 == TIMEOUT) { + SM_PROCEED(sendenq); + } else if (c1 < 0) { + SM_ERROR; + } + c2 = GETCHAR(15); + if (c2 == TIMEOUT) { + SM_PROCEED(sendenq); + } else if (c2 < 0) { + SM_ERROR; + } + rcrc = (c2 << 8) + (c1 & 0xff); + if (lcrc != rcrc) { + Syslog('s', "lcrc 0x%04x != rcrc 0x%04x", lcrc, rcrc); + PUTCHAR(NAK); + SM_PROCEED(sendenq); + } + SM_PROCEED(sendack); + +SM_STATE(sendack) + + Syslog('s', "recvbark SENDACK"); + count = 0; + PUTCHAR(ACK); + tosend = respond_bark(buf); + SM_PROCEED(waitnak); + +SM_STATE(waitnak) + + Syslog('s', "recvbark WAITNAK count=%d, count"); + + if (count++ > 5) { + SM_ERROR; + } + c = GETCHAR(3); + if (c == TIMEOUT) { + Syslog('s', " timeout"); + PUTCHAR(ACK); + SM_PROCEED(waitnak); + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case NAK: session_flags &= ~FTSC_XMODEM_CRC; /* fallthrough */ + case 'C': session_flags |= FTSC_XMODEM_CRC; + SM_PROCEED(sendfiles); + break; + case ENQ: PUTCHAR(ETB); + SM_PROCEED(waitack); + break; + case SUB: SM_PROCEED(sendenq); + break; + default: Syslog('s', "Recvbark got '%s' waiting for NAK", printablec(c)); + SM_PROCEED(waitack); + break; + } + +SM_STATE(sendfiles) + + Syslog('s', "recvbark SENDFILES"); + rc = xmsndfiles(tosend); + tidy_filelist(tosend, 0); + if (rc == 0) { + SM_PROCEED(sendenq); + } else { + SM_ERROR; + } + +SM_END +SM_RETURN + diff --git a/mbcico/recvbark.h b/mbcico/recvbark.h new file mode 100644 index 00000000..31b0512f --- /dev/null +++ b/mbcico/recvbark.h @@ -0,0 +1,7 @@ +#ifndef _RECVBARK_H +#define _RECVBARK_H + +int recvbark(void); + +#endif + diff --git a/mbcico/respfreq.c b/mbcico/respfreq.c new file mode 100644 index 00000000..edd52a79 --- /dev/null +++ b/mbcico/respfreq.c @@ -0,0 +1,663 @@ +/***************************************************************************** + * + * File ..................: mbcico/respfreq.c + * Purpose ...............: Fidonet mailer + * Last modification date : 07-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "lutil.h" +#include "config.h" +#include "atoul.h" +#include "respfreq.h" +#include "filelist.h" + + +#ifndef S_ISDIR +#define S_ISDIR(st_mode) (((st_mode) & S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISREG +#define S_ISREG(st_mode) (((st_mode) & S_IFMT) == S_IFREG) +#endif + + +extern char *freqname; + +static void attach_report(file_list**); +static void add_report(char *, ...); +static char *report_text = NULL; +static unsigned long report_total = 0L; +static unsigned long report_count = 0L; +static int no_more = FALSE; + + + +file_list *respond_wazoo(void) +{ + char buf[256]; + char *nm, *pw, *dt, *p; + file_list *fl=NULL, **tmpl; + FILE *fp; + + if (freqname == NULL) + return NULL; + + if ((fp=fopen(freqname,"r")) == NULL) { + WriteError("$cannot open received wazoo freq \"%s\"",freqname); + unlink(freqname); + free(freqname); + freqname=NULL; + return NULL; + } + + tmpl=&fl; + while (fgets(buf,sizeof(buf)-1,fp)) { + nm = NULL; + pw = NULL; + dt = NULL; + p = strtok(buf," \n\r"); + if ((p == NULL) || (*p == '\0')) + continue; + nm = p; + p = strtok(NULL," \n\r"); + if (p && (*p == '!')) + pw = p+1; + else + if (p && ((*p == '+') || (*p == '-'))) + dt = p; + p = strtok(NULL," \n\r"); + if (p && (*p == '!')) + pw = p+1; + else + if (p && ((*p == '+') || (*p == '-'))) + dt = p; + *tmpl = respfreq(nm, pw, dt); + while (*tmpl) tmpl=&((*tmpl)->next); + if (no_more) + break; + } + + fclose(fp); + unlink(freqname); + free(freqname); + freqname = NULL; + for (tmpl = &fl; *tmpl; tmpl = &((*tmpl)->next)) { + Syslog('F', "resplist: %s",MBSE_SS((*tmpl)->local)); + } + attach_report(&fl); + return fl; +} + + + +file_list *respond_bark(char *buf) +{ + char *nm, *pw, *dt, *p; + file_list *fl; + + nm = buf; + pw = (char *)""; + dt = (char *)"0"; + while (isspace(*nm)) + nm++; + for (p = nm; *p && (!isspace(*p)); p++); + if (*p) { + *p++ = '\0'; + dt = p; + while (isspace(*dt)) + dt++; + for (p = dt; *p && (!isspace(*p)); p++); + if (*p) { + *p++ = '\0'; + pw = p; + while (isspace(*pw)) + pw++; + for (p = pw; *p && (!isspace(*p)); p++); + *p = '\0'; + } + } + fl = respfreq(nm, pw, dt); + attach_report(&fl); + return fl; +} + + + +file_list *respfreq(char *nm, char *pw, char *dt) +{ + file_list *fl = NULL; + struct stat st; + char mask[256], *p, *q; + char *tnm, *t; + time_t upd = 0L; + int newer = 1; + FILE *fa, *fb, *fi; + long Area; + int Send; + struct FILEIndex idx; + + if (localoptions & NOFREQS) { + Syslog('+', "File requests disabled"); + add_report((char *)"ER: \"%s\" denied: file requests disabled", nm); + return NULL; + } + + if (strchr(nm, '/') || strchr(nm, '\\') || strchr(nm, ':')) { + Syslog('+', "Illegal characters in request"); + add_report((char *)"ER: \"%s\" denied: illegal characters", nm); + return NULL; + } + + if (dt) { + if (*dt == '+') { + newer = 1; + dt++; + } else if (*dt == '-') { + newer = 0; + dt++; + } else + newer = 1; + upd=atoul(dt); + } + + if (strlen(CFG.req_magic)) { + /* + * Check for uppercase and lowercase magic names. + */ + tnm = xstrcpy(CFG.req_magic); + tnm = xstrcat(tnm,(char *)"/"); + tnm = xstrcat(tnm,tl(xstrcpy(nm))); + if ((stat(tnm, &st) == 0) && + (S_ISREG(st.st_mode))) { + if (access(tnm, X_OK) == 0) { + return respmagic(tnm); + /* respmagic will free(tnm) */ + } else if (access(tnm, R_OK) == 0) { + return resplist(tnm, pw, dt); + /* resplist will free(tnm) */ + } else + free(tnm); + } else + free(tnm); + + tnm = xstrcpy(CFG.req_magic); + tnm = xstrcat(tnm,(char *)"/"); + t = xstrcpy(nm); + tnm = xstrcat(tnm,tu(t)); + free(t); + if ((stat(tnm, &st) == 0) && + (S_ISREG(st.st_mode))) { + if (access(tnm, X_OK) == 0) { + return respmagic(tnm); + /* respmagic will free(tnm) */ + } else if (access(tnm, R_OK) == 0) { + return resplist(tnm, pw, dt); + /* resplist will free(tnm) */ + } else + free(tnm); + } else free(tnm); + } + + Syslog('+', "File request : %s (update (%s), password \"%s\")",MBSE_SS(nm),MBSE_SS(dt),MBSE_SS(pw)); + add_report((char *)"RQ: Regular file \"%s\"",nm); + p = tl(nm); + q = mask; + *q++ = '^'; + while ((*p) && (q < (mask + sizeof(mask) - 4))) { + switch (*p) { + case '\\': *q++ = '\\'; *q++ = '\\'; break; + case '?': *q++ = '.'; break; + case '.': *q++ = '\\'; *q++ = '.'; break; + case '+': *q++ = '\\'; *q++ = '+'; break; + case '*': *q++ = '.'; *q++ = '*'; break; + default: *q++ = toupper(*p); break; + } + p++; + } + *q++ = '$'; + *q = '\0'; + Syslog('f', "Search mask \"%s\"", mask); + re_comp(mask); + + /* + * Open the areas database and request index. + */ + p = xstrcpy(getenv("MBSE_ROOT")); + p = xstrcat(p, (char *)"/etc/fareas.data"); + if ((fa = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + return NULL; + } + free(p); + fread(&areahdr, sizeof(areahdr), 1, fa); + + p = xstrcpy(getenv("MBSE_ROOT")); + p = xstrcat(p, (char *)"/etc/request.index"); + if ((fi = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + return NULL; + } + Area = 0L; + free(p); + + while (!no_more && (fread(&idx, sizeof(idx), 1, fi) == 1)) { + if (re_exec(idx.Name) || re_exec(idx.LName)) { + Syslog('f', "Index found %s area %d record %d", idx.LName, idx.AreaNum, idx.Record); + if (fseek(fa, ((idx.AreaNum - 1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET) == -1) { + WriteError("$Can't seek in fareas.data"); + return NULL; + } + if (fread(&area, areahdr.recsize, 1, fa) != 1) { + WriteError("$Can't read record %d in fareas.data", idx.AreaNum); + return NULL; + } + Syslog('f', "Area %s", area.Name); + p = calloc(128, sizeof(char)); + sprintf(p, "%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), idx.AreaNum); + if ((fb = fopen(p, "r+")) == NULL) { + WriteError("$Can't open %s", p); + free(p); + } else { + free(p); + if (fseek(fb, idx.Record * sizeof(file), SEEK_SET) == -1) { + WriteError("$Can't seek filerecord %d", idx.Record); + } else { + if (fread(&file, sizeof(file), 1, fb) != 1) { + WriteError("$Can't read filerecord %d", idx.Record); + } else { + Send = FALSE; + Syslog('f', "Found \"%s\" in %s", file.Name, area.Name); + tnm = xstrcpy(area.Path); + tnm = xstrcat(tnm, (char *)"/"); + tnm = xstrcat(tnm, file.Name); + if ((stat(tnm, &st) == 0) && + (S_ISREG(st.st_mode)) && + (access(tnm, R_OK) == 0) && + ((upd == 0L) || + ((newer) && (st.st_mtime <= upd)))) { + Send = TRUE; + } + + /* + * If no password is given, we do not respond + * on requests to password protected areas + * or files in case it was a wildcard request. + * Wrong passwords are honored with an error + * response. + */ + if (Send && strlen(area.Password)) { + if (pw != NULL) { + if (strcasecmp(area.Password, pw)) { + Send = FALSE; + Syslog('+', "Bad password for area %s", area.Name); + add_report((char *)"ER: bad password for area %s", area.Name); + } + } else { + Send = FALSE; + } + } + + if (Send && strlen(file.Password)) { + if (pw != NULL) { + if (strcasecmp(file.Password, pw)) { + Send = FALSE; + Syslog('+', "Bad password for file %s", file.Name); + add_report((char *)"ER: bad password for file %s", file.Name); + } + } else { + Send = FALSE; + } + } + + if (Send && CFG.Req_Files) { + if (report_count >= CFG.Req_Files) { + Send = FALSE; + add_report((char *)"ER: too many files requested"); + Syslog('+', "Exceeding maximum files limit"); + no_more = TRUE; + } + } + + if (Send && CFG.Req_MBytes) { + if ((st.st_size + report_total) > (CFG.Req_MBytes * 1048576)) { + Send = FALSE; + add_report((char *)"ER: file %s will exceed the request limit", file.Name); + Syslog('+', "Exceeding request size limit"); + no_more = TRUE; + } + } + + if (Send) { + Syslog('f', "Will send %s", file.LName); + report_total += st.st_size; + report_count++; + add_report((char *)"OK: Sending \"%s\" (%lu bytes)", file.Name, file.Size); + add_list(&fl, tnm, file.Name, 0, 0L, NULL, 1); + /* + * Update file information + */ + file.TimesReq++; + file.LastDL = time(NULL); + fseek(fb, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, fb); + } + free(tnm); + } + } + fclose(fb); + } + } + } + + fclose(fa); + fclose(fi); + + if (fl == NULL) + add_report((char *)"ER: No matching files found"); + + return fl; +} + + + +#define MAXRECURSE 5 +static int recurse=0; + +/* + * Magic filerquests. + */ +file_list *resplist(char *listfn, char *pw, char *dt) +{ + FILE *fp; + char buf[256], *p; + file_list *fl = NULL, **pfl; + + Syslog('+', "Magic request: %s (update (%s), password \"%s\")", + strrchr(xstrcpy(listfn), '/')+1, MBSE_SS(dt), MBSE_SS(pw)); + + if (++recurse > MAXRECURSE) { + WriteError("Excessive recursion in file lists for \"%s\"", MBSE_SS(listfn)); + add_report((char *)"ER: Exessive recursion for magic filename \"%s\", contact sysop", listfn); + recurse = 0; + free(listfn); + return NULL; + } + + pfl = &fl; + if ((fp = fopen(listfn,"r")) == NULL) { + WriteError("$cannot open file list \"%s\"",listfn); + add_report((char *)"ER: Could not open magic file \"%s\", contact sysop", listfn); + free(listfn); + recurse--; + return NULL; + } + + p = xstrcpy(listfn); + add_report((char *)"RQ: Magic filename \"%s\"", strrchr(p, '/')+1); + free(p); + + while (fgets(buf, sizeof(buf)-1, fp)) { + if ((p = strchr(buf, '#'))) + *p = '\0'; + if ((p = strtok(buf," \t\n\r"))) { + *pfl = respfreq(p, pw, dt); + while (*pfl) + pfl = &((*pfl)->next); + } + } + fclose(fp); + + free(listfn); + recurse--; + return fl; +} + + + +file_list *respmagic(char *cmd) /* must free(cmd) before exit */ +{ + struct stat st; + char cmdbuf[256]; + char tmpfn[PATH_MAX], tmptx[PATH_MAX]; + char remname[32], *p, *q, *z, *buf; + int i, escaped; + file_list *fl = NULL; + FILE *fp, *ft; + long zeroes = 0L; + ftnmsg fmsg; + char *svname; + + Syslog('+', "Magic execute: %s", strrchr(xstrcpy(cmd), '/')+1); + add_report((char *)"RQ: Magic \"%s\"",cmd); + sprintf(tmpfn, "%s/tmp/%08lX", getenv((char *)"MBSE_ROOT"), (unsigned long)sequencer()); + Syslog('+', "tmpfn \"%s\"", tmpfn); + if ((p = strrchr(cmd,'/'))) + p++; + else + p = cmd; + strncpy(remname, p, sizeof(remname)-1); + remname[sizeof(remname)-1] = '\0'; + if (remote->addr->name == NULL) + remote->addr->name = xstrcpy((char *)"Sysop"); + strncpy(cmdbuf, cmd, sizeof(cmdbuf)-2); + cmdbuf[sizeof(cmdbuf)-2] = '\0'; + q = cmdbuf + strlen(cmdbuf); + z = cmdbuf + sizeof(cmdbuf)-2; + *q++ = ' '; + escaped = 0; + for (p = ascfnode(remote->addr,0x7f); *p && (q < z); p++) { + if (escaped) { + escaped = 0; + } else switch (*p) { + case '\\': escaped = 1; break; + case '\'': + case '`': + case '"': + case '(': + case ')': + case '<': + case '>': + case '|': + case ';': + case '$': *q++ = '\\'; break; + } + *q++ = *p; + } + *q++ = '\0'; + + /* + * Execute the shell, output goes into tmpfn + */ + if (execsh(cmdbuf,(char *)"/dev/null",tmpfn,(char *)"/dev/null")) { + WriteError("$Execute magic error"); + add_report((char *)"ER: Magic command execution failed"); + unlink(tmpfn); + } else { + if (stat(tmpfn, &st) == 0) { + sprintf(tmptx, "%s/tmp/%08lX", getenv((char *)"MBSE_ROOT"), (unsigned long)sequencer()); + Syslog('+', "tmptx \"%s\"", tmptx); + + if ((fp = fopen(tmptx, "w"))) { + fmsg.flags = M_PVT|M_KILLSENT; + fmsg.from = bestaka_s(remote->addr); + svname = fmsg.from->name; + fmsg.from->name = (char *)"mbcico FREQ processor"; + fmsg.to = remote->addr; + fmsg.date = time((time_t*)NULL); + fmsg.subj = strrchr(xstrcpy(cmd), '/')+1; + fmsg.msgid_s = NULL; + fmsg.msgid_a = xstrcpy(ascfnode(fmsg.from, 0x1f)); + fmsg.msgid_n = sequencer(); + fmsg.reply_s = NULL; + fmsg.reply_a = NULL; + fmsg.reply_n = 0L; + fmsg.origin = NULL; + fmsg.area = NULL; + (void)ftnmsghdr(&fmsg, fp, NULL, 'f', (char *)"MBSE-CICO"); + free(fmsg.msgid_a); + + if ((ft = fopen(tmpfn, "r")) == NULL) { + WriteError("$Can't open %s", tmpfn); + } else { + buf = calloc(2049, sizeof(char)); + while ((fgets(buf, 2048, ft)) != NULL) { + for (i = 0; i < strlen(buf); i++) { + if (*(buf + i) == '\0') + break; + if (*(buf + i) == '\n') + *(buf + i) = '\r'; + } + fputs(buf, fp); + } + fprintf(fp, "\r--- mbcico v%s\r", VERSION); + free(buf); + } + fwrite(&zeroes, 1, 3, fp); + fclose(fp); + sprintf(remname, "%08lX.PKT", (unsigned long)sequencer()); + + add_list(&fl, tmptx, remname, KFS, 0L, NULL, 0); + fmsg.from->name = svname; + add_report((char *)"OK: magic output is send by mail"); + unlink(tmpfn); + } else { + WriteError("$cannot open temp file \"%s\"",MBSE_SS(tmpfn)); + } + } else { + WriteError("$cannot stat() magic stdout \"%s\"",tmpfn); + add_report((char *)"ER: Could not get magic command output, contact sysop"); + } + } + + free(cmd); + return fl; +} + + + +static void attach_report(file_list **fl) +{ + FILE *fp; + char tmpfn[L_tmpnam]; + char remname[14]; + long zeroes = 0L; + ftnmsg fmsg; + char *svname; + + if (report_text == NULL) { + WriteError("Empty FREQ report"); + add_report((char *)"ER: empty request report, contact sysop"); + } + + add_report((char *)"\rTotal to send: %lu files, %lu bytes", report_count, report_total); + + if (!CFG.Req_Files) + add_report((char *)"Maximum files: unlimited"); + else + add_report((char *)"Maximum files: %d", CFG.Req_Files); + if (!CFG.Req_MBytes) + add_report((char *)"Maximum size : unlimited"); + else + add_report((char *)"Maximum size : %d MBytes", CFG.Req_MBytes); + + add_report((char *)"\r--- mbcico v%s\r", VERSION); + + (void)tmpnam(tmpfn); + + if ((fp = fopen(tmpfn,"w"))) { + fmsg.flags = M_PVT|M_KILLSENT; + fmsg.from = bestaka_s(remote->addr); + svname = fmsg.from->name; + fmsg.from->name = (char *)"mbcico FREQ processor"; + fmsg.to = remote->addr; + /* + * If we don't know the sysops name, fake it. + */ + if (fmsg.to->name == NULL) + fmsg.to->name = xstrcpy((char *)"Sysop"); + fmsg.date = time((time_t*)NULL); + fmsg.subj = (char *)"File request status report"; + fmsg.msgid_s = NULL; + fmsg.msgid_a = xstrcpy(ascfnode(fmsg.from, 0x1f)); + fmsg.msgid_n = sequencer(); + fmsg.reply_s = NULL; + fmsg.reply_a = NULL; + fmsg.reply_n = 0L; + fmsg.origin = NULL; + fmsg.area = NULL; + (void)ftnmsghdr(&fmsg, fp, NULL, 'f', (char *)"MBSE-CICO"); + free(fmsg.msgid_a); + fwrite(report_text, 1, strlen(report_text), fp); + fwrite(&zeroes, 1, 3, fp); + fclose(fp); + sprintf(remname, "%08lX.PKT", (unsigned long)sequencer()); + add_list(fl, tmpfn, remname, KFS, 0L, NULL, 0); + fmsg.from->name = svname; + } else { + WriteError("$cannot open temp file \"%s\"",MBSE_SS(tmpfn)); + } + + report_total = 0L; + free(report_text); + report_text = NULL; +} + + + +static void add_report(char *format, ...) +{ + va_list va_ptr; + char buf[1024]; + + if (report_text == NULL) { + sprintf(buf, +" Status of file request\r\ + ======================\r\r\ + Received By: %s\r\ +", + ascfnode(bestaka_s(remote->addr),0x1f)); + sprintf(buf+strlen(buf), +" From: %s\r\ + On: %s\r\r\ +", + ascfnode(remote->addr,0x1f), + date(0L)); + report_text = xstrcat(report_text,buf); + } + + va_start(va_ptr, format); + vsprintf(buf, format, va_ptr); + va_end(va_ptr); + strcat(buf,"\r"); + report_text = xstrcat(report_text,buf); +} + diff --git a/mbcico/respfreq.h b/mbcico/respfreq.h new file mode 100644 index 00000000..77d4e73b --- /dev/null +++ b/mbcico/respfreq.h @@ -0,0 +1,11 @@ +#ifndef _RESPFREQ_H +#define _RESPFREQ_H + +file_list *respond_wazoo(void); +file_list *respond_bark(char *); +file_list *respfreq(char *, char *, char *); +file_list *resplist(char *, char *, char *); +file_list *respmagic(char *); + +#endif + diff --git a/mbcico/scanout.c b/mbcico/scanout.c new file mode 100644 index 00000000..46829ce6 --- /dev/null +++ b/mbcico/scanout.c @@ -0,0 +1,244 @@ +/***************************************************************************** + * + * File ..................: mbcico/scanout.c + * Purpose ...............: Fidonet mailer + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbftn.h" +#include "config.h" +#include "scanout.h" +#include "lutil.h" + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + + +static faddr addr = { + NULL, + 0,0,0,0, + NULL +}; + + +extern time_t t_start; + + +static int scan_dir(int (*)(faddr*,char,int,char*),char*,int); +static int scan_dir(int (*fn)(faddr *, char, int, char *), char *dname, int ispoint) +{ + char fname[PATH_MAX]; + char flavor = '?'; + DIR *dp = NULL; + struct dirent *de; + int rc = 0, isflo, fage; + + Syslog('o' ,"scan_dir \"%s\" (%s)",MBSE_SS(dname),ispoint?"point":"node"); + + if ((dp = opendir(dname)) == NULL) { + Syslog('-', "Creating directory %s", dname); + /* + * Create a fake filename, mkdirs() likes that. + */ + sprintf(fname, "%s/foo", dname); + (void)mkdirs(fname); + if ((dp = opendir(dname)) == NULL) { + Syslog('o' ,"\"%s\" cannot be opened, proceed",MBSE_SS(dname)); + return 0; + } + } + + while ((de=readdir(dp))) + if ((strlen(de->d_name) == 12) && (de->d_name[8] == '.') && + (strspn(de->d_name,"0123456789abcdefABCDEF") == 8)) { + Syslog('o' ,"checking: \"%s\"",de->d_name); + addr.point= 0; + strncpy(fname,dname,PATH_MAX-2); + strcat(fname,"/"); + strncat(fname,de->d_name,PATH_MAX-strlen(fname)-2); + + if ((strcasecmp(de->d_name+9,"pnt") == 0) && !ispoint) { + sscanf(de->d_name,"%04x%04x",&addr.net,&addr.node); + if ((rc = scan_dir(fn, fname, 1))) + goto exout; + } else if ((strcasecmp(de->d_name+8,".out") == 0) || + (strcasecmp(de->d_name+8,".cut") == 0) || + (strcasecmp(de->d_name+8,".hut") == 0) || + (strcasecmp(de->d_name+8,".iut") == 0) || + (strcasecmp(de->d_name+8,".opk") == 0) || + (strcasecmp(de->d_name+8,".cpk") == 0) || + (strcasecmp(de->d_name+8,".hpk") == 0) || + (strcasecmp(de->d_name+8,".ipk") == 0) || + (strcasecmp(de->d_name+8,".flo") == 0) || + (strcasecmp(de->d_name+8,".clo") == 0) || + (strcasecmp(de->d_name+8,".hlo") == 0) || + (strcasecmp(de->d_name+8,".ilo") == 0) || + (strcasecmp(de->d_name+8,".req") == 0) || + (strcasecmp(de->d_name+8,".pol") == 0)) { + if (ispoint) + sscanf(de->d_name,"%08x", &addr.point); + else + sscanf(de->d_name,"%04x%04x", &addr.net,&addr.node); + flavor = tolower(de->d_name[9]); + if (flavor == 'f') + flavor='o'; + if (strcasecmp(de->d_name+10,"ut") == 0) + isflo=OUT_PKT; + else if (strcasecmp(de->d_name+10,"pk") == 0) + isflo=OUT_DIR; + else if (strcasecmp(de->d_name+10,"lo") == 0) + isflo=OUT_FLO; + else if (strcasecmp(de->d_name+9,"req") == 0) + isflo=OUT_REQ; + else if (strcasecmp(de->d_name+9,"pol") == 0) + isflo=OUT_POL; + else + isflo=-1; + Syslog('o' ,"%s \"%s\"", + (isflo == OUT_FLO) ? "flo file" : "packet", + de->d_name); + if ((rc=fn(&addr,flavor,isflo,fname))) + goto exout; + } else if ((strncasecmp(de->d_name+9,"su",2) == 0) || + (strncasecmp(de->d_name+9,"mo",2) == 0) || + (strncasecmp(de->d_name+9,"tu",2) == 0) || + (strncasecmp(de->d_name+9,"we",2) == 0) || + (strncasecmp(de->d_name+9,"th",2) == 0) || + (strncasecmp(de->d_name+9,"fr",2) == 0) || + (strncasecmp(de->d_name+9,"sa",2) == 0)) { + isflo = OUT_ARC; + if ((rc = fn(&addr, flavor, isflo, fname))) + goto exout; + + Syslog('o' ,"arcmail file \"%s\"",de->d_name); + sprintf(fname, "%s/%s", dname, de->d_name); + fage = (int)((t_start - file_time(fname)) / 86400); + + if (file_size(fname) == 0) { + Syslog('o', "Age %d days", fage); + /* + * Remove truncated ARCmail that has a day extension + * other then the current day or if the file is older + * then 6 days. + */ + if ((strncasecmp(de->d_name+9, dayname(), 2)) || (fage > 6)) { + if (unlink(fname) == 0) + Syslog('-', "Removed truncated ARCmail file %s", fname); + } + } + + if (CFG.toss_days && (fage > CFG.toss_days)) { + /* + * Remove ARCmail that is on hold too long. + */ + if (unlink(fname) == 0) + Syslog('+', "Removed ARCmail %s, %d days", fname, fage); + } + } else { + Syslog('o' ,"skipping \"%s\"",de->d_name); + } + } + +exout: + closedir(dp); + return rc; +} + + + +int scanout(int (*fn)(faddr *, char, int, char *)) +{ + int i, j, rc = 0; + unsigned short zone = 0; + char fext[5]; + char *p = NULL, *q = NULL; + DIR *dp; + + if ((dp = opendir(CFG.outbound)) == NULL) { + WriteError("$Can't open outbound directory \"%s\" for reading", MBSE_SS(CFG.outbound)); + return 1; + } + closedir(dp); + + /* + * Build outbound directory names with zone numbers. + */ + for (i = 0; i < 40; i++) { + if ((CFG.aka[i].zone) && (CFG.aka[i].zone != zone)) { + zone = CFG.aka[i].zone; + if (SearchFidonet(zone)) { + for (j = 0; j < 6; j++) { + /* + * Create outbound directory name for + * the primary aka of that zone. + */ + p = xstrcpy(CFG.outbound); + if (zone != CFG.aka[0].zone) { + if ((q = strrchr(p, '/'))) + *q = '\0'; + p = xstrcat(p, (char *)"/"); + p = xstrcat(p, fidonet.domain); + } + + /* + * Not primary zones in the domain get + * a directory extension. + */ + if (fidonet.zone[j]) { + if (j) { + sprintf(fext, ".%03x", fidonet.zone[j]); + p = xstrcat(p, fext); + } + Syslog('o', "Zone %d Dir %s", fidonet.zone[j], p); + addr.zone = fidonet.zone[j]; + addr.domain = fidonet.domain; + + if ((rc = scan_dir(fn, p, 0))) { + if (p) + free(p); + p = NULL; + return rc; + } + } + + if (p) + free(p); + p = NULL; + } + } + } + } + return rc; +} + + diff --git a/mbcico/scanout.h b/mbcico/scanout.h new file mode 100644 index 00000000..b5dcdfc2 --- /dev/null +++ b/mbcico/scanout.h @@ -0,0 +1,13 @@ +#ifndef SCANOUT_H +#define SCANOUT_H + +#define OUT_PKT 0 +#define OUT_DIR 1 +#define OUT_FLO 2 +#define OUT_ARC 3 +#define OUT_REQ 4 +#define OUT_POL 5 + +extern int scanout(int (*)(faddr*,char,int,char*)); + +#endif diff --git a/mbcico/sendbark.c b/mbcico/sendbark.c new file mode 100644 index 00000000..f1a4c03e --- /dev/null +++ b/mbcico/sendbark.c @@ -0,0 +1,186 @@ +/***************************************************************************** + * + * File ..................: mbcico/sendbark.c + * Purpose ...............: Fidonet mailer + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "sendbark.h" +#include "xmrecv.h" + + + +static int send_bark(void); +static char *nm,*pw,*dt; + + +int sendbark(void) +{ + char *fn; + FILE *fp; + char buf[256], *p; + int rc = 0; + + fn = reqname(remote->addr); + if ((fp = fopen(fn,"r")) == NULL) { + Syslog('s', "no request file for this node"); + PUTCHAR(ETB); + return 0; + } + + while (fgets(buf,sizeof(buf)-1,fp)) { + nm = buf; + pw = strchr(buf, '!'); + dt = strchr(buf, '+'); + + if (pw) + *pw++= '\0'; + if (dt) + *dt++= '\0'; + + if (nm) { + while (isspace(*nm)) + nm++; + for (p = nm; (*p != '!') && (*p != '+') && (!isspace(*p)); p++); + *p = '\0'; + } + + if (pw) { + while (isspace(*pw)) + pw++; + for (p = pw; (*p != '!') && (*p != '+') && (!isspace(*p)); p++); + *p = '\0'; + } else + pw = (char *)""; + + if (dt) { + while (isspace(*nm)) + nm++; + for (p = nm; (*p != '!') && (*p != '+') && (*p != '-') && (!isspace(*p)); p++); + *p = '\0'; + } else + dt = (char *)"0"; + + if (*nm == ';') + continue; + + Syslog('+', "Sending bark request for \"%s\", password \"%s\", update \"%s\"",MBSE_SS(nm),MBSE_SS(pw),MBSE_SS(dt)); + if ((rc = send_bark())) + break; + } + if (rc == 0) + PUTCHAR(ETB); + fclose(fp); + if (rc == 0) + unlink(fn); + + return rc; +} + + + +SM_DECL(send_bark,(char *)"sendbark") +SM_STATES + Send, + waitack, + getfile +SM_NAMES + (char *)"send", + (char *)"waitack", + (char *)"getfile" +SM_EDECL + + int c; + char buf[256]; + unsigned short crc; + int count = 0; + + Syslog('s', "send_bark INIT"); + sprintf(buf,"%s %s %s",nm,dt,pw); + crc = crc16xmodem(buf, strlen(buf)); + Syslog('s', "sending bark packet \"%s\", crc = 0x%04x", buf, crc); + +SM_START(Send) + +SM_STATE(Send) + + Syslog('s', "send_bark SEND"); + if (count++ > 5) { + Syslog('+', "Bark request failed"); + SM_ERROR; + } + + PUTCHAR(ACK); + PUT(buf, strlen(buf)); + PUTCHAR(ETX); + PUTCHAR(crc & 0xff); + PUTCHAR((crc >> 8) & 0xff); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + +SM_STATE(waitack) + + Syslog('s', "send_bark WAITACK"); + c = GETCHAR(10); + if (c == TIMEOUT) { + Syslog('s', "sendbark got timeout waiting for ACK"); + SM_PROCEED(Send); + } else if (c < 0) { + SM_PROCEED(Send); + } else if (c == ACK) { + SM_PROCEED(getfile); + } else { + Syslog('s', "sendbark got %s waiting for ACK", printablec(c)); + SM_PROCEED(Send); + } + +SM_STATE(getfile) + + Syslog('s', "send_bark GETFILE"); + switch (xmrecv(NULL)) { + case 0: SM_PROCEED(getfile); + break; + case 1: SM_SUCCESS; + break; + default: SM_ERROR; + break; + } + +SM_END +SM_RETURN + + diff --git a/mbcico/sendbark.h b/mbcico/sendbark.h new file mode 100644 index 00000000..10fee0ec --- /dev/null +++ b/mbcico/sendbark.h @@ -0,0 +1,7 @@ +#ifndef _SENDBARK_H +#define _SENDBARK_H + +int sendbark(void); + +#endif + diff --git a/mbcico/session.c b/mbcico/session.c new file mode 100644 index 00000000..3ad4af27 --- /dev/null +++ b/mbcico/session.c @@ -0,0 +1,572 @@ +/***************************************************************************** + * + * File ..................: mbcico/session.c + * Purpose ...............: Fidonet mailer + * Last modification date : 02-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "statetbl.h" +#include "emsi.h" +#include "ftsc.h" +#include "session.h" +#include "yoohoo.h" +#include "mbcico.h" +#include "binkp.h" +#include "callstat.h" + + +extern int tcp_mode; + +node *nlent; +fa_list *remote=NULL; +int session_flags; +int remote_flags; + +int tx_define_type(void); +int rx_define_type(void); + +static int type; +static char *data=NULL; + + + +char *typestr(int); +char *typestr(int tp) +{ + switch (tp) { + case SESSION_FTSC: return (char *)"FTSC"; + case SESSION_YOOHOO: return (char *)"YooHoo/2U2"; + case SESSION_EMSI: return (char *)"EMSI"; + case SESSION_BINKP: return (char *)"Binkp"; + default: return (char *)"Unknown"; + } +} + + + +int session(faddr *a, node *nl, int role, int tp, char *dt) +{ + int rc = 1; + fa_list *tmpl; + struct sockaddr_in peeraddr; + int addrlen = sizeof(struct sockaddr_in); + + session_flags = 0; + type = tp; + nlent = nl; + + if (role) { + Syslog('s', "Start outbound session type %s with %s", typestr(type), ascfnode(a,0x1f)); + IsDoing("Outb %s", ascfnode(a, 0x0f)); + } else + Syslog('s', "Start inbound session type %s", typestr(type)); + + if (getpeername(0,(struct sockaddr*)&peeraddr,&addrlen) == 0) { + Syslog('s', "TCP connection: len=%d, family=%hd, port=%hu, addr=%s", + addrlen,peeraddr.sin_family, peeraddr.sin_port, inet_ntoa(peeraddr.sin_addr)); + if (role == 0) { + if (tcp_mode == TCPMODE_IBN) + Syslog('+', "Incoming IBN/TCP connection from %s", inet_ntoa(peeraddr.sin_addr)); + else if (tcp_mode == TCPMODE_ITN) + Syslog('+', "Incoming ITN/TCP connection from %s", inet_ntoa(peeraddr.sin_addr)); + else if (tcp_mode == TCPMODE_IFC) + Syslog('+', "Incoming IFC/TCP connection from %s", inet_ntoa(peeraddr.sin_addr)); + else if (tcp_mode == TCPMODE_NONE) { + WriteError("Unknown TCP connection, parameter missing"); + die(101); + } + + IsDoing("Answer TCP"); + } + session_flags |= SESSION_TCP; + } + + if (data) + free(data); + data=NULL; + + if (dt) + data=xstrcpy(dt); + + emsi_local_protos=0; + emsi_local_opts=0; + emsi_local_lcodes=0; + + tidy_falist(&remote); + remote=NULL; + if (a) { + remote=(fa_list*)malloc(sizeof(fa_list)); + remote->next=NULL; + remote->addr=(faddr*)malloc(sizeof(faddr)); + remote->addr->zone=a->zone; + remote->addr->net=a->net; + remote->addr->node=a->node; + remote->addr->point=a->point; + remote->addr->domain=xstrcpy(a->domain); + remote->addr->name=NULL; + } else { + remote=NULL; + } + + remote_flags=SESSION_FNC; + + if (role) { + if (type == SESSION_UNKNOWN) + (void)tx_define_type(); + switch(type) { + case SESSION_UNKNOWN: rc=20; break; + case SESSION_FTSC: rc=tx_ftsc(); break; + case SESSION_YOOHOO: rc=tx_yoohoo(); break; + case SESSION_EMSI: rc=tx_emsi(data); break; + case SESSION_BINKP: rc=binkp(role); break; + } + } else { + if (type == SESSION_FTSC) + session_flags |= FTSC_XMODEM_CRC; + if (type == SESSION_UNKNOWN) + (void)rx_define_type(); + switch(type) { + case SESSION_UNKNOWN: rc=20; break; + case SESSION_FTSC: rc=rx_ftsc(); break; + case SESSION_YOOHOO: rc=rx_yoohoo(); break; + case SESSION_EMSI: rc=rx_emsi(data); break; + case SESSION_BINKP: rc=binkp(role); break; + } + } + sleep(2); + for (tmpl = remote; tmpl; tmpl = tmpl->next) { + /* + * Unlock all nodes, locks not owned by us are untouched. + */ + (void)nodeulock(tmpl->addr); + /* + * If successfull session, reset all status records. + */ + if (rc == 0) + putstatus(tmpl->addr, 0, 0); + } + tidy_falist(&remote); + if (data) + free(data); + data = NULL; + + if (emsi_local_password) + free(emsi_local_password); + if (emsi_remote_password) + free(emsi_remote_password); + + if (nlent->addr.domain) + free(nlent->addr.domain); + + return rc; +} + + + +SM_DECL(tx_define_type,(char *)"tx_define_type") +SM_STATES + skipjunk, + wake, + waitchar, + nextchar, + checkintro, + sendinq +SM_NAMES + (char *)"skipjunk", + (char *)"wake", + (char *)"waitchar", + (char *)"nextchar", + (char *)"checkintro", + (char *)"sendinq" +SM_EDECL + int c=0; + int count=0; + char buf[256],*p; + char ebuf[13],*ep; + int standby=0; + + int maybeftsc=0; + int maybeyoohoo=0; + + type=SESSION_UNKNOWN; + ebuf[0]='\0'; + ep=ebuf; + buf[0]='\0'; + p=buf; + +SM_START(skipjunk) + +SM_STATE(skipjunk) + + Syslog('S', "tx_define_type SKIPJUNK"); + while ((c = GETCHAR(1)) >= 0) /*nothing*/ ; + if (c == TIMEOUT) { + SM_PROCEED(wake); + } else { + SM_ERROR; + } + +SM_STATE(wake) + + Syslog('S', "tx_define_type WAKE"); + if (count++ > 20) { + Syslog('+', "Remote did not respond"); + SM_ERROR; + } + + p=buf; + PUTCHAR('\r'); + if ((c = GETCHAR(2)) == TIMEOUT) { + SM_PROCEED(wake); + } else if (c < 0) { + WriteError("Error while waking remote"); + SM_ERROR; + } else { + count = 0; + Syslog('S', "Got %c wakeup", c); + SM_PROCEED(nextchar); + } + +SM_STATE(waitchar) + + Syslog('S', "tx_define_type WAITCHAR"); + if ((c = GETCHAR(2)) == TIMEOUT) { /* Was 4 seconds */ + standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (count++ > 30) { /* Was 8 loops */ + Syslog('+', "Too many tries waking remote"); + SM_ERROR; + } + SM_PROCEED(sendinq); + } else if (c < 0) { + Syslog('+', "Error while getting intro from remote"); + SM_ERROR; + } else { + SM_PROCEED(nextchar); + } + +SM_STATE(nextchar) + + Syslog('S', "tx_define_type NEXTCHAR"); + if (c == 'C') { + session_flags |= FTSC_XMODEM_CRC; + maybeftsc++; + } + if (c == NAK) { + session_flags &= ~FTSC_XMODEM_CRC; + maybeftsc++; + } + if (c == ENQ) + maybeyoohoo++; + + if (((localoptions & NOWAZOO) == 0) && (maybeyoohoo > 1)) { + type = SESSION_YOOHOO; + SM_SUCCESS; + } + + if (maybeftsc > 1) { + type = SESSION_FTSC; + SM_SUCCESS; + } + + if ((c >= ' ') && (c <= '~')) { + if (c != 'C') + maybeftsc = 0; + maybeyoohoo = 0; + + if ((p-buf) < (sizeof(buf)-1)) { + *p++ = c; + *p = '\0'; + } + + if (c == '*') { + standby = 1; + ep = ebuf; + buf[0] = '\0'; + } else if (standby) { + if ((ep - ebuf) < (sizeof(ebuf) - 1)) { + *ep++ = c; + *ep = '\0'; + } + if ((ep - ebuf) >= (sizeof(ebuf) - 1)) { + standby = 0; + SM_PROCEED(checkintro); + } + } + } else switch (c) { + case DC1: break; + case '\r': + case '\n': standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (buf[0]) + Syslog('+', "Intro: \"%s\"", printable(buf, 0)); + p = buf; + buf[0] = '\0'; + break; + default: standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + Syslog('i', "Got '%s' reading intro", printablec(c)); + break; + } + + SM_PROCEED(waitchar); + +SM_STATE(checkintro) + + Syslog('S', "tx_define_type CHECKINTRO"); + Syslog('i', "Check \"%s\" for being EMSI request",ebuf); + + if (((localoptions & NOEMSI) == 0) && (strncasecmp(ebuf,"EMSI_REQA77E",12) == 0)) { + type = SESSION_EMSI; + data = xstrcpy((char *)"**EMSI_REQA77E"); + Syslog('i', "Sending **EMSI_INQC816 (2 times)"); + PUTSTR((char *)"\r**EMSI_INQC816\r**EMSI_INQC816\r\021"); + SM_SUCCESS; + } else { + p = buf; + buf[0] = '\0'; + SM_PROCEED(waitchar); + } + +SM_STATE(sendinq) + + Syslog('S', "tx_define_type SENDINQ"); + PUTCHAR(DC1); + if ((localoptions & NOEMSI) == 0) { + Syslog('S', "send **EMSI_INQC816 (2 times)"); + PUTSTR((char *)"\r**EMSI_INQC816**EMSI_INQC816"); + } + if ((localoptions & NOWAZOO) == 0) { + Syslog('S', "send YOOHOO char"); + PUTCHAR(YOOHOO); + } + Syslog('S', "send TSYNC char"); + PUTCHAR(TSYNC); + if ((localoptions & NOEMSI) == 0) + PUTSTR((char *)"\r\021"); + SM_PROCEED(waitchar); + +SM_END +SM_RETURN + + + +SM_DECL(rx_define_type,(char *)"rx_define_type") +SM_STATES + sendintro, + waitchar, + nextchar, + checkemsi, + getdat +SM_NAMES + (char *)"sendintro", + (char *)"waitchar", + (char *)"nextchar", + (char *)"checkemsi", + (char *)"getdat" +SM_EDECL + int count=0; + int c=0; + int maybeftsc=0,maybeyoohoo=0; + char ebuf[13],*ep; + char *p; + int standby=0; + int datasize; + + type=SESSION_UNKNOWN; + session_flags|=FTSC_XMODEM_CRC; + ebuf[0]='\0'; + ep=ebuf; + Syslog('S', "rxdefine_type INIT"); + +SM_START(sendintro) + +SM_STATE(sendintro) + + Syslog('S', "rxdefine_type SENDINTRO"); + if (count++ > 6) { /* Was 16, is 6 according to the EMSI spec */ + Syslog('+', "Too many tries to get anything from the caller"); + SM_ERROR; + } + + standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + + if ((localoptions & NOEMSI) == 0) { + PUTSTR((char *)"**EMSI_REQA77E\r\021"); + } + PUTSTR((char *)"\r\rAddress: "); + PUTSTR(aka2str(CFG.aka[0])); + PUTSTR((char *)" using mbcico "); + PUTSTR((char *)VERSION); + switch (tcp_mode) { + case TCPMODE_IFC: PUTSTR((char *)"; IFC"); + break; + case TCPMODE_ITN: PUTSTR((char *)"; ITN"); + break; + case TCPMODE_IBN: PUTSTR((char *)"; IBN"); + break; + } + PUTCHAR('\r'); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitchar); + } + +SM_STATE(waitchar) + + Syslog('S', "rxdefine_type WAITCHAR"); + if ((c=GETCHAR(20)) == TIMEOUT) { /* Timeout was 8, must be 20. */ + SM_PROCEED(sendintro); + } else if (c < 0) { + Syslog('+', "EMSI error while getting from caller"); + SM_ERROR; + } else { + SM_PROCEED(nextchar); + } + +SM_STATE(nextchar) + + Syslog('S', "rxdefine_type NEXTCHAR"); + if ((c >= ' ') && (c <= 'z')) { + if (c == '*') { + standby = 1; + ep = ebuf; + ebuf[0] = '\0'; + } else if (standby) { + if ((ep - ebuf) < (sizeof(ebuf) - 1)) { + *ep++ = c; + *ep = '\0'; + } + if ((ep - ebuf) >= (sizeof(ebuf) - 1)) { + standby = 0; + SM_PROCEED(checkemsi); + } + } + SM_PROCEED(waitchar); + } else switch (c) { + case DC1: SM_PROCEED(waitchar); + break; + case TSYNC: standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (++maybeftsc > 1) { + type = SESSION_FTSC; + SM_SUCCESS; + } else { + SM_PROCEED(waitchar); + } + break; + case YOOHOO: standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (++maybeyoohoo > 1) { + type = SESSION_YOOHOO; + SM_SUCCESS; + } else { + SM_PROCEED(waitchar); + } + break; + case '\r': + case '\n': standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (ebuf[0]) { + SM_PROCEED(checkemsi); + } else { + SM_PROCEED(sendintro); + } + break; + default: standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + Syslog('i', "Got '%s' from remote", printablec(c)); + SM_PROCEED(waitchar); + break; + } + +SM_STATE(checkemsi) + + Syslog('S', "rxdefine_type CHECKEMSI"); + Syslog('i', "check \"%s\" for being EMSI inquery or data",ebuf); + + if (localoptions & NOEMSI) { + SM_PROCEED(sendintro); + } + + if (strncasecmp(ebuf, "EMSI_INQC816", 12) == 0) { + type = SESSION_EMSI; + data = xstrcpy((char *)"**EMSI_INQC816"); + SM_SUCCESS; + } else if (strncasecmp(ebuf, "EMSI_DAT", 8) == 0) { + SM_PROCEED(getdat); + } else { + SM_PROCEED(sendintro); + } + +SM_STATE(getdat) + + Syslog('S', "rxdefine_type GETDAT"); + Syslog('i', "Try get emsi_dat packet starting with \"%s\"",ebuf); + + if (sscanf(ebuf+8, "%04x", &datasize) != 1) { + SM_PROCEED(sendintro); + } + + datasize += 18; /* strlen("**EMSI_DATxxxxyyyy"), include CRC */ + data=malloc(datasize+1); + strcpy(data,"**"); + strcat(data, ebuf); + p = data + strlen(data); + + while (((p - data) < datasize) && ((c = GETCHAR(8)) >= 0)) { + *p++ = c; + *p= '\0'; + } + if (c == TIMEOUT) { + SM_PROCEED(sendintro); + } else if (c < 0) { + Syslog('+', "Error while reading EMSI_DAT from the caller"); + SM_ERROR; + } + type = SESSION_EMSI; + SM_SUCCESS; + +SM_END +SM_RETURN + diff --git a/mbcico/session.h b/mbcico/session.h new file mode 100644 index 00000000..f2e87c2d --- /dev/null +++ b/mbcico/session.h @@ -0,0 +1,69 @@ +#ifndef _SESSION_H +#define _SESSION_H + +#define TCPMODE_NONE 0 +#define TCPMODE_IFC 1 /* ifcico native EMSI on raw TCP */ +#define TCPMODE_ITN 2 /* EMSI encapsulation through telnet */ +#define TCPMODE_IBN 3 /* Binkp protocol */ + +#define SESSION_UNKNOWN 0 +#define SESSION_FTSC 1 +#define SESSION_YOOHOO 2 +#define SESSION_EMSI 3 +#define SESSION_BINKP 4 + +#define SESSION_SLAVE 0 +#define SESSION_MASTER 1 + +extern node *nlent; +extern fa_list *remote; + +typedef struct _file_list { + struct _file_list *next; + char *local; + char *remote; + int disposition; + FILE *flofp; + off_t floff; +} file_list; + +#define HOLD_MAIL "h" +#define NONHOLD_MAIL "ico" +#define ALL_MAIL "coh" + +extern int session_flags; +extern int remote_flags; +#define FTSC_XMODEM_CRC 1 /* xmodem-crc */ +#define FTSC_XMODEM_RES 2 /* sealink-resync */ +#define FTSC_XMODEM_SLO 4 /* sealink-overdrive */ +#define FTSC_XMODEM_XOF 8 /* xoff flow control, aka macflow */ +#define WAZOO_ZMODEM_ZAP 1 /* ZedZap allowed */ + +#define SESSION_WAZOO 0x8000 /* WaZOO type file requests */ +#define SESSION_BARK 0x4000 /* bark type file requests */ +#define SESSION_IFNA 0x2000 /* DietIFNA transfer from Yoohoo session */ +#define SESSION_FNC 0x1000 /* Filename conversion sending files */ + +#define SESSION_TCP 0x0800 /* Established over TCP/IP link */ +#define SESSION_HYDRA 0x0400 /* Hydra special file requests */ + +extern int localoptions; +#define NOCALL 0x0001 +#define NOHOLD 0x0002 +#define NOPUA 0x0004 +#define NOWAZOO 0x0008 +#define NOEMSI 0x0010 +#define NOFREQS 0x0020 +#define NOZMODEM 0x0040 +#define NOZEDZAP 0x0080 +#define NOJANUS 0x0100 +#define NOHYDRA 0x0200 +#define NOTCP 0x0400 + + +struct _history history; /* History record for sessions */ + +int session(faddr*,node*,int,int,char*); + +#endif + diff --git a/mbcico/statetbl.h b/mbcico/statetbl.h new file mode 100644 index 00000000..8a9ceece --- /dev/null +++ b/mbcico/statetbl.h @@ -0,0 +1,48 @@ +#ifndef STATETBL_H +#define STATETBL_H + +#define SM_DECL(proc,name) \ +int proc(void)\ +{\ + int sm_success=0;\ + char *sm_name=name; + +#define SM_STATES \ + enum { + +#define SM_NAMES \ + } sm_state; \ + char * sm_sname[] = { + +#define SM_EDECL \ + }; + +#define SM_START(x) \ + sm_state=x;\ + Syslog('S', "Statemachine %s start %s (%d)",sm_name,sm_sname[sm_state],sm_state); \ + while (!sm_success) switch (sm_state)\ + {\ + default: WriteError("Statemachine %s error: state=%d",sm_name,sm_state);\ + sm_success=-1; + +#define SM_STATE(x) \ + break;\ + case x: + +#define SM_END \ + }\ + +#define SM_RETURN \ + return (sm_success != 1);\ +} + +#define SM_PROCEED(x) \ + sm_state=x; break; + +#define SM_SUCCESS \ + sm_success=1; break; + +#define SM_ERROR \ + sm_success=-1; break; + +#endif diff --git a/mbcico/tcp.c b/mbcico/tcp.c new file mode 100644 index 00000000..0e842df7 --- /dev/null +++ b/mbcico/tcp.c @@ -0,0 +1,136 @@ +/***************************************************************************** + * + * File ..................: mbcico/tcp.c + * Purpose ...............: Fidonet mailer + * Last modification date : 01-Feb-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + contributed by Stanislav Voronyi +*/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "respfreq.h" +#include "filelist.h" +#include "tcpproto.h" +#include "tcp.h" + + +extern int made_request; + + +int rxtcp(void) +{ + int rc = 0; + fa_list *eff_remote, tmpl; + file_list *tosend = NULL, **tmpfl; + + Syslog('+', "Start TCP session"); + + if (emsi_remote_lcodes & LCODE_NPU) { + Syslog('+', "Remote requested \"no pickup\", no send"); + eff_remote=NULL; + } else if (emsi_remote_lcodes & LCODE_PUP) { + Syslog('+', "Remote requested \"pickup primary\""); + tmpl.addr=remote->addr; + tmpl.next=NULL; + eff_remote=&tmpl; + } else + eff_remote=remote; + + tosend = create_filelist(eff_remote, (char *)ALL_MAIL, 0); + + if ((rc=tcprcvfiles()) == 0) { + if ((emsi_local_opts & OPT_NRQ) == 0) { + for (tmpfl = &tosend; *tmpfl; tmpfl = &((*tmpfl)->next)); + *tmpfl = respond_wazoo(); + } + + if ((tosend != NULL) || ((emsi_remote_lcodes & LCODE_NPU) == 0)) + rc = tcpsndfiles(tosend); + + if ((rc == 0) && (made_request)) { + Syslog('+', "Freq was made, trying to receive files"); + rc = tcprcvfiles(); + } + } + + tidy_filelist(tosend,(rc == 0)); + + if (rc) + WriteError("TCP session failed: rc=%d", rc); + else + Syslog('+', "TCP session completed"); + return rc; +} + + + +int txtcp(void) +{ + int rc=0; + file_list *tosend = NULL, *respond = NULL; + char *nonhold_mail; + + Syslog('+', "Start TCP session"); + + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + if (emsi_remote_lcodes & LCODE_HAT) { + Syslog('+', "Remote asked to \"hold all traffic\", no send"); + tosend=NULL; + } else + tosend = create_filelist(remote,nonhold_mail,0); + + if ((tosend != NULL) || ((emsi_remote_lcodes & LCODE_NPU) == 0)) + rc = tcpsndfiles(tosend); + if (rc == 0) + if ((rc = tcprcvfiles()) == 0) + if ((emsi_local_opts & OPT_NRQ) == 0) + if ((respond = respond_wazoo())) + rc = tcpsndfiles(respond); + + tidy_filelist(tosend,(rc == 0)); + tidy_filelist(respond,0); + + if (rc) + WriteError("TCP session failed: rc=%d", rc); + else + Syslog('+', "TCP session completed"); + return rc; +} + diff --git a/mbcico/tcp.h b/mbcico/tcp.h new file mode 100644 index 00000000..5f61c86a --- /dev/null +++ b/mbcico/tcp.h @@ -0,0 +1,9 @@ +#ifndef _TCP_H +#define _TCP_H + +int rxtcp(void); +int txtcp(void); + + +#endif + diff --git a/mbcico/tcpproto.c b/mbcico/tcpproto.c new file mode 100644 index 00000000..f5877825 --- /dev/null +++ b/mbcico/tcpproto.c @@ -0,0 +1,478 @@ +/***************************************************************************** + * + * File ..................: mbcico/tcpproto.c + * Purpose ...............: Fidonet mailer + * Last modification date : 24-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + contributed by Stanislav Voronyi +*/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "config.h" +#include "emsi.h" +#include "lutil.h" +#include "openfile.h" +#include "filelist.h" +#include "tcpproto.h" + + +#define TCP_CMD 0x87 +#define TCP_DATA 0xe1 + +static FILE *fout; +static FILE *in; +static char txbuf[2048]; +static char rxbuf[2048]; +static int rx_type; +static long startime,endtime,rxbytes,sbytes; + +static int sendfile(char *,char *); +static int finsend(void); +static int receivefile(char *,time_t,off_t); +static int resync(off_t); +static int closeit(int); +static int tcp_sblk(char *,int,int); +static int tcp_rblk(char *,int *); +static int getsync(void); + +extern unsigned long sentbytes; +extern unsigned long rcvdbytes; +extern char *ttystat[]; + + +int tcpsndfiles(file_list *lst) +{ + int rc = 0, maxrc = 0; + file_list *tmpf; + + Syslog('+', "Start TCP send%s",lst?"":" (dummy)"); + + if (getsync()) { + WriteError("Can't get synchronization"); + return 1; + } + + for (tmpf = lst; tmpf && (maxrc == 0); tmpf = tmpf->next) { + if (tmpf->remote) { + rc = sendfile(tmpf->local,tmpf->remote); + rc = abs(rc); + if (rc > maxrc) + maxrc=rc; + if (rc == 0) + execute_disposition(tmpf); + } else + if (maxrc == 0) + execute_disposition(tmpf); + } + + if (maxrc < 2) { + rc = finsend(); + rc = abs(rc); + } + + if (rc > maxrc) + maxrc=rc; + + if (rc) + WriteError("TCP send error: rc=%d",maxrc); + return maxrc; +} + + + +int tcprcvfiles(void) +{ + int rc, bufl; + long filesize, filetime; + char *filename, *p; + + Syslog('+', "Start TCP receive"); + if (getsync()) { + WriteError("Can't get synchronization"); + return 1; + } +next: + if ((rc = tcp_rblk(rxbuf, &bufl)) == 0) { + if (strncmp(rxbuf, "SN", 2) == 0) { + rc = tcp_sblk((char *)"RN", 2, TCP_CMD); + return rc; + } else if (*rxbuf == 'S') { + p = strchr(rxbuf+2, ' '); + if (p != NULL) + *p=0; + else + return 1; + filename = xstrcpy(rxbuf+2); + p++; + filesize = strtol(p, &p, 10); + filetime = strtol(++p, (char **)NULL, 10); + } else + return rc==0?1:rc; + + if (strlen(filename) && filesize && filetime) + rc = receivefile(filename,filetime,filesize); + + if (fout) { + if (closeit(0)) + WriteError("Error closing file"); + (void)tcp_sblk((char *)"FERROR",6,TCP_CMD); + } else + goto next; + } + + if (rc) + WriteError("TCP receive error: rc=%d", rc); + return abs(rc); +} + + + +static int sendfile(char *ln, char *rn) +{ + int rc=0; + struct stat st; + struct flock fl; + int bufl, sverr; + long offset; + + fl.l_type = F_RDLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + + if ((in = fopen(ln,"r")) == NULL) { + sverr = errno; + if ((sverr == ENOENT) || (sverr == EINVAL)) { + Syslog('+', "File %s doesn't exist, removing", MBSE_SS(ln)); + return 0; + } else { + WriteError("$tcpsend: cannot open file %s, skipping", MBSE_SS(ln)); + return 1; + } + } + + if (fcntl(fileno(in), F_SETLK, &fl) != 0) { + Syslog('+', "$tcpsend: cannot lock file %s, skipping", MBSE_SS(ln)); + fclose(in); + return 1; + } + + if (stat(ln, &st) != 0) { + Syslog('+', "$tcpsend: cannot access \"%s\", skipping", MBSE_SS(ln)); + fclose(in); + return 1; + } + + if (st.st_size > 0) { + Syslog('+', "TCP send \"%s\" as \"%s\"", MBSE_SS(ln), MBSE_SS(rn)); + Syslog('+', "TCP size %lu bytes, dated %s", (unsigned long)st.st_size, date(st.st_mtime)); + (void)time(&startime); + } else { + Syslog('+', "File \"%s\" has 0 size, skiped",ln); + return 0; + } + + sprintf(txbuf,"S %s %lu %lu",rn,(unsigned long)st.st_size,st.st_mtime+(st.st_mtime%2)); + bufl = strlen(txbuf); + rc = tcp_sblk(txbuf, bufl, TCP_CMD); + rc = tcp_rblk(rxbuf, &bufl); + + if (strncmp(rxbuf,"RS",2) == 0) { + Syslog('+', "File %s already received, skipping",rn); + return 0; + } else if (strncmp(rxbuf,"RN",2) == 0) { + Syslog('+', "Remote refused file, aborting",rn); + return 2; + } else if (strncmp(rxbuf,"ROK",3) == 0) { + if (bufl > 3 && rxbuf[3]==' ') { + offset = strtol(rxbuf+4,(char **)NULL,10); + if (fseek(in,offset,SEEK_SET) != 0) { + WriteError("$tcpsend cannot seek in file %s",ln); + return 1; + } + } else + offset = 0; + } else + return rc; + + while ((bufl = fread(&txbuf, 1, 1024, in)) != 0) { + if ((rc = tcp_sblk(txbuf, bufl, TCP_DATA)) > 0) + break; + } + + fclose(in); + if (rc == 0){ + strcpy(txbuf, "EOF"); + rc = tcp_sblk(txbuf, 3, TCP_CMD); + rc = tcp_rblk(rxbuf, &bufl); + } + + if (rc == 0 && strncmp(rxbuf,"FOK",3) == 0) { + (void)time(&endtime); + + if ((startime=endtime-startime) == 0) + startime = 1; + Syslog('a', "st_size %d, offset %d",st.st_size,offset); + Syslog('+', "Sent %lu bytes in %s (%ld cps)", + (unsigned long)st.st_size-offset, + str_time(startime), + (long)(st.st_size-offset)/startime); + sentbytes += (unsigned long)st.st_size - offset; + return 0; + } else if(strncmp(rxbuf,"FERROR",6) == 0){ + WriteError("$tcpsend remote file error",ln); + return rc==0?1:rc; + } else + return rc==0?1:rc; +} + + + +static int resync(off_t off) +{ + sprintf(txbuf,"ROK %ld",(long)off); + return 0; +} + + + +static int closeit(int success) +{ + int rc; + + rc = closefile(success); + fout = NULL; + sbytes = rxbytes - sbytes; + (void)time(&endtime); + + if ((startime = endtime - startime) == 0L) + startime = 1L; + Syslog('+', "%s %lu bytes in %s (%ld cps)", + success?"OK":"dropped after", + sbytes, str_time(startime), sbytes / startime); + rcvdbytes += sbytes; + return rc; +} + + + +static int finsend(void) +{ + int rc,bufl; + + rc = tcp_sblk((char *)"SN",2,TCP_CMD); + if(rc) + return rc; + + rc = tcp_rblk(rxbuf,&bufl); + if (strncmp(rxbuf, "RN", 2) == 0) + return rc; + else + return 1; +} + + + +static int receivefile(char *fn, time_t ft, off_t fs) +{ + int rc, bufl; + + Syslog('+', "TCP receive \"%s\" (%lu bytes) dated %s",fn,fs,date(ft)); + strcpy(txbuf,"ROK"); + fout = openfile(fn, ft, fs, &rxbytes, resync); + (void)time(&startime); + sbytes = rxbytes; + + if (fs == rxbytes) { + Syslog('+', "Skipping %s", fn); + fout = NULL; + rc = tcp_sblk((char *)"RS",2,TCP_CMD); + return rc; + } + + if (!fout) + return 1; + + bufl = strlen(txbuf); + rc = tcp_sblk(txbuf,bufl,TCP_CMD); + + while ((rc = tcp_rblk(rxbuf, &bufl)) == 0) { + if (rx_type == TCP_CMD) + break; + if (fwrite(rxbuf, 1, bufl, fout) != bufl) + break; + rxbytes += bufl; + } + + if (rc) + return rc; + + if (rx_type == TCP_CMD && bufl == 3 && strncmp(rxbuf,"EOF",3) == 0) { + if (ftell(fout) == fs) { + closeit(1); + rc = tcp_sblk((char *)"FOK",3,TCP_CMD); + return rc; + } else + return 1; + } else + return 1; +} + + + +static int tcp_sblk(char *buf, int len, int typ) +{ + Nopper(); + if (typ == TCP_CMD) + Syslog('A', "tcp_sblk: cmd: %s", buf); + else + Syslog('A', "tcp_sblk: data: %d bytes", len); + + PUTCHAR(0xc6); + PUTCHAR(typ); + PUTCHAR((len >> 8) & 0x0ff); + PUTCHAR(len & 0x0ff); + PUT(buf, len); + PUTCHAR(0x6c); + FLUSHOUT(); + if (tty_status) + WriteError("TCP send error: %s", ttystat[tty_status]); + else + Syslog('A', "tcp_sblk: complete"); + return tty_status; +} + + + +static int tcp_rblk(char *buf, int *len) +{ + int c; + + Syslog('A', "tcp_rblk: start"); + *len = 0; + + /* + * Wait up to 3 minutes for the header + */ + c = GETCHAR(180); + if (tty_status) + goto to; + if (c != 0xc6) { + WriteError("tcp_rblk: got %d instead of block header", c); + return c; + } + + /* + * Get block type + */ + c = GETCHAR(120); + if (tty_status) + goto to; + rx_type = c; + if (c != TCP_CMD && c != TCP_DATA) { + WriteError("tcp_rblk: got %d character instead of DATA/CMD", c); + return c; + } + + /* + * Get block length + */ + c = GETCHAR(120); + if (tty_status) + goto to; + *len = c << 8; + c = GETCHAR(120); + if (tty_status) + goto to; + *len += c; + Syslog('A', "tcp_rblk: expecting %d bytes", *len); + + /* + * Get actual data block + */ + GET(buf, *len, 120); + if (tty_status) + goto to; + + /* + * Get block trailer + */ + c = GETCHAR(120); + if (tty_status) + goto to; + if (c != 0x6c) + return c; + + if (rx_type == TCP_CMD) { + buf[*len] = '\0'; + Syslog('A', "tcp_rblk: cmd: %s", buf); + } else + Syslog('A', "tcp_rblk: data: %d bytes", *len); + +to: + if (tty_status) + WriteError("TCP receive error: %s", ttystat[tty_status]); + return tty_status; +} + + + +static int getsync(void) +{ + int c; + + PUTCHAR(0xaa); + PUTCHAR(0x55); + FLUSHOUT(); + Syslog('a', "getsync try to synchronize"); + +gs: + if (tty_status) { + WriteError("TCP getsync failed %s", ttystat[tty_status]); + return 1; + } + while ((c = GETCHAR(180)) != 0xaa) + if (tty_status) { + WriteError("TCP getsync failed: %s", ttystat[tty_status]); + return 1; + } + + if ((c = GETCHAR(120)) != 0x55) + goto gs; + + Syslog('a', "getsync done, tty_status %s", ttystat[tty_status]); + return tty_status; +} + + diff --git a/mbcico/tcpproto.h b/mbcico/tcpproto.h new file mode 100644 index 00000000..9a5da755 --- /dev/null +++ b/mbcico/tcpproto.h @@ -0,0 +1,9 @@ +#ifndef _TCPPROTO_H +#define _TCPPROTO_H + +int tcpsndfiles(file_list *); +int tcprcvfiles(void); + + +#endif + diff --git a/mbcico/ttyio.c b/mbcico/ttyio.c new file mode 100644 index 00000000..df9d2afe --- /dev/null +++ b/mbcico/ttyio.c @@ -0,0 +1,590 @@ +/***************************************************************************** + * + * File ..................: mbcico/ttyio.c + * Purpose ...............: Fidonet mailer + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* ### Modified by P.Saratxaga on 25 Oct 1995 ### + * - Added if (inetaddr) code from T. Tanaka + */ +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "lutil.h" + +extern int hanged_up; +extern char *inetaddr; + +#define TT_BUFSIZ 1024 +#define NUMTIMERS 3 + + +int tty_status = 0; +int f_flags; +static char buffer[TT_BUFSIZ]; +static char *next; +static int left = 0; + + +static time_t timer[NUMTIMERS]; + +char *ttystat[]= {(char *)"Ok", + (char *)"Error", + (char *)"TimeOut", + (char *)"EOF", + (char *)"Hangup", + (char *)"Empty"}; + + + + +/* + * timer functions + */ + +int tty_resettimer(int tno) +{ + if (tno >= NUMTIMERS) { + errno = EINVAL; + WriteError("$ttyio: invalid timer No for resettimer()"); + return -1; + } + + Syslog('T', "ttyio: resettimer(%d)", tno); + timer[tno] = (time_t) 0; + return 0; +} + + + +void tty_resettimers(void) +{ + int i; + + Syslog('T', "ttyio: resettimers"); + for (i = 0; i < NUMTIMERS; i++) + timer[i] = (time_t)0; +} + + + +int tty_settimer(int tno, int interval) +{ + if (tno >= NUMTIMERS) { + errno = EINVAL; + WriteError("$ttyio: invalid timer No for settimer()"); + return -1; + } + + Syslog('T', "ttyio: settimer(%d,%d)",tno,interval); + timer[tno]=time((time_t*)NULL)+interval; + return 0; +} + + + +int tty_expired(int tno) +{ + time_t now; + + if (tno >= NUMTIMERS) { + errno = EINVAL; + WriteError("$ttyio: invalid timer No for expired(%d)", tno); + return -1; + } + + /* + * Check if timer is running + */ + if (timer[tno] == (time_t) 0) + return 0; + + (void)time(&now); + Syslog('T', "ttyio: expired(%d) now=%lu,timer=%lu,return %s", + tno,now,timer[tno],(now >= timer[tno])?"yes":"no"); + return (now >= timer[tno]); +} + + + +int tty_running(int tno) +{ + if (tno > NUMTIMERS) { + errno = EINVAL; + WriteError("$ttyio: invalid timer for tty_running(%d)", tno); + return -1; + } + + /* + * check if timer is running + */ + if (timer[tno] == (time_t) 0) + return 0; + else + return 1; +} + + + +/* + * private r/w functions + */ + +static int tty_read(char *buf, int size, int tot) +{ + time_t timeout, now; + int i, rc; + fd_set readfds, writefds, exceptfds; + struct timeval seltimer; + + Syslog('T', "tty_read: (%08lx,%d,%d)",buf,size,tot); + if (size == 0) + return 0; + tty_status = 0; + + (void)time(&now); + timeout = (time_t)300; /* maximum of 5 minutes */ + + for (i = 0; i < TIMERNO_TX; i++) { + if (timer[i]) { + if (now >= timer[i]) { + tty_status=STAT_TIMEOUT; + Syslog('t', "tty_read: timer %d already expired, return",i); + return -tty_status; + } else { + if (timeout > (timer[i]-now)) + timeout=timer[i]-now; + } + } + } + if ((tot != -1) && (timeout > tot)) + timeout=tot; + + Syslog('T', "tty_read: timeout = %d", timeout); + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + FD_SET(0,&readfds); + FD_SET(0,&exceptfds); + seltimer.tv_sec=timeout; + seltimer.tv_usec=0; + + rc = select(1,&readfds,&writefds,&exceptfds,&seltimer); + + if (rc < 0) { + if (hanged_up) { + tty_status=STAT_HANGUP; + WriteError("$tty_read: hanged_up flag"); + } else { + WriteError("$tty_read: select for read failed"); + tty_status = STAT_ERROR; + } + } else if (rc == 0) { + tty_status = STAT_TIMEOUT; + } else { /* rc > 0 */ + if (FD_ISSET(0,&exceptfds)) { + Syslog('+', "$tty_read: exeption error"); + tty_status = STAT_ERROR; + } + } + + if (tty_status) { + Syslog('T', "tty_read: return after select: %s",ttystat[tty_status]); + return -tty_status; + } + + if (!FD_ISSET(0,&readfds)) { + WriteError("tty_read: Cannot be: select returned but read fd not set"); + tty_status = STAT_ERROR; + return -tty_status; + } + + rc = read(0,buf,size); + if (rc <= 0) { + Syslog('t', "tty_read: return %d",rc); + if (hanged_up || (errno == EPIPE) || (errno == ECONNRESET)) { + tty_status = STAT_HANGUP; + WriteError("$tty_read: hanged_up flag"); + } else + tty_status = STAT_ERROR; + rc=-tty_status; + } else + Syslog('T', "tty_read: %s %d characters", printable(buf, rc), rc); + return rc; +} + + + +int tty_write(char *buf, int size) +{ + int result; + + Syslog('T', "tty_write(%08lx,%d)",buf,size); + + tty_status=0; + result = write(1,buf,size); + + if (result != size) { + if (hanged_up || (errno == EPIPE) || (errno == ECONNRESET)) { + tty_status = STAT_HANGUP; + WriteError("$tty_write: hanged_up flag"); + } else + tty_status=STAT_ERROR; + } + if (tty_status) + Syslog('t', "tty_write: error %s", ttystat[tty_status]); + + return -tty_status; +} + + + +/* public r/w functions */ + +/** + * Check if there is data available on stdin. + */ +int tty_check(void) +{ + int rc; + + // try to read available (timeout = 0) data if we have no data in + // our buffer + + if (!left) { + rc = tty_read(buffer, TT_BUFSIZ, 0); + if (rc > 0) { + left = rc; + } + } + + return (left > 0); +} + + + +int tty_putcheck(int size) +{ + fd_set set; + struct timeval timeout; + + /* + * Initialize the file descriptor set. + */ + FD_ZERO(&set); + FD_SET(1, &set); + + /* + * Initialize the timeout data structure. + */ + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + /* + * `select' returns 0 if timeout, 1 if input available, -1 if error. + */ + return select(FD_SETSIZE, NULL, &set, NULL, &timeout); +} + + + +int tty_waitputget(int tot) +{ + int i, rc; + time_t timeout, now; + fd_set readfds, writefds, exceptfds; + struct timeval seltimer; + + tty_status=0; + (void)time(&now); + timeout=(time_t)300; /* maximum of 5 minutes */ + + for (i = 0; i < NUMTIMERS; i++) { + if (timer[i]) { + if (now >= timer[i]) { + tty_status = STAT_TIMEOUT; + WriteError("tty_waitputget: timer %d already expired, return",i); + return -tty_status; + } else { + if (timeout > (timer[i]-now)) + timeout = timer[i]-now; + } + } + } + if ((tot != -1) && (timeout > tot)) + timeout=tot; + Syslog('t', "tty_waitputget: timeout=%d",timeout); + + /* + * Initialize the file descriptor set. + */ + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + + FD_SET(0, &readfds); + FD_SET(1, &writefds); + FD_SET(0, &exceptfds); + FD_SET(1, &exceptfds); + + /* + * Initialize the timeout data structure. + */ + seltimer.tv_sec = timeout; + seltimer.tv_usec = 0; + + /* + * `select' returns 0 if timeout, 1 if input available, -1 if error. + */ + rc = select(FD_SETSIZE, &readfds, &writefds, &exceptfds, &seltimer); + + if (rc < 0) { + if (hanged_up) { + tty_status=STAT_HANGUP; + WriteError("tty_waitputget: hanged_up flag"); + } else { + WriteError("$tty_waitputget: select failed"); + tty_status=STAT_ERROR; + } + } else if (rc == 0) { + tty_status=STAT_TIMEOUT; + } else { + /* rc > 0 */ + if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) { + WriteError("$tty_waitputget: exeption error"); + tty_status=STAT_ERROR; + } + } + + if (tty_status) { + Syslog('t', "tty_waitputget: return after select status %s",ttystat[tty_status]); + return -tty_status; + } + + rc = 0; + + if (FD_ISSET(0,&readfds)) + rc |= 1; + + if (FD_ISSET(1,&writefds)) + rc |= 2; + + return rc; +} + + + +void tty_flushin(void) +{ + tcflush(0, TCIFLUSH); +} + + + +void tty_flushout(void) +{ + tcflush(1, TCOFLUSH); +} + + + +int tty_ungetc(int c) +{ + if (next == buffer) { + if (left >= TT_BUFSIZ) { + return -1; + } + + next = buffer + TT_BUFSIZ - left; + memcpy(next, buffer, left); + } + + next--; + *next = c; + left++; + + return 0; +} + + + +int tty_getc(int tot) +{ + if (!left) { + left=tty_read(buffer,TT_BUFSIZ,tot); + next=buffer; + } + + if (left <= 0) { + left=0; + return -tty_status; + } else { + left--; + return (*next++)&0xff; + } +} + + + +int tty_get(char *buf, int size, int tot) +{ + int result=0; + + if (left >= size) { + memcpy(buf,next,size); + next += size; + left -= size; + return 0; + } + + if (left > 0) { + memcpy(buf,next,left); + buf += left; + next += left; + size -= left; + left=0; + } + + while ((result=tty_read(buf,size,tot)) > 0) { + buf += result; + size -= result; + } + + return result; +} + + + +int tty_putc(int c) +{ + char buf = c; + + return tty_write(&buf,1); +} + + + +int tty_put(char *buf, int size) +{ + return tty_write(buf,size); +} + + + +int tty_putget(char **obuf, int *osize, char **ibuf, int *isize) +{ + time_t timeout, now; + int i, rc; + fd_set readfds, writefds, exceptfds; + struct timeval seltimer; + + tty_status = 0; + (void)time(&now); + timeout = (time_t)300; /* maximum of 5 minutes */ + + for (i = 0; i < NUMTIMERS; i++) { + if (timer[i]) { + if (now >= timer[i]) { + tty_status = STAT_TIMEOUT; + WriteError("tty_putget: timer %d already expired, return",i); + return -tty_status; + } else { + if (timeout > (timer[i]-now)) + timeout=timer[i]-now; + } + } + } + + Syslog('t', "tty_putget: timeout=%d",timeout); + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + FD_SET(0,&readfds); + FD_SET(1,&writefds); + FD_SET(0,&exceptfds); + FD_SET(1,&exceptfds); + seltimer.tv_sec=timeout; + seltimer.tv_usec=0; + + rc=select(2,&readfds,&writefds,&exceptfds,&seltimer); + if (rc < 0) { + if (hanged_up) { + tty_status=STAT_HANGUP; + WriteError("tty_putget: hanged_up flag"); + } else { + WriteError("$tty_putget: select failed"); + tty_status=STAT_ERROR; + } + } else if (rc == 0) { + tty_status=STAT_TIMEOUT; + } else { + /* rc > 0 */ + if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) { + WriteError("$tty_putget: exeption error"); + tty_status=STAT_ERROR; + } + } + + if (tty_status) { + Syslog('t', "tty_putget: return after select status %s",ttystat[tty_status]); + return -tty_status; + } + + if (FD_ISSET(0,&readfds) && *isize) { + rc=read(0,*ibuf,*isize); + if (rc < 0) { + WriteError("$tty_putget: read failed"); + tty_status=STAT_ERROR; + } else { + (*ibuf)+=rc; + (*isize)-=rc; + } + } + + if (FD_ISSET(1,&writefds) && *osize) { + rc=write(1,*obuf,*osize); + if (rc < 0) { + WriteError("$tty_putget: write failed"); + tty_status=STAT_ERROR; + } else { + (*obuf)+=rc; + (*osize)-=rc; + } + } + + if (tty_status) + return -tty_status; + else + return ((*isize == 0) | ((*osize == 0) << 1)); +} + diff --git a/mbcico/ttyio.h b/mbcico/ttyio.h new file mode 100644 index 00000000..c33ff2c8 --- /dev/null +++ b/mbcico/ttyio.h @@ -0,0 +1,183 @@ +#ifndef TTYIO_H +#define TTYIO_H + +/* + * Timer numbers for Hydra + */ +#define TIMERNO_BRAIN 0 +#define TIMERNO_RX 1 +#define TIMERNO_TX 2 + +#define RESETTIMER(x) tty_resettimer(x) +#define RESETTIMERS() tty_resettimers() +#define SETTIMER(x,y) tty_settimer(x,y) +#define EXPIRED(x) tty_expired(x) +#define RUNNING(x) tty_running(x) + +#define TCHECK() tty_check() +#define PUTCHECK(x) tty_putcheck(x) +#define WAITPUTGET(x) tty_waitputget(x) +#define FLUSHOUT() tty_flushout() +#define FLUSHIN() tty_flushin() +#define PUTCHAR(x) tty_putc(x) +#define PUT(x,y) tty_put(x,y) +#define PUTSTR(x) tty_put(x,strlen(x)) +#define GETCHAR(x) tty_getc(x) +#define UNGETCHAR(x) tty_ungetc(x) +#define GET(x,y,z) tty_get(x,y,z) +#define PUTGET(a,b,x,y) tty_putget(a,b,x,y) +#define STATUS tty_status + +#define STAT_SUCCESS 0 +#define STAT_ERROR 1 +#define STAT_TIMEOUT 2 +#define STAT_EOFILE 3 +#define STAT_HANGUP 4 +#define STAT_EMPTY 5 + +#define SUCCESS (STATUS == 0) +#define TERROR (-STAT_ERROR) +#define TIMEOUT (-STAT_TIMEOUT) +#define EOFILE (-STAT_EOFILE) +#define HANGUP (-STAT_HANGUP) +#define EMPTY (-STAT_EMPTY) + +#define GET_COMPLETE(x) (x & 1) +#define PUT_COMPLETE(x) (x & 2) + +#ifndef NUL +#define NUL 0x00 +#endif +#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 +#ifndef FF +#define FF 0x0c +#endif +#ifndef CR +#define CR 0x0d +#endif +#define SO 0x0e +#define SI 0x0f +#define DLE 0x10 +#define XON 0x11 +#define DC1 0x11 +#define DC2 0x12 +#define XOFF 0x13 +#define DC3 0x13 +#define DC4 0x14 +#define NAK 0x15 +#define SYN 0x16 +#define ETB 0x17 +#define CAN 0x18 +#define EM 0x19 +#define SUB 0x1a +#ifndef ESC +#define ESC 0x1b +#endif +#define RS 0x1e +#define US 0x1f +#define TSYNC 0xae +#define YOOHOO 0xf1 + +/* ### Modifned by T.Tanaka on 4 Dec 1995 */ +#define ClearArray(x) memset((char *)x, 0, sizeof x) + +#define NETADD(c) { PUTCHAR(c); } +#define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } + +#define MY_STATE_WILL 0x01 +#define MY_WANT_STATE_WILL 0x02 +#define MY_STATE_DO 0x04 +#define MY_WANT_STATE_DO 0x08 +#define my_state_is_do(opt) (telnet_options[opt]&MY_STATE_DO) +#define my_state_is_will(opt) (telnet_options[opt]&MY_STATE_WILL) +#define my_want_state_is_do(opt) (telnet_options[opt]&MY_WANT_STATE_DO) +#define my_want_state_is_will(opt) (telnet_options[opt]&MY_WANT_STATE_WILL) +#define my_state_is_dont(opt) (!my_state_is_do(opt)) +#define my_state_is_wont(opt) (!my_state_is_will(opt)) +#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt)) +#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt)) +#define set_my_want_state_do(opt) {telnet_options[opt] |= MY_WANT_STATE_DO;} +#define set_my_want_state_will(opt) {telnet_options[opt] |= MY_WANT_STATE_WILL;} +#define set_my_want_state_dont(opt) {telnet_options[opt] &= ~MY_WANT_STATE_DO;} +#define set_my_want_state_wont(opt) {telnet_options[opt] &= ~MY_WANT_STATE_WILL;} + +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_XDISPLOC 35 /* X Display Location */ +#define TELOPT_ENVIRON 36 /* Environment variables */ +#define TELOPT_AUTHENTICATION 37/* Authenticate */ +#define TELOPT_ENCRYPT 38 /* Encryption option */ +#define TELOPT_EXOPL 255 /* extended-options-list */ +/* ### */ + +extern int tty_status; + +extern int tty_check(void); +extern int tty_waitputget(int); +extern int tty_ungetc(int); +extern int tty_getc(int); +extern int tty_get(char*,int,int); +extern int tty_putcheck(int); +extern int tty_putc(int); +extern int tty_put(char*,int); +extern int tty_putget(char**,int*,char**,int*); +extern void tty_flushout(void); +extern void tty_flushin(void); +extern void sendbrk(void); +extern int tty_resettimer(int tno); +extern void tty_resettimers(void); +extern int tty_settimer(int,int); +extern int tty_expired(int); +extern int tty_running(int); + +#endif diff --git a/mbcico/ulock.c b/mbcico/ulock.c new file mode 100644 index 00000000..06f2e5b1 --- /dev/null +++ b/mbcico/ulock.c @@ -0,0 +1,141 @@ +/***************************************************************************** + * + * File ..................: mbcico/ulock.c + * Purpose ...............: Fidonet mailer + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/clcomm.h" + +#ifndef LOCKDIR +#define LOCKDIR "/var/lock" +#endif + +#define LCKPREFIX LOCKDIR"/LCK.." +#define LCKTMP LOCKDIR"/TMP." + +#ifdef DONT_HAVE_PID_T +#define pid_t int +#endif + + + +int lock(char *line) +{ + pid_t mypid,rempid=0; + int tmppid; + char tmpname[256],lckname[256]; + char *p; + int i,rc; + FILE *f; + + rc=-1; + if ((p=strrchr(line,'/')) == NULL) + p=line; + else + p++; + mypid = getpid(); + sprintf(tmpname,"%s%d",LCKTMP,mypid); + if ((f = fopen(tmpname,"w")) == NULL) { + WriteError("$ulock: can't create %s",tmpname); + return(-1); + } + + fprintf(f,"%10d\n",mypid); + fclose(f); + chmod(tmpname,0444); + sprintf(lckname,"%s%s",LCKPREFIX,p); + p=lckname+strlen(lckname)-1; + *p=tolower(*p); + + for (i=0; (i++<5) && ((rc = link(tmpname, lckname)) != 0) && + (errno == EEXIST);) + { + if ((f=fopen(lckname,"r")) == NULL) { + Syslog('l', "$Can't open existing lock file"); + } else { + fscanf(f,"%d",&tmppid); + rempid=tmppid; + fclose(f); + Syslog('l', "lock: file read for process %d",rempid); + } + + if (kill(rempid,0) && (errno == ESRCH)) { + Syslog('l', "process inactive, unlink file"); + unlink(lckname); + } else { + Syslog('l', "process active, sleep a bit"); + sleep(2); + } + } + + if (rc) + Syslog('l', "$ulock: result %d (errno %d)",rc,errno); + unlink(tmpname); + return(rc); +} + + + +int ulock(char *line) +{ + pid_t mypid,rempid; + int tmppid; + char lckname[256]; + char *p; + int rc; + FILE *f; + + rc=-1; + if ((p=strrchr(line,'/')) == NULL) + p=line; + else + p++; + mypid=getpid(); + sprintf(lckname,"%s%s",LCKPREFIX,p); + p=lckname+strlen(lckname)-1; + *p=tolower(*p); + + if ((f=fopen(lckname,"r")) == NULL) + { + WriteError("$cannot open lock file %s",lckname); + return rc; + } + + fscanf(f,"%d",&tmppid); + rempid=tmppid; + fclose(f); + if (rempid == mypid) { + rc = unlink(lckname); + if (rc) + Syslog('l', "Unlock %s rc=%d", lckname, rc); + } + return(rc); +} + + diff --git a/mbcico/ulock.h b/mbcico/ulock.h new file mode 100644 index 00000000..0f25b4d3 --- /dev/null +++ b/mbcico/ulock.h @@ -0,0 +1,8 @@ +#ifndef _ULOCK_H +#define _ULOCK_H + +int lock(char *); +int ulock(char *); + +#endif + diff --git a/mbcico/wazoo.c b/mbcico/wazoo.c new file mode 100644 index 00000000..c26124ed --- /dev/null +++ b/mbcico/wazoo.c @@ -0,0 +1,128 @@ +/***************************************************************************** + * + * File ..................: mbcico/wazoo.c + * Purpose ...............: Fidonet mailer + * Last modification date : 01-Feb-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "respfreq.h" +#include "filelist.h" +#include "wazoo.h" +#include "zmodem.h" + + +extern int made_request; + + +int rxwazoo(void) +{ + int rc = 0; + fa_list *eff_remote, tmpl; + file_list *tosend = NULL, **tmpfl; + + Syslog('+', "Start WaZOO session"); + + if (emsi_remote_lcodes & LCODE_NPU) { + Syslog('+', "Remote requested \"no pickup\", no send"); + eff_remote=NULL; + } else if (emsi_remote_lcodes & LCODE_PUP) { + Syslog('+', "Remote requested \"pickup primary\""); + tmpl.addr = remote->addr; + tmpl.next = NULL; + eff_remote = &tmpl; + } else eff_remote=remote; + + tosend = create_filelist(eff_remote,(char *)ALL_MAIL,0); + + if ((rc = zmrcvfiles()) == 0) { + if ((emsi_local_opts & OPT_NRQ) == 0) { + for (tmpfl = &tosend; *tmpfl; tmpfl = &((*tmpfl)->next)); + *tmpfl = respond_wazoo(); + } + + if ((tosend != NULL) || ((emsi_remote_lcodes & LCODE_NPU) == 0)) + rc = zmsndfiles(tosend); + + if ((rc == 0) && (made_request)) { + Syslog('+', "Freq was made, trying to receive files"); + rc = zmrcvfiles(); + } + } + + tidy_filelist(tosend, (rc == 0)); + + if (rc) + WriteError("WaZOO session failed: rc=%d", rc); + else + Syslog('+', "WaZOO session completed"); + return rc; +} + + + +int txwazoo(void) +{ + int rc = 0; + file_list *tosend = NULL, *respond = NULL; + char *nonhold_mail; + + Syslog('+', "Start WaZOO session"); + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + if (emsi_remote_lcodes & LCODE_HAT) { + Syslog('+', "Remote asked to \"hold all traffic\", no send"); + tosend = NULL; + } else tosend = create_filelist(remote, nonhold_mail, 0); + + if ((tosend != NULL) || ((emsi_remote_lcodes & LCODE_NPU) == 0)) + rc = zmsndfiles(tosend); + if (rc == 0) + if ((rc = zmrcvfiles()) == 0) + if ((emsi_local_opts & OPT_NRQ) == 0) + if ((respond = respond_wazoo())) + rc = zmsndfiles(respond); + + tidy_filelist(tosend,(rc == 0)); + tidy_filelist(respond,0); + if (rc) + WriteError("WaZOO session failed: rc=%d", rc); + else + Syslog('+', "WaZOO session completed"); + return rc; +} + diff --git a/mbcico/wazoo.h b/mbcico/wazoo.h new file mode 100644 index 00000000..5e1a74f2 --- /dev/null +++ b/mbcico/wazoo.h @@ -0,0 +1,8 @@ +#ifndef _WAZOO_H +#define _WAZOO_H + +int rxwazoo(void); +int txwazoo(void); + +#endif + diff --git a/mbcico/xmrecv.c b/mbcico/xmrecv.c new file mode 100644 index 00000000..3c19f7ff --- /dev/null +++ b/mbcico/xmrecv.c @@ -0,0 +1,604 @@ +/***************************************************************************** + * + * File ..................: mbcico/xmrecv.c + * Purpose ...............: Fidonet mailer + * Last modification date : 04-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "ttyio.h" +#include "statetbl.h" +#include "config.h" +#include "lutil.h" +#include "openfile.h" +#include "m7recv.h" +#include "xmrecv.h" +#include "filetime.h" + + +#define XMBLKSIZ 128 + + +static int xm_recv(void); +static int resync(off_t); +static int closeit(int); + +static char *recvname=NULL; +static char *fpath=NULL; +static FILE *fp=NULL; +static int last; +static time_t stm,etm; +static off_t startofs; +static long recv_blk; + +extern unsigned long rcvdbytes; + + + +int xmrecv(char *Name) +{ + int rc; + + Syslog('+', "Xmodem start receive \"%s\"",MBSE_SS(Name)); + recvname = Name; + last = 0; + rc = xm_recv(); + if (fp) + closeit(0); + if (rc) + return -1; + else + if (last) + return 1; + else + return 0; +} + + + +int closeit(int success) +{ + off_t endofs; + + endofs = recv_blk*XMBLKSIZ; + (void)time(&etm); + if (etm == stm) + etm++; + Syslog('+', "Xmodem %s %lu bytes in %s (%lu cps)", success?"received":"dropped after", + (unsigned long)(endofs-startofs),str_time(etm-stm), (unsigned long)(endofs-startofs)/(etm-stm)); + rcvdbytes += (unsigned long)(endofs-startofs); + fp = NULL; + return closefile(success); +} + + + +SM_DECL(xm_recv,(char *)"xmrecv") +SM_STATES + sendnak0, + waitblk0, + sendnak, + waitblk, + recvblk, + sendack, + checktelink, + recvm7, + goteof +SM_NAMES + (char *)"sendnak0", + (char *)"waitblk0", + (char *)"sendnak", + (char *)"waitblk", + (char *)"recvblk", + (char *)"sendack", + (char *)"checktelink", + (char *)"recvm7", + (char *)"goteof" +SM_EDECL + + int tmp, i; + int SEAlink = FALSE, Slo = FALSE; + int crcmode = session_flags & FTSC_XMODEM_CRC; + int count=0,junk=0,cancount=0; + int header = 0; + struct _xmblk { + unsigned char n1,n2; + unsigned char data[XMBLKSIZ]; + unsigned char c1,c2; + } xmblk; + unsigned short localcrc,remotecrc; + unsigned char localcs,remotecs; + long ackd_blk=-1L; + long next_blk=1L; + long last_blk=0L; + off_t resofs; + char tmpfname[16]; + off_t wsize; + time_t remtime=0L; + off_t remsize=0; + int goteot = FALSE; + + Syslog('x', "xmrecv INIT"); + (void)time(&stm); + recv_blk=-1L; + + memset(&tmpfname, 0, sizeof(tmpfname)); + if (recvname) + strncpy(tmpfname,recvname,sizeof(tmpfname)-1); + +SM_START(sendnak0) + +SM_STATE(sendnak0) + + Syslog('x', "xmrecv SENDNAK0 count=%d mode=%s", count, crcmode?"crc":"cksum"); + if (count++ > 9) { + Syslog('+', "too many errors while xmodem receive init"); + SM_ERROR; + } + if ((ackd_blk < 0) && crcmode && (count > 5)) { + Syslog('x', "no responce to 'C', try checksum mode"); + session_flags &= ~FTSC_XMODEM_CRC; + crcmode = FALSE; + } + + if (crcmode) + PUTCHAR('C'); + else + PUTCHAR(NAK); + junk = 0; + SM_PROCEED(waitblk0); + +SM_STATE(waitblk0) + + Syslog('x', "xmrecv WAITBLK0"); + header = GETCHAR(5); + if (header == TIMEOUT) { + Syslog('x', "timeout waiting for xmodem block 0 header, count=%d", count); + if ((count > 2) && (session_flags & SESSION_IFNA)) { + Syslog('+', "Timeout waiting for file in WaZOO session, report success"); + last=1; + SM_SUCCESS; + } + SM_PROCEED(sendnak0); + } else if (header < 0) { + Syslog('x', "Error"); + SM_ERROR; + } else { + switch (header) { + case EOT: Syslog('x', "got EOT"); + Slo = FALSE; + if (ackd_blk == -1L) + last=1; + else { + ackd_blk++; + PUTCHAR(ACK); + if (SEAlink) { + PUTCHAR(ackd_blk); + PUTCHAR(~ackd_blk); + } + } + if (STATUS) { + SM_ERROR; + } + SM_SUCCESS; + break; + case CAN: Syslog('+', "Got CAN while xmodem receive init"); + SM_ERROR; + break; + case SOH: SEAlink = TRUE; + Syslog('x', "Got SOH, SEAlink mode"); + SM_PROCEED(recvblk); + break; + case SYN: SEAlink = FALSE; + Syslog('x', "Got SYN, Telink mode"); + SM_PROCEED(recvblk); + break; + case ACK: SEAlink = FALSE; + Syslog('x', "Got ACK, Modem7 mode"); + SM_PROCEED(recvm7); + break; + case TSYNC: Syslog('x', "Got TSYSNC char"); + SM_PROCEED(sendnak0); + break; + case NAK: + case 'C': Syslog('x', "Got %s waiting for block 0, sending EOT", printablec(header)); + PUTCHAR(EOT); /* other end still waiting us to send? */ + SM_PROCEED(waitblk0); + break; + default: Syslog('x', "Got '%s' waiting for block 0", printablec(header)); + if (junk++ > 300) { + SM_PROCEED(sendnak0); + } else { + SM_PROCEED(waitblk0); + } + break; + } + } + +SM_STATE(sendnak) + + Syslog('x', "xmrecv SENDNAK"); + if (ackd_blk < 0) { + SM_PROCEED(sendnak0); + } + + if (count++ > 9) { + Syslog('+', "too many errors while xmodem receive"); + SM_ERROR; + } + + junk = 0; + + if (remote_flags & FTSC_XMODEM_RES) { + if (resync(ackd_blk*XMBLKSIZ)) { + SM_ERROR; + } else { + SM_PROCEED(waitblk); + } + } else { /* simple NAK */ + Syslog('x', "negative acknowlege block %ld",ackd_blk+1); + + if (crcmode) + PUTCHAR('C'); + else + PUTCHAR(NAK); + if (SEAlink) { + PUTCHAR(ackd_blk+1); + PUTCHAR(~(ackd_blk+1)); + } + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitblk); + } + } + +SM_STATE(sendack) + + Syslog('x', "xmrecv SENDACK block=%d", recv_blk); + ackd_blk = recv_blk; + count = 0; + cancount = 0; + + PUTCHAR(ACK); + if (SEAlink) { + PUTCHAR(ackd_blk); + PUTCHAR(~ackd_blk); + } + if (STATUS) { + SM_ERROR; + } + if (goteot) { + SM_SUCCESS; + } + SM_PROCEED(waitblk); + +SM_STATE(waitblk) + + Syslog('x', "xmrecv WAITBLK"); + header = GETCHAR(15); + if (header == TIMEOUT) { + Syslog('x', "timeout waiting for xmodem block header, count=%d", count); + SM_PROCEED(sendnak); + } else if (header < 0) { + SM_ERROR; + } else { + switch (header) { + case EOT: if (last_blk && (ackd_blk != last_blk)) { + Syslog('x', "false EOT after %ld block, need after %ld", ackd_blk,last_blk); + SM_PROCEED(waitblk); + } else { + SM_PROCEED(goteof); + } + break; + case CAN: if (cancount++ > 4) { + closeit(0); + Syslog('+', "Got CAN while xmodem receive"); + SM_ERROR; + } else { + SM_PROCEED(waitblk); + } + break; + case SOH: SM_PROCEED(recvblk); + break; + default: Syslog('x', "got '%s' waiting SOH", printablec(header)); + if (junk++ > 200) { + SM_PROCEED(sendnak); + } else { + SM_PROCEED(waitblk); + } + break; + } + } + +SM_STATE(recvblk) + + Syslog('x', "xmrecv RECVBLK"); + Nopper(); + GET((char*)&xmblk,(crcmode && (header != SYN))? sizeof(xmblk): sizeof(xmblk)-1,15); + if (STATUS == STAT_TIMEOUT) { + Syslog('x', "xmrecv timeout waiting for block body"); + SM_PROCEED(sendnak); + } + if (STATUS) { + SM_ERROR; + } + if ((xmblk.n1 & 0xff) != ((~xmblk.n2) & 0xff)) { + Syslog('x', "bad block number: 0x%02x/0x%02x (0x%02x)", xmblk.n1,xmblk.n2,(~xmblk.n2)&0xff); + SM_PROCEED(waitblk); + } + recv_blk = xmblk.n1 + (ackd_blk & ~0xff); + if (abs(recv_blk - ackd_blk) > 128) + recv_blk += 256; + + if (crcmode && (header != SYN)) { + remotecrc = (short)xmblk.c1 << 8 | xmblk.c2; + localcrc = crc16xmodem(xmblk.data, sizeof(xmblk.data)); + if (remotecrc != localcrc) { + Syslog('x', "bad crc: 0x%04x/0x%04x",remotecrc,localcrc); + if (recv_blk == (ackd_blk+1)) { + SM_PROCEED(sendnak); + } else { + SM_PROCEED(waitblk); + } + } + } else { + remotecs = xmblk.c1; + localcs = checksum(xmblk.data, sizeof(xmblk.data)); + if (remotecs != localcs) { + Syslog('x', "bad checksum: 0x%02x/0x%02x",remotecs,localcs); + if (recv_blk == (ackd_blk+1)) { + SM_PROCEED(sendnak); + } else { + SM_PROCEED(waitblk); + } + } + } + if ((ackd_blk == -1L) && (recv_blk == 0L)) { + SM_PROCEED(checktelink); + } + if ((ackd_blk == -1L) && (recv_blk == 1L)) { + if (count < 3) { + SM_PROCEED(sendnak0); + } else + ackd_blk=0L; + } + if (recv_blk < (ackd_blk+1L)) { + Syslog('x', "old block number %ld after %ld, go on", recv_blk,ackd_blk); + SM_PROCEED(waitblk); + } else if (recv_blk > (ackd_blk+1L)) { + Syslog('x', "bad block order: %ld after %ld, go on", recv_blk,ackd_blk); + SM_PROCEED(waitblk); + } + + Syslog('X', "received block %ld \"%s\"", recv_blk,printable(xmblk.data,128)); + + if (fp == NULL) { + if ((fp = openfile(tmpfname,remtime,remsize,&resofs,resync)) == NULL) { + SM_ERROR; + } else { + if (resofs) + ackd_blk=(resofs-1)/XMBLKSIZ+1L; + else + ackd_blk=-1L; + } + startofs=resofs; + Syslog('+', "Xmodem receive: \"%s\"",tmpfname); + } + + if (recv_blk > next_blk) { + WriteError("xmrecv internal error: recv_blk %ld > next_blk %ld", recv_blk,next_blk); + SM_ERROR; + } + if (recv_blk == next_blk) { + if (recv_blk == last_blk) + wsize=remsize%XMBLKSIZ; + else + wsize=XMBLKSIZ; + if (wsize == 0) + wsize=XMBLKSIZ; + if ((tmp = fwrite(xmblk.data,wsize,1,fp)) != 1) { + WriteError("$error writing block %l (%d bytes) to file \"%s\" (fwrite return %d)", + recv_blk,wsize,fpath,tmp); + SM_ERROR; + } else + Syslog('x', "Block %ld size %d written (ret %d)", recv_blk,wsize,tmp); + next_blk++; + } else { + Syslog('x', "recv_blk %ld < next_blk %ld, ack without writing", recv_blk,next_blk); + } + SM_PROCEED(sendack); + +SM_STATE(checktelink) + + Syslog('x', "xmrecv CHECKTELINK"); + Syslog('X', "checktelink got \"%s\"",printable(xmblk.data,45)); + if (tmpfname[0] == '\0') { + strncpy(tmpfname,xmblk.data+8,16); + /* + * Some systems fill the rest of the filename with spaces, sigh. + */ + for (i = 16; i; i--) { + if ((tmpfname[i] == ' ') || (tmpfname[i] == '\0')) + tmpfname[i] = '\0'; + else + break; + } + } else { + Syslog('+', "Remote uses %s",printable(xmblk.data+25,-14)); + Syslog('X', "Remote file name \"%s\" discarded", printable(xmblk.data+8,-16)); + } + remsize = ((off_t)xmblk.data[0]) + ((off_t)xmblk.data[1]<<8) + ((off_t)xmblk.data[2]<<16) + ((off_t)xmblk.data[3]<<24); + last_blk = (remsize-1)/XMBLKSIZ+1; + if (header == SOH) { + /* + * SEAlink block + */ + remtime=sl2mtime(((time_t)xmblk.data[4])+ ((time_t)xmblk.data[5]<<8)+ + ((time_t)xmblk.data[6]<<16)+ ((time_t)xmblk.data[7]<<24)); + if (xmblk.data[40]) { + Slo = TRUE; + remote_flags |= FTSC_XMODEM_SLO; + } else + remote_flags &= ~FTSC_XMODEM_SLO; + if (xmblk.data[41]) + remote_flags |= FTSC_XMODEM_RES; + else + remote_flags &= ~FTSC_XMODEM_RES; + if (xmblk.data[42]) + remote_flags |= FTSC_XMODEM_XOF; + else + remote_flags &= ~FTSC_XMODEM_XOF; + } else if (header == SYN) { + /* + * Telink block + */ + remtime=tl2mtime(((time_t)xmblk.data[4])+ ((time_t)xmblk.data[5]<<8)+ + ((time_t)xmblk.data[6]<<16)+ ((time_t)xmblk.data[7]<<24)); + if (xmblk.data[41]) + session_flags |= FTSC_XMODEM_CRC; + else + session_flags &= ~FTSC_XMODEM_CRC; + } else { + WriteError("Got data block with header 0x%02x", header); + SM_PROCEED(sendnak0); + } + + Syslog('x', "%s block, session_flags=0x%04x, remote_flags=0x%04x", + (header == SYN)?"Telink":"Sealink",session_flags,remote_flags); + + if ((fp = openfile(tmpfname,remtime,remsize,&resofs,resync)) == NULL) { + SM_ERROR; + } + if (resofs) + ackd_blk=(resofs-1)/XMBLKSIZ+1L; + else + ackd_blk=-1L; + startofs=resofs; + + Syslog('+', "Xmodem %s receive: \"%s\" %ld bytes dated %s", (header == SYN)?"Telink":"Sealink", + tmpfname, remsize, rfcdate(remtime)); + + if (ackd_blk == -1) { + SM_PROCEED(sendack); + } else { + SM_PROCEED(waitblk); + } + +SM_STATE(recvm7) + + Syslog('x', "xmrecv RECVM7"); + switch (m7recv(tmpfname)) { + case 0: ackd_blk=0; + SM_PROCEED(sendnak); + break; + case 1: last=1; + SM_SUCCESS; + break; + default: SM_PROCEED(sendnak); + } + +SM_STATE(goteof) + + Syslog('x', "xmrecv GOTEOF"); + Slo = FALSE; + closeit(1); + if (ackd_blk == -1L) + last=1; + else { + ackd_blk++; + PUTCHAR(ACK); + if (SEAlink) { + PUTCHAR(ackd_blk); + PUTCHAR(~ackd_blk); + } + } + if (STATUS) { + SM_ERROR; + } + SM_SUCCESS; + +SM_END +SM_RETURN + + + +int resync(off_t resofs) +{ + char resynbuf[16]; + short lcrc; + int count=0; + int gotack,gotnak; + int c; + long sblk; + + Syslog('x', "trying to resync at offset %ld",resofs); + + sblk=resofs/XMBLKSIZ+1; + sprintf(resynbuf,"%ld",sblk); + lcrc=crc16xmodem(resynbuf,strlen(resynbuf)); + gotack=0; + gotnak=0; + + do { + count++; + PUTCHAR(SYN); + PUTSTR(resynbuf); + PUTCHAR(ETX); + PUTCHAR(lcrc&0xff); + PUTCHAR(lcrc>>8); + do { + if ((c=GETCHAR(5)) == ACK) { + if ((c=GETCHAR(1)) == SOH) + gotack=1; + UNGETCHAR(c); + } else if (c == NAK) { + if ((c=GETCHAR(1)) == TIMEOUT) + gotnak=1; + UNGETCHAR(c); + } + } + while (!gotack && !gotnak && (c >= 0)); + if ((c < 0) && (c != TIMEOUT)) + return 1; + } + while (!gotack && !gotnak && (count < 6)); + + if (gotack) { + Syslog('x', "resyncing at offset %ld",resofs); + return 0; + } else { + Syslog('+', "sealink resync at offset %ld failed",resofs); + return 1; + } +} + + diff --git a/mbcico/xmrecv.h b/mbcico/xmrecv.h new file mode 100644 index 00000000..18b70e16 --- /dev/null +++ b/mbcico/xmrecv.h @@ -0,0 +1,7 @@ +#ifndef _XMRECV_H +#define _XMRECV_H + +int xmrecv(char *); + +#endif + diff --git a/mbcico/xmsend.c b/mbcico/xmsend.c new file mode 100644 index 00000000..a2d87974 --- /dev/null +++ b/mbcico/xmsend.c @@ -0,0 +1,523 @@ +/***************************************************************************** + * + * File ..................: mbcico/xmsend.c + * Purpose ...............: Fidonet mailer + * Last modification date : 04-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "ttyio.h" +#include "statetbl.h" +#include "xmsend.h" +#include "m7send.h" +#include "filelist.h" +#include "filetime.h" + + +#define XMBLKSIZ 128 +#define DEFAULT_WINDOW 127 + + +static char *ln,*rn; +static int flg; +static int xm_send(void); + +extern unsigned long sentbytes; + + +int xmsend(char *local, char *Remote, int fl) +{ + int rc; + + ln=local; + rn=Remote; + flg=fl; + rc=xm_send(); + if (rc) + Syslog('+', "xmsend failed"); + return rc; +} + + + +SM_DECL(xm_send,(char *)"xmsend") +SM_STATES + sendm7, + sendblk0, + waitack0, + sendblk, + writeblk, + waitack, + resync, + sendeot +SM_NAMES + (char *)"sendm7", + (char *)"sendblk0", + (char *)"waitack0", + (char *)"sendblk", + (char *)"writeblk", + (char *)"waitack", + (char *)"resync", + (char *)"sendeot" +SM_EDECL + + FILE *fp; + struct stat st; + struct flock fl; + unsigned short lcrc=0,rcrc; + int startstate; + int crcmode,seamode,telink; + int a,a1,a2; + int i; + time_t seatime; + time_t stm,etm; + unsigned char header=SOH; + struct _xmblk { + unsigned char n1; + unsigned char n2; + char data[XMBLKSIZ]; + unsigned char c1; + unsigned char c2; + } xmblk; + int count=0; + int cancount=0; + int window; + long last_blk; + long send_blk; + long next_blk; + long ackd_blk; + long tmp; + char resynbuf[16]; + + fl.l_type=F_RDLCK; + fl.l_whence=0; + fl.l_start=0L; + fl.l_len=0L; + + Syslog('x', "xmsend INIT"); + (void)time(&stm); + + /* if we got 'C' than hopefully remote is sealink capable... */ + + if (session_flags & FTSC_XMODEM_CRC) { + telink=0; + crcmode=1; + session_flags |= FTSC_XMODEM_RES; + session_flags |= FTSC_XMODEM_SLO; + session_flags |= FTSC_XMODEM_XOF; + window=DEFAULT_WINDOW; + send_blk=0L; + next_blk=0L; + ackd_blk=-1L; + startstate=sendblk0; + } else { + telink=1; + crcmode=0; + session_flags &= ~FTSC_XMODEM_RES; + session_flags |= FTSC_XMODEM_SLO; + session_flags |= FTSC_XMODEM_XOF; + window=1; + send_blk=0L; + next_blk=0L; + ackd_blk=-1L; + if (flg && !(session_flags & SESSION_IFNA)) + startstate = sendm7; + else + startstate = sendblk0; + } + + seamode=-1; /* not yet sure about numbered ACKs */ + + if (stat(ln,&st) != 0) { + WriteError("$cannot stat local file \"%s\" to send",MBSE_SS(ln)); + return 1; + } + last_blk=(st.st_size-1)/XMBLKSIZ+1; + + if ((fp=fopen(ln,"r")) == NULL) { + WriteError("$cannot open local file \"%s\" to send",MBSE_SS(ln)); + return 1; + } + fl.l_pid = getpid(); + if (fcntl(fileno(fp),F_SETLK,&fl) != 0) { + WriteError("$cannot lock local file \"%s\" to send, skip it",MBSE_SS(ln)); + return 0; + } + if (stat(ln,&st) != 0) { + WriteError("$cannot access local file \"%s\" to send, skip it",MBSE_SS(ln)); + return 0; + } + + Syslog('+', "Xmodem send \"%s\" as \"%s\", size=%lu", MBSE_SS(ln),MBSE_SS(rn),(unsigned long)st.st_size); + sentbytes += (unsigned long)st.st_size; + +SM_START(startstate) + +SM_STATE(sendm7) + + Syslog('x', "xmsend SENDM7"); + if (m7send(rn)) { + SM_PROCEED(sendblk0); + } else { + SM_ERROR; + } + +SM_STATE(sendblk0) + + Syslog('X', "xmsend SENDBLK0"); + Syslog('x', "xmsendblk0 send:%ld, next:%ld, ackd:%ld, last:%ld", send_blk,next_blk,ackd_blk,last_blk); + + memset(xmblk.data,0,sizeof(xmblk.data)); + + xmblk.data[0]=(st.st_size)&0xff; + xmblk.data[1]=(st.st_size>>8)&0xff; + xmblk.data[2]=(st.st_size>>16)&0xff; + xmblk.data[3]=(st.st_size>>24)&0xff; + seatime=mtime2sl(st.st_mtime); + xmblk.data[4]=(seatime)&0xff; + xmblk.data[5]=(seatime>>8)&0xff; + xmblk.data[6]=(seatime>>16)&0xff; + xmblk.data[7]=(seatime>>24)&0xff; + strncpy(xmblk.data+8,rn,17); + if (telink) + for (i=23;(i>8) && (xmblk.data[i] == '\0');i--) + xmblk.data[i]=' '; + sprintf(xmblk.data+25,"mbcico %s",VERSION); + xmblk.data[40]=((session_flags & FTSC_XMODEM_SLO) != 0); + xmblk.data[41]=((session_flags & FTSC_XMODEM_RES) != 0); + xmblk.data[42]=((session_flags & FTSC_XMODEM_XOF) != 0); + + Syslog('X', "sealink block: \"%s\"",printable(xmblk.data,44)); + + next_blk=send_blk+1; + SM_PROCEED(sendblk); + +SM_STATE(sendblk) + + Syslog('X', "xmsend SENDBLK %d", send_blk); + if (send_blk == 0) { + SM_PROCEED(writeblk); + } + + Syslog('x', "xmsendblk send:%ld, next:%ld, ackd:%ld, last:%ld", send_blk,next_blk,ackd_blk,last_blk); + + if (send_blk > last_blk) { + Syslog('X', "send_blk > last_blk"); + if (send_blk == (last_blk+1)) { + SM_PROCEED(sendeot); + } else if (ackd_blk < last_blk) { + SM_PROCEED(waitack); + } else { + (void)time(&etm); + if (etm == stm) + etm++; + Syslog('+', "sent %lu bytes in %s (%lu cps)", (unsigned long)st.st_size,str_time(etm-stm), + (unsigned long)st.st_size/(etm-stm)); + sentbytes += (unsigned long)st.st_size; + fclose(fp); + SM_SUCCESS; + } + } + + memset(xmblk.data, SUB, sizeof(xmblk.data)); + + if (send_blk != next_blk) + if (fseek(fp,(send_blk-1)*XMBLKSIZ,SEEK_SET) != 0) { + WriteError("$fseek error setting block %ld (byte %lu) in file \"%s\"", + send_blk,(send_blk-1)*XMBLKSIZ,MBSE_SS(ln)); + SM_ERROR; + } + if (fread(xmblk.data,1,XMBLKSIZ,fp) <= 0) { + WriteError("$read error for block %lu in file \"%s\"", send_blk,MBSE_SS(ln)); + SM_ERROR; + } + next_blk=send_blk+1; + + SM_PROCEED(writeblk); + +SM_STATE(writeblk) + + Syslog('X', "xmsend WRITEBLK"); + Nopper(); + xmblk.n1=send_blk&0xff; + xmblk.n2=~xmblk.n1; + if (crcmode) { + lcrc=crc16xmodem(xmblk.data,sizeof(xmblk.data)); + xmblk.c1=(lcrc>>8)&0xff; + xmblk.c2=lcrc&0xff; + } else { + xmblk.c1=checksum(xmblk.data,sizeof(xmblk.data)); + } + + PUTCHAR(header); + PUT((char*)&xmblk,crcmode?sizeof(xmblk):sizeof(xmblk)-1); + if (STATUS) { + SM_ERROR; + } + if (crcmode) + Syslog('x', "sent '0x%02x',no 0x%02x, %d bytes crc 0x%04x", header, xmblk.n1, XMBLKSIZ, lcrc); + else + Syslog('x', "sent '0x%02x',no 0x%02x, %d bytes checksum 0x%02x", header, xmblk.n1, XMBLKSIZ, xmblk.c1); + send_blk++; + SM_PROCEED(waitack); + +SM_STATE(waitack) + + Syslog('x', "xmsend WAITACK"); + if ((count > 4) && (ackd_blk < 0)) { + Syslog('+', "Cannot send sealink block, try xmodem"); + window=1; + ackd_blk++; + SM_PROCEED(sendblk); + } + if (count > 9) { + Syslog('+', "Too many errors in xmodem send"); + SM_ERROR; + } + + if (!((ackd_blk < 0) || (send_blk > (last_blk+1)) || ((send_blk-ackd_blk) > window))) { + if ((WAITPUTGET(0) & 3) == 2) { + SM_PROCEED(sendblk); + } + } + + a = GETCHAR(20); + Syslog('X', "xmsend got 0x%02x", a); + if (a == TIMEOUT) { + if (count++ > 9) { + Syslog('+', "too many tries to send block"); + SM_ERROR; + } + Syslog('x', "timeout waiting for ACK"); + send_blk=ackd_blk+1; + SM_PROCEED(sendblk); + } else if (a < 0) { + SM_ERROR; + } else switch (a) { + case ACK: + Syslog('x', "got ACK seamode=%d", seamode); + count=0; + cancount=0; + switch (seamode) { + case -1:if ((a1=GETCHAR(1)) < 0) { + seamode=0; + UNGETCHAR(a); + SM_PROCEED(waitack); + } else if ((a2=GETCHAR(1)) < 0) { + seamode=0; + UNGETCHAR(a1); + UNGETCHAR(a); + SM_PROCEED(waitack); + } else if ((a1&0xff) != ((~a2)&0xff)) { + seamode=0; + UNGETCHAR(a2); + UNGETCHAR(a1); + UNGETCHAR(a); + SM_PROCEED(waitack); + } else { + seamode=1; + UNGETCHAR(a2); + UNGETCHAR(a1); + UNGETCHAR(a); + SM_PROCEED(waitack); + } + break; + case 0: + ackd_blk++; + SM_PROCEED(sendblk); + break; + case 1: + a1=GETCHAR(1); + a2=GETCHAR(1); + Syslog('X', "got block ACK %d", a1); + if ((a1 < 0) || (a2 < 0) || (a1 != ((~a2)&0xff))) { + Syslog('x', "bad ACK: 0x%02x/0x%02x, ignore", a1,a2); + SM_PROCEED(sendblk); + } else { + if (a1 == ((send_blk-1) & 0xff)) { + /* FD seems only to ACK last received block which is allright, 31-12-2000 MB. */ + Syslog('x', "got ACK %d", a1); + } else if (a1 != ((ackd_blk+1) & 0xff)) { + Syslog('x', "got ACK %d, expected %d", a1,(ackd_blk+1)&0xff); + ackd_blk++; + } + tmp=send_blk-((send_blk-a1)&0xff); + if ((tmp > ackd_blk) && (tmp < send_blk)) + ackd_blk=tmp; + else + Syslog('x', "bad ACK: %ld, ignore", a1,a2); + if ((ackd_blk+1) == send_blk) { + SM_PROCEED(sendblk); + } else { /* read them all if more than 1 */ + SM_PROCEED(waitack); + } + } + break; + } + break; + case NAK: if (ackd_blk <= 0) + crcmode=0; + count++; + send_blk=ackd_blk+1; + SM_PROCEED(sendblk); + break; + case SYN: SM_PROCEED(resync); + break; + case DC3: if (session_flags & FTSC_XMODEM_XOF) { + while (((a=GETCHAR(15)) > 0) && (a != DC1)) + Syslog('x', "got '%s' waiting for DC1", printablec(a)); + } + SM_PROCEED(waitack); + break; + case CAN: if (cancount++ > 5) { + Syslog('+', "Remote requested cancel transfer"); + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + break; + case 'C': if (ackd_blk < 0) { + crcmode=1; + count++; + send_blk=ackd_blk+1; + SM_PROCEED(sendblk); + } + /* fallthru */ + default: Syslog('x', "Got '%s' waiting for ACK",printablec(a)); + SM_PROCEED(waitack); + break; + } + +SM_STATE(resync) + + Syslog('x', "xmsend RESYNC"); + if (count++ > 9) { + Syslog('+', "too may tries to resync"); + SM_ERROR; + } + + i=-1; + do { + a=GETCHAR(15); + resynbuf[++i]=a; + } + while ((a >= '0') && (a <= '9') && (i < sizeof(resynbuf)-1)); + resynbuf[i]='\0'; + Syslog('x', "got resync \"%s\", i=%d",resynbuf,i); + lcrc=crc16xmodem(resynbuf,strlen(resynbuf)); + rcrc=0; + if (a != ETX) { + if (a > 0) + Syslog('+', "Got %d waiting for resync",a); + else + Syslog('+', "Got %s waiting for resync",printablec(a)); + PUTCHAR(NAK); + SM_PROCEED(waitack); + } + if ((a=GETCHAR(1)) < 0) { + PUTCHAR(NAK); + SM_PROCEED(waitack); + } + rcrc=a&0xff; + if ((a=GETCHAR(1)) < 0) { + PUTCHAR(NAK); + SM_PROCEED(waitack); + } + rcrc |= (a << 8); + if (rcrc != lcrc) { + Syslog('+', "Bad resync crc: 0x%04x != 0x%04x",lcrc,rcrc); + PUTCHAR(NAK); + SM_PROCEED(waitack); + } + send_blk=atol(resynbuf); + ackd_blk=send_blk-1; + Syslog('+', "Resyncing at block %ld (byte %lu)", send_blk,(send_blk-1L)*XMBLKSIZ); + PUTCHAR(ACK); + SM_PROCEED(sendblk); + +SM_STATE(sendeot) + + Syslog('x', "xmsend SENDEOT"); + PUTCHAR(EOT); + if (STATUS) { + SM_ERROR; + } + send_blk++; + SM_PROCEED(waitack); + +SM_END +SM_RETURN + + + +int xmsndfiles(file_list *tosend) +{ + int rc,c = 0,gotnak,count; + file_list *nextsend; + + Syslog('x', "Xmodem send files start"); + for (nextsend=tosend;nextsend;nextsend=nextsend->next) { + if (*(nextsend->local) != '~') { + if (nextsend->remote) { + if ((rc=xmsend(nextsend->local,nextsend->remote, (nextsend != tosend)))) {/* send m7 for rest */ + Syslog('x', "Xmodem send files failed, rc=%d", rc); + return rc; /* and thus avoid execute_disposition() */ + } else { + gotnak=0; + count=0; + while (!gotnak && (count < 6)) { + c=GETCHAR(15); + if (c < 0) + return STATUS; + if (c == CAN) { + Syslog('+', "Remote refused receiving"); + return 1; + } + if ((c == 'C') || (c == NAK)) + gotnak=1; + else + Syslog('x', "Got '%s' waiting NAK", printablec(c)); + } + if (c == 'C') + session_flags |= FTSC_XMODEM_CRC; + if (!gotnak) + return 1; + } + } + execute_disposition(nextsend); + } + } + Syslog('x', "Xmodem send files finished"); + PUTCHAR(EOT); + return STATUS; +} + + diff --git a/mbcico/xmsend.h b/mbcico/xmsend.h new file mode 100644 index 00000000..7140f13e --- /dev/null +++ b/mbcico/xmsend.h @@ -0,0 +1,9 @@ +#ifndef _XMSEND_H +#define _XMSEND_H + +int xmsend(char *, char *, int); +int xmsndfiles(file_list *); + + +#endif + diff --git a/mbcico/yoohoo.c b/mbcico/yoohoo.c new file mode 100644 index 00000000..900d9b7b --- /dev/null +++ b/mbcico/yoohoo.c @@ -0,0 +1,637 @@ +/***************************************************************************** + * + * File ..................: mbcico/yoohoo.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* Added modifications made on 9 Jun 1996 by P.Saratxaga + * - added "Hello" structure (from FTS-0006) so we can more easily + * parse it. + * - added domain support in hello packet (in Hello.name, reading after + * first \0 there is the domain) + * - added support for 16 bit product code + */ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "statetbl.h" +#include "ttyio.h" +#include "session.h" +#include "config.h" +#include "emsi.h" +#include "hydra.h" +#include "rdoptions.h" +#include "wazoo.h" +#include "dietifna.h" +#include "yoohoo.h" + + +/*------------------------------------------------------------------------*/ +/* YOOHOO CAPABILITY VALUES */ +/*------------------------------------------------------------------------*/ +#define Y_DIETIFNA 0x0001 /* Can do fast "FTS-0001" 0000 0000 0000 0001 */ +#define FTB_USER 0x0002 /* Full-Tilt Boogie 0000 0000 0000 0010 */ +#define ZED_ZIPPER 0x0004 /* Does ZModem, 1K blocks 0000 0000 0000 0100 */ +#define ZED_ZAPPER 0x0008 /* Can do ZModem variant 0000 0000 0000 1000 */ +#define DOES_IANUS 0x0010 /* Can do Janus 0000 0000 0001 0000 */ +#define DOES_HYDRA 0x0020 /* Can do Hydra 0000 0000 0010 0000 */ +#define Bit_6 0x0040 /* reserved by FTSC 0000 0000 0100 0000 */ +#define Bit_7 0x0080 /* reserved by FTSC 0000 0000 1000 0000 */ +#define Bit_8 0x0100 /* reserved by FTSC 0000 0001 0000 0000 */ +#define Bit_9 0x0200 /* reserved by FTSC 0000 0010 0000 0000 */ +#define Bit_a 0x0400 /* reserved by FTSC 0000 0100 0000 0000 */ +#define Bit_b 0x0800 /* reserved by FTSC 0000 1000 0000 0000 */ +#define Bit_c 0x1000 /* reserved by FTSC 0001 0000 0000 0000 */ +#define Bit_d 0x2000 /* reserved by FTSC 0010 0000 0000 0000 */ +#define DO_DOMAIN 0x4000 /* Packet contains domain 0100 0000 0000 0000 */ +#define WZ_FREQ 0x8000 /* WZ file req. ok 1000 0000 0000 0000 */ + +#define LOCALCAPS (Y_DIETIFNA|ZED_ZIPPER|ZED_ZAPPER|DOES_HYDRA|DO_DOMAIN) + + +static int rxyoohoo(void); +static int txyoohoo(void); +static void fillhello(unsigned short,char*); +static int checkhello(void); + +static int iscaller; +static struct _hello { + unsigned char data[128]; + unsigned char crc[2]; +} hello; + +typedef struct _Hello { + unsigned short signal; /* always 'o' (0x6f) */ + unsigned short hello_version; /* currently 1 (0x01) */ + unsigned short product; /* product code */ + unsigned short product_maj; /* major revision of the product */ + unsigned short product_min; /* minor revision of the product */ + unsigned char my_name[60]; /* Other end's name, will include domain */ + /* if DO_DOMAIN is set in capabilities */ + unsigned char sysop[20]; /* sysop's name */ + unsigned short my_zone; /* 0== not supported */ + unsigned short my_net; /* out primary net number */ + unsigned short my_node; /* our primary node number */ + unsigned short my_point; /* 0 == not supported */ + unsigned char my_password[8]; /* This isn't necessarily null-terminated */ + unsigned char reserved2[8]; /* reserved by Opus */ + unsigned short capabilities; /* see below */ + unsigned char reserved3[12]; /* for non-Opus systems with "approval" */ + /* total size 128 bytes */ +} Hello; + + +extern int Loaded; + +Hello hello2; +Hello gethello2(unsigned char[]); + + + +int rx_yoohoo(void) +{ + int rc; + unsigned short capabilities,localcaps; + char *pwd = NULL; + + Syslog('+', "Start inbound YooHoo session"); + + pwd = NULL; + localcaps = LOCALCAPS; + if (localoptions & NOZMODEM) localcaps &= ~(ZED_ZAPPER|ZED_ZIPPER); + if (localoptions & NOZEDZAP) localcaps &= ~ZED_ZAPPER; + if (localoptions & NOHYDRA) localcaps &= ~DOES_HYDRA; + emsi_local_opts = 0; + emsi_remote_opts = 0; + iscaller = 0; + + if ((rc = rxyoohoo()) == 0) { + Loaded = checkhello(); + capabilities = hello2.capabilities; + if (capabilities & WZ_FREQ) + session_flags |= SESSION_WAZOO; + else + session_flags &= ~SESSION_WAZOO; + localcaps &= capabilities; + if (localcaps & DOES_HYDRA) + localcaps &= DOES_HYDRA; + else if (localcaps & ZED_ZAPPER) + localcaps &= ZED_ZAPPER; + else if (localcaps & ZED_ZIPPER) + localcaps &= ZED_ZIPPER; + else if (localcaps & FTB_USER) + localcaps &= FTB_USER; + else if (localcaps & Y_DIETIFNA) + localcaps &= Y_DIETIFNA; + if ((localoptions & NOFREQS) == 0) + localcaps |= WZ_FREQ; + else + emsi_local_opts |= OPT_NRQ; + + if (((nlent=getnlent(remote->addr))) && (nlent->pflag != NL_DUMMY)) { + Syslog('+', "Remote is a listed system"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); + sprintf(history.location, "%s", nlent->location); + } + if (nlent) + rdoptions(Loaded); + + if (strlen(nodes.Epasswd)) { + if ((strncasecmp((char*)hello2.my_password, nodes.Epasswd, strlen(nodes.Epasswd)) == 0) && + (strlen((char*)hello2.my_password) == strlen(nodes.Epasswd))) { + Syslog('+', "Password correct, protected mail session"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); + pwd = xstrcpy(nodes.Epasswd); + } else { + pwd = (char *)"BAD_PASS"; + Syslog('?', "Remote password \"%s\", expected \"%s\"", (char*)hello2.my_password, nodes.Epasswd); + localcaps = 0; + } + } else + Syslog('s', "No YooHoo password check"); + fillhello(localcaps,pwd); + + rc = txyoohoo(); + if (pwd) + free(pwd); + } + + if ((rc == 0) && ((localcaps & LOCALCAPS) == 0)) { + Syslog('+', "No common protocols or bad password"); + return 0; + } + if (rc) + return rc; + + IsDoing("Inbound %s", ascfnode(remote->addr, 0x0f)); + + session_flags |= SESSION_WAZOO; + if (localcaps & DOES_HYDRA) + return hydra(0); + else if ((localcaps & ZED_ZAPPER) || (localcaps & ZED_ZIPPER)) { + if (localcaps & ZED_ZAPPER) + emsi_local_protos = PROT_ZAP; + else + emsi_local_protos = PROT_ZMO; + return rxwazoo(); + } else if (localcaps & Y_DIETIFNA) + return rxdietifna(); + else + WriteError("YooHoo internal error - no proto for 0x%04xh",localcaps); + return 1; +} + + + +int tx_yoohoo(void) +{ + int rc; + unsigned short capabilities; + char *pwd; + + Syslog('+', "Start outbound YooHoo session"); + + if (strlen(nodes.Epasswd)) + pwd = xstrcpy(nodes.Epasswd); + else + pwd = NULL; + + capabilities = LOCALCAPS; + if (localoptions & NOZMODEM) + capabilities &= ~(ZED_ZAPPER|ZED_ZIPPER); + if (localoptions & NOZEDZAP) + capabilities &= ~ZED_ZAPPER; + if (localoptions & NOHYDRA) + capabilities &= ~DOES_HYDRA; + if ((localoptions & NOFREQS) == 0) + capabilities |= WZ_FREQ; + else + emsi_local_opts |= OPT_NRQ; + + fillhello(capabilities,pwd); + iscaller=1; + + if ((rc = txyoohoo()) == 0) { + rc = rxyoohoo(); + checkhello(); + capabilities = hello2.capabilities; + if (capabilities & WZ_FREQ) + session_flags |= SESSION_WAZOO; + else + session_flags &= ~SESSION_WAZOO; + } + + if ((rc == 0) && ((capabilities & LOCALCAPS) == 0)) { + Syslog('+', "No common protocols"); + return 0; + } + + if (rc) + return rc; + + IsDoing("Outbound %s", ascfnode(remote->addr, 0x0f)); + + session_flags |= SESSION_WAZOO; + if (capabilities & DOES_HYDRA) + return hydra(1); + else if ((capabilities & ZED_ZAPPER) || (capabilities & ZED_ZIPPER)) { + if (capabilities & ZED_ZAPPER) + emsi_local_protos = PROT_ZAP; + else + emsi_local_protos = PROT_ZMO; + return txwazoo(); + } else if (capabilities & Y_DIETIFNA) + return txdietifna(); + else + WriteError("YooHoo internal error - no proto for 0x%04xh",capabilities); + return 1; +} + + + +SM_DECL(rxyoohoo,(char *)"rxyoohoo") +SM_STATES + sendenq, + waitchar, + getpacket, + sendnak, + sendack +SM_NAMES + (char *)"sendenq", + (char *)"waitchar", + (char *)"getpacket", + (char *)"sendnak", + (char *)"sendack" +SM_EDECL + + int c; + int count=0; + unsigned short lcrc,rcrc; + +SM_START(sendenq) + +SM_STATE(sendenq) + + Syslog('S', "rxyoohoo SENDENQ"); + if (count++ > 12) { + Syslog('+', "Too many tries to get hello packet"); + SM_ERROR; + } + PUTCHAR(ENQ); + SM_PROCEED(waitchar) + +SM_STATE(waitchar) + + Syslog('S', "rxyoohoo WAITCHAR"); + c=GETCHAR(10); + if (c == TIMEOUT) { + SM_PROCEED(sendenq); + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case 0x1f: SM_PROCEED(getpacket); + break; + case YOOHOO: SM_PROCEED(sendenq); + break; + default: SM_PROCEED(waitchar); + break; + } + +SM_STATE(getpacket) + + Syslog('S', "rxyoohoo GETPACKET"); + GET((char*)&hello, sizeof(hello), 30); + if (STATUS) { + SM_ERROR; + } + + lcrc = crc16xmodem((char*)hello.data, sizeof(hello.data)); + rcrc = (hello.crc[0] << 8) + hello.crc[1]; + if (lcrc != rcrc) { + Syslog('+',"crc does not match in hello packet: %04xh/%04xh", rcrc,lcrc); + SM_PROCEED(sendnak); + } else { + SM_PROCEED(sendack); + } + +SM_STATE(sendnak) + + Syslog('S', "rxyoohoo SENDNAK"); + if (count++ > 9) { + Syslog('+', "Too many tries to get hello packet"); + SM_ERROR; + } + PUTCHAR('?'); + SM_PROCEED(waitchar); + +SM_STATE(sendack) + + Syslog('S', "rxyoohoo SENDACK"); + PUTCHAR(ACK); + SM_SUCCESS; + +SM_END +SM_RETURN + + + +SM_DECL(txyoohoo,(char *)"txyoohoo") +SM_STATES + sendyoohoo, + waitenq, + sendpkt, + waitchar +SM_NAMES + (char *)"sendyoohoo", + (char *)"waitenq", + (char *)"sendpkt", + (char *)"waitchar" +SM_EDECL + + int c; + int count=0; + int startstate; + unsigned short lcrc; + + if (iscaller) + startstate = sendpkt; + else + startstate = sendyoohoo; + + lcrc = crc16xmodem((char*)hello.data, sizeof(hello.data)); + hello.crc[0] = lcrc >> 8; + hello.crc[1] = lcrc & 0xff; + Syslog('S', "txyoohoo INIT"); + +SM_START(startstate) + +SM_STATE(sendyoohoo) + + Syslog('S', "txyoohoo SENDYOOHOO"); + PUTCHAR(YOOHOO); + SM_PROCEED(waitenq); + +SM_STATE(waitenq) + + Syslog('S', "txyoohoo WAITENQ"); + c=GETCHAR(10); + if (c == TIMEOUT) { + if (count++ > 9) { + Syslog('+', "Timeout waiting ENQ"); + SM_ERROR; + } else { + SM_PROCEED(sendyoohoo); + } + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case ENQ: SM_PROCEED(sendpkt); + case YOOHOO: SM_PROCEED(waitenq); + default: Syslog('+',"Got '%s' waiting hello ACK", printablec(c)); + SM_PROCEED(waitchar); + break; + } + +SM_STATE(sendpkt) + + Syslog('S', "txyoohoo SENDPKT"); + if (count++ > 9) { + Syslog('+', "Too many tries to send hello packet"); + SM_ERROR; + } + + PUTCHAR(0x1f); + PUT((char*)&hello, sizeof(hello)); + if (STATUS) { + SM_ERROR; + } + SM_PROCEED(waitchar); + +SM_STATE(waitchar) + + Syslog('S', "txyoohoo WAITCHAR"); + c=GETCHAR(30); + if (c == TIMEOUT) { + Syslog('+', "Timeout waiting hello ACK"); + SM_ERROR; + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case ACK: Syslog('S', "Handshake successfull"); + SM_SUCCESS; + break; + case '?': SM_PROCEED(sendpkt); + break; + case ENQ: SM_PROCEED(sendpkt); + break; + default: SM_PROCEED(waitchar); + break; + } + +SM_END +SM_RETURN + + + + +void fillhello(unsigned short capabilities, char *password) +{ + faddr *best; + unsigned short majver, minver; + + Syslog('S',"fillhello(0x%04hx)",capabilities); + + best = bestaka_s(remote->addr); + + sscanf(VERSION,"%hd.%hd", &majver, &minver); + memset(&hello, 0, sizeof(hello)); + hello.data[0] = 'o'; /* signal */ + hello.data[2] = 1; /* hello-version */ + hello.data[4] = PRODCODE; /* product */ + hello.data[6] = majver&0xff; /* prod-ver-major */ + hello.data[7] = majver>>8; /* prod-ver-major */ + hello.data[8] = minver&0xff; /* prod-ver-minor */ + hello.data[9] = minver>>8; /* prod-ver-minor */ + strncpy((char*)hello.data+10, name?name:"Unavailable",59); /* name */ + if (name) { + hello.data[10+strlen(name)] = '\0'; + strncpy((char*)hello.data+11 + strlen(name), + best->domain, 58-strlen(name)); /* domain */ + } else + strncpy((char*)hello.data + 22, best->domain, 47); /* domain */ + strncpy((char*)hello.data+70, CFG.sysop_name,19); /* sysop */ + hello.data[90] = best->zone&0xff; /* zone */ + hello.data[91] = best->zone>>8; /* zone */ + hello.data[92] = best->net&0xff; /* net */ + hello.data[93] = best->net>>8; /* net */ + hello.data[94] = best->node&0xff; /* node */ + hello.data[95] = best->node>>8; /* node */ + hello.data[96] = best->point&0xff; /* point */ + hello.data[97] = best->point>>8; /* point */ + + if (password) + strncpy((char*)hello.data + 98, password, 8); + + hello.data[114] = capabilities & 0xff; /* capabilities */ + hello.data[115] = capabilities >> 8; /* capabilities */ + tidy_faddr(best); + Syslog('S',"filled hello \"%s\"",printable((char*)hello.data,128)); +} + + + +int checkhello(void) +{ + unsigned short i, majver = 0, minver = 0; + fa_list **tmpl,*tmpn; + faddr remaddr; + char *prodnm, *q; + int loaded = FALSE; + + Syslog('S',"check hello \"%s\"",printable((char*)hello.data,128)); + + hello2 = gethello2(hello.data); + + if ((hello2.signal != 0x6f) || + (hello2.hello_version != 0x01)) { + Syslog('+', "Got \"%s\" instead of \"o\\000\\001\000\"", printable((char*)hello.data,3)); + } + + prodnm = xstrcpy((char *)""); + for (i = 0; ftscprod[i].name; i++) + if (ftscprod[i].code == hello2.product) { + free(prodnm); + prodnm = xstrcpy(ftscprod[i].name); + majver = hello2.product_maj; + minver = hello2.product_min; + break; + } + + remaddr.zone = hello2.my_zone; + remaddr.net = hello2.my_net; + remaddr.node = hello2.my_node; + remaddr.point = hello2.my_point; + remaddr.name = NULL; + remaddr.domain = NULL; + if (hello2.my_name[0]) + remaddr.domain = hello2.my_name + (strlen(hello2.my_name)) + 1; + if (remaddr.domain[0]) { + if ((q = strchr(remaddr.domain, '.'))) + *q = '\0'; + } else { + remaddr.domain = NULL; + } + if (remote) + Syslog('S',"Remote known address: %s",ascfnode(remote->addr,0x1f)); + + for (tmpl = &remote; *tmpl; tmpl = &((*tmpl)->next)); + if ((remote == NULL) || (metric(remote->addr, &remaddr) != 0)) { + (*tmpl) = (fa_list*)malloc(sizeof(fa_list)); + (*tmpl)->next = NULL; + (*tmpl)->addr = (faddr*)malloc(sizeof(faddr)); + (*tmpl)->addr->zone = remaddr.zone; + (*tmpl)->addr->net = remaddr.net; + (*tmpl)->addr->node = remaddr.node; + (*tmpl)->addr->point = remaddr.point; + (*tmpl)->addr->domain = xstrcpy(remaddr.domain); + (*tmpl)->addr->name = NULL; /* Added 15-Dec-1998 */ + } else { + tmpl=&remote; + Syslog('S',"Using single remote address"); + } + + for (tmpn = remote; tmpn; tmpn = tmpn->next) { + (void)nodelock(tmpn->addr); + /* + * lock all remotes, ignore locking result + */ + if (!loaded) + if (noderecord(tmpn->addr)) + loaded = TRUE; + } + + Syslog('+', " address: %s",ascfnode(remote->addr,0x1f)); + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + Syslog('S', "password: %s",(char*)hello2.my_password); + if (hello2.product < 0x0100) + Syslog('+', " uses: %s [%02X] version %d.%d", prodnm, hello2.product, majver, minver); + else + Syslog('+', " uses: %s [%04X] version %d.%d", prodnm, hello2.product, majver, minver); + Syslog('+', " system: %s",(char*)hello2.my_name); + sprintf(history.system_name, "%s", hello2.my_name); + history.system_name[36] = '\0'; + Syslog('+', " sysop: %s",(char*)hello2.sysop); + sprintf(history.sysop, "%s", hello2.sysop); + sprintf(history.location, "Somewhere"); + + free(prodnm); + return loaded; +} + + + +Hello gethello2(unsigned char Hellop[]) +{ + int i; + Hello p; + + p.signal=Hellop[0]+(Hellop[1]<<8); + p.hello_version=Hellop[2]+(Hellop[3]<<8); + p.product=Hellop[4]+(Hellop[5]<<8); + p.product_maj=Hellop[6]+(Hellop[7]<<8); + p.product_min=Hellop[8]+(Hellop[9]<<8); + for (i=0;i<60;i++) + p.my_name[i]=Hellop[10+i]; + for (i=0;i<20;i++) + p.sysop[i]=Hellop[70+i]; + p.my_zone=Hellop[90]+(Hellop[91]<<8); + p.my_net=Hellop[92]+(Hellop[93]<<8); + p.my_node=Hellop[94]+(Hellop[95]<<8); + p.my_point=Hellop[96]+(Hellop[97]<<8); + for (i=0;i<8;i++) + p.my_password[i]=Hellop[98+i]; + for (i=0;i<8;i++) + p.reserved2[i]=Hellop[106+i]; + p.capabilities=Hellop[114]+(Hellop[115]<<8); + for (i=0;i<12;i++) + p.reserved3[i]=Hellop[116+i]; + + return p; +} + diff --git a/mbcico/yoohoo.h b/mbcico/yoohoo.h new file mode 100644 index 00000000..d02eac6f --- /dev/null +++ b/mbcico/yoohoo.h @@ -0,0 +1,8 @@ +#ifndef _YOOHOO_H +#define _YOOHOO_H + +int rx_yoohoo(void); +int tx_yoohoo(void); + +#endif + diff --git a/mbcico/zmmisc.c b/mbcico/zmmisc.c new file mode 100644 index 00000000..c21b1dd7 --- /dev/null +++ b/mbcico/zmmisc.c @@ -0,0 +1,999 @@ +/* + * Z M . C + * Copyright 1994 Omen Technology Inc All Rights Reserved + * ZMODEM protocol primitives + * + * Entry point Functions: + * zsbhdr(type, hdr) send binary header + * zshhdr(type, hdr) send hex header + * zgethdr(hdr) receive header - binary or hex + * zsdata(buf, len, frameend) send data + * zrdata(buf, len) receive data + * stohdr(pos) store position data in Txhdr + * long rclhdr(hdr) recover position offset from header + * + * + * This version implements numerous enhancements including ZMODEM + * Run Length Encoding and variable length headers. These + * features were not funded by the original Telenet development + * contract. + * + * This software may be freely used for educational (didactic + * only) purposes. This software may also be freely used to + * support file transfer operations to or from licensed Omen + * Technology products. Use with other commercial or shareware + * programs (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION. + * + * Any programs which use part or all of this software must be + * provided in source form with this notice intact except by + * written permission from Omen Technology Incorporated. + * + * Use of this software for commercial or administrative purposes + * except when exclusively limited to interfacing Omen Technology + * products requires a per port license payment of $20.00 US per + * port (less in quantity). Use of this code by inclusion, + * decompilation, reverse engineering or any other means + * constitutes agreement to these conditions and acceptance of + * liability to license the materials and payment of reasonable + * legal costs necessary to enforce this license agreement. + * + * + * Omen Technology Inc + * Post Office Box 4681 + * Portland OR 97208 + * + * This code is made available in the hope it will be useful, + * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY + * DAMAGES OF ANY KIND. + * + */ + +static void zputhex(int); +static void zsbh32(int,char*,int,int); +static void zsda32(char*,int,int); +static int zrdat32(char*,int); +static int noxrd7(void); +static int zrbhd32(char*); +static int zrbhdr(char*); +static int zrhhdr(char*); +static int zgethex(void); +static int zgeth1(void); +static void garbitch(void); + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "zmodem.h" + + +/* Original zm.c timing was in tenths of seconds, but our current ttyio driver + does timing in whole seconds. +*/ +static int Rxtimeout = 10; /* Seconds to wait for something */ +int Zctlesc; + +/* Globals used by ZMODEM functions */ +int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ +int Rxtype; /* Type of header received */ +int Rxhlen; /* Length of header received */ +int Rxcount; /* Count of data bytes received */ +char Rxhdr[ZMAXHLEN]; /* Received header */ +char Txhdr[ZMAXHLEN]; /* Transmitted header */ +long Rxpos; /* Received file position */ +long Txpos; /* Transmitted file position */ +int Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ +int Crc32t; /* Controls 32 bit CRC being sent */ + /* 1 == CRC32, 2 == CRC32 + RLE */ +int Crc32r; /* Indicates/controls 32 bit CRC being received */ + /* 0 == CRC16, 1 == CRC32, 2 == CRC32 + RLE */ +int Usevhdrs; /* Use variable length headers */ +int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +char *Altcan; /* Alternate canit string */ + +char *txbuf=NULL; +char *rxbuf=NULL; + +static int lastsent; /* Last char we sent */ +static int Not8bit; /* Seven bits seen on header */ + +char *frametypes[] = { + (char *)"EMPTY", /* -16 */ + (char *)"Can't be (-15)", + (char *)"Can't be (-14)", + (char *)"Can't be (-13)", + (char *)"Can't be (-12)", + (char *)"Can't be (-11)", + (char *)"Can't be (-10)", + (char *)"Can't be (-9)", + (char *)"HANGUP", /* -8 */ + (char *)"Can't be (-7)", + (char *)"Can't be (-6)", + (char *)"Can't be (-5)", + (char *)"EOFILE", /* -4 */ + (char *)"Can't be (-3)", + (char *)"TIMEOUT", /* -2 */ + (char *)"ERROR", /* -1 */ + (char *)"ZRQINIT", + (char *)"ZRINIT", + (char *)"ZSINIT", + (char *)"ZACK", + (char *)"ZFILE", + (char *)"ZSKIP", + (char *)"ZNAK", + (char *)"ZABORT", + (char *)"ZFIN", + (char *)"ZRPOS", + (char *)"ZDATA", + (char *)"ZEOF", + (char *)"ZFERR", + (char *)"ZCRC", + (char *)"ZCHALLENGE", + (char *)"ZCOMPL", + (char *)"ZCAN", + (char *)"ZFREECNT", + (char *)"ZCOMMAND", + (char *)"ZSTDERR", + (char *)"xxxxx" +#define FRTYPES 22 /* Total number of frame types in this array */ + /* not including psuedo negative entries */ +}; + + +/***** Hack by mj ***********************************************************/ +/* + * Buffer for outgoing frames. Sending them with single character write()'s + * is a waste of processor time and causes severe performance degradation + * on TCP and ISDN connections. + */ +#define FRAME_BUFFER_SIZE 16384 +static char *frame_buffer=NULL; +static int frame_length = 0; + +#define BUFFER_CLEAR() do { frame_length=0; } while(0) +#define BUFFER_BYTE(c) do { frame_buffer[frame_length++]=(c); } while(0) +#define BUFFER_FLUSH() do { PUT(frame_buffer, frame_length); \ + frame_length=0; } while(0); +/****************************************************************************/ + +void get_frame_buffer(void) +{ + if (frame_buffer == NULL) + frame_buffer = malloc(FRAME_BUFFER_SIZE); +} + + +void free_frame_buffer(void) +{ + if (frame_buffer) + free(frame_buffer); + frame_buffer = NULL; +} + + + +/* + * Send ZMODEM binary header hdr of type type + */ +void zsbhdr(int len, int type, register char *shdr) +{ + register int n; + register unsigned short crc; + + Syslog('z', "zsbhdr: %c %d %s %lx", Usevhdrs?'v':'f', len, frametypes[type+FTOFFSET], rclhdr(shdr)); + + BUFFER_CLEAR(); + + if (type == ZDATA) + for (n = Znulls; --n >=0; ) + BUFFER_BYTE(0); + + BUFFER_BYTE(ZPAD); BUFFER_BYTE(ZDLE); + + switch (Crc32t=Txfcs32) { + case 2: + zsbh32(len, shdr, type, Usevhdrs?ZVBINR32:ZBINR32); + BUFFER_FLUSH(); break; + case 1: + zsbh32(len, shdr, type, Usevhdrs?ZVBIN32:ZBIN32); break; + default: + if (Usevhdrs) { + BUFFER_BYTE(ZVBIN); + zsendline(len); + } + else + BUFFER_BYTE(ZBIN); + zsendline(type); + crc = updcrc16(type, 0); + + for (n=len; --n >= 0; ++shdr) { + zsendline(*shdr); + crc = updcrc16((0377& *shdr), crc); + } + crc = updcrc16(0,updcrc16(0,crc)); + zsendline(((int)(crc>>8))); + zsendline(crc); + } + + BUFFER_FLUSH(); +} + + + +/* + * Send ZMODEM binary header hdr of type type + */ +void zsbh32(int len, register char *shdr, int type, int flavour) +{ + register int n; + register unsigned long crc; + + BUFFER_BYTE(flavour); + if (Usevhdrs) + zsendline(len); + zsendline(type); + crc = 0xFFFFFFFFL; crc = updcrc32(type, crc); + + for (n=len; --n >= 0; ++shdr) { + crc = updcrc32((0377 & *shdr), crc); + zsendline(*shdr); + } + crc = ~crc; + for (n=4; --n >= 0;) { + zsendline((int)crc); + crc >>= 8; + } +} + + + +/* + * Send ZMODEM HEX header hdr of type type + */ +void zshhdr(int len, int type, register char *shdr) +{ + register int n; + register unsigned short crc; + + Syslog('z', "zshhdr: %c %d %s %ld", Usevhdrs?'v':'f', len, frametypes[type+FTOFFSET], rclhdr(shdr)); + + BUFFER_CLEAR(); + + BUFFER_BYTE(ZPAD); + BUFFER_BYTE(ZPAD); + BUFFER_BYTE(ZDLE); + if (Usevhdrs) { + BUFFER_BYTE(ZVHEX); + zputhex(len); + } + else + BUFFER_BYTE(ZHEX); + zputhex(type); + Crc32t = 0; + + crc = updcrc16(type, 0); + for (n=len; --n >= 0; ++shdr) { + zputhex(*shdr); crc = updcrc16((0377 & *shdr), crc); + } + crc = updcrc16(0,updcrc16(0,crc)); + zputhex(((int)(crc>>8))); zputhex(crc); + + /* + * Make it printable on remote machine + */ + BUFFER_BYTE(015); + BUFFER_BYTE(0212); + + /* + * Uncork the remote in case a fake XOFF has stopped data flow + */ + if (type != ZFIN && type != ZACK) + BUFFER_BYTE(021); + + BUFFER_FLUSH(); +} + + + +/* + * Send binary array buf of length length, with ending ZDLE sequence frameend + */ +char *Zendnames[] = {(char *)"ZCRCE",(char *)"ZCRCG",(char *)"ZCRCQ",(char *)"ZCRCW"}; +void zsdata(register char *buf, int length, int frameend) +{ + register unsigned short crc; + + Syslog('z', "zsdata: %d %s", length, Zendnames[(frameend-ZCRCE)&3]); + + BUFFER_CLEAR(); + + switch (Crc32t) { + case 1: + zsda32(buf, length, frameend); break; + case 2: + zsdar32(buf, length, frameend); break; + default: + crc = 0; + for (;--length >= 0; ++buf) { + zsendline(*buf); crc = updcrc16((0377 & *buf), crc); + } + BUFFER_BYTE(ZDLE); BUFFER_BYTE(frameend); + crc = updcrc16(frameend, crc); + + crc = updcrc16(0,updcrc16(0,crc)); + zsendline(((int)(crc>>8))); zsendline(crc); + } + if (frameend == ZCRCW) + BUFFER_BYTE(XON); + + BUFFER_FLUSH(); +} + + + +void zsda32(register char *buf, int length, int frameend) +{ + register int c; + register unsigned long crc; + + crc = 0xFFFFFFFFL; + for (;--length >= 0; ++buf) { + c = *buf & 0377; + if (c & 0140) + BUFFER_BYTE(lastsent = c); + else + zsendline(c); + crc = updcrc32(c, crc); + } + BUFFER_BYTE(ZDLE); + BUFFER_BYTE(frameend); + crc = updcrc32(frameend, crc); + + crc = ~crc; + for (c=4; --c >= 0;) { + zsendline((int)crc); crc >>= 8; + } +} + + + +/* + * Receive array buf of max length with ending ZDLE sequence + * and CRC. Returns the ending character or error code. + * NB: On errors may store length+1 bytes! + */ +int zrdata(register char *buf, int length) +{ + register int c; + register unsigned short crc; + register char *end; + register int d; + + switch (Crc32r) { + case 1: + return zrdat32(buf, length); + case 2: + return zrdatr32(buf, length); + } + + crc = Rxcount = 0; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + crc = updcrc16((((d=c))&0377), crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc16(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc16(c, crc); + if (crc & 0xFFFF) { + Syslog('+', "Zmodem zrdata: Bad CRC"); + return TERROR; + } + Rxcount = length - (end - buf); + Syslog('z', "zrdata: %d %s", Rxcount, Zendnames[(d-GOTCRCE)&3]); + return d; + case GOTCAN: + Syslog('+', "Zmodem: Sender Canceled"); + return ZCAN; + case TIMEOUT: + Syslog('+', "Zmodem: TIMEOUT receiving data"); + return c; + case HANGUP: + Syslog('+', "Zmodem: Carrier lost while receiving"); + return c; + default: + garbitch(); + return c; + } + } + *buf++ = c; + crc = updcrc16(c, crc); + } + Syslog('+', "Zmodem: Data subpacket too long"); + return TERROR; +} + + + +int zrdat32(register char *buf, int length) +{ + register int c; + register unsigned long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; c &= 0377; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if (crc != 0xDEBB20E3) { + Syslog('+', "Zmodem zrdat32: Bad CRC"); + return TERROR; + } + Rxcount = length - (end - buf); + + Syslog('z', "zrdat32: %d %s", Rxcount, Zendnames[(d-GOTCRCE)&3]); + + return d; + case GOTCAN: + Syslog('+', "Zmodem: Sender Canceled"); + return ZCAN; + case TIMEOUT: + Syslog('+', "Zmodem: TIMEOUT"); + return c; + case HANGUP: + Syslog('+', "Zmodem: Carrier lost while receiving"); + return c; + default: + garbitch(); + return c; + } + } + *buf++ = c; + crc = updcrc32(c, crc); + } + Syslog('+', "Zmodem: Data subpacket too long"); + return TERROR; +} + + + +void garbitch(void) +{ + Syslog('+', "Zmodem: Garbled data subpacket"); +} + + + +/* + * Read a ZMODEM header to hdr, either binary or hex. + * + * Set Rxhlen to size of header (default 4) (valid if good hdr) + * On success, set Zmodem to 1, set Rxpos and return type of header. + * Otherwise return negative on error. + * Return ERROR instantly if ZCRCW sequence, for fast error recovery. + */ +int zgethdr(char *shdr) +{ + register int c, n, cancount; + + int Zrwindow = 1400; + int Baudrate = 9600; + n = Zrwindow + Baudrate; + Rxframeind = Rxtype = 0; + +startover: + cancount = 5; +again: + /* + * Return immediate ERROR if ZCRCW sequence seen + */ + if (((c = GETCHAR(Rxtimeout)) < 0) && (c != TIMEOUT)) + goto fifi; + else switch(c) { + case 021: case 0221: + goto again; + case HANGUP: + case TIMEOUT: + goto fifi; + case CAN: +gotcan: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + switch (c = GETCHAR(Rxtimeout)) { + case TIMEOUT: + goto again; + case ZCRCW: + switch (GETCHAR(Rxtimeout)) { + case TIMEOUT: + c = TERROR; goto fifi; + case HANGUP: + goto fifi; + default: + goto agn2; + } + case HANGUP: + goto fifi; + default: + break; + case CAN: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + goto again; + } + /* **** FALL THRU TO **** */ + default: +agn2: +#define GCOUNT (-4) + if ( --n == 0) { + c = GCOUNT; goto fifi; + } + goto startover; + case ZPAD|0200: /* This is what we want. */ + Not8bit = c; + case ZPAD: /* This is what we want. */ + break; + } + cancount = 5; +splat: + switch (c = noxrd7()) { + case ZPAD: + goto splat; + case HANGUP: + case TIMEOUT: + goto fifi; + default: + goto agn2; + case ZDLE: /* This is what we want. */ + break; + } + + + Rxhlen = 4; /* Set default length */ + Rxframeind = c = noxrd7(); + switch (c) { + case ZVBIN32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 1; c = zrbhd32(shdr); break; + case ZBIN32: + if (Usevhdrs) + goto agn2; + Crc32r = 1; c = zrbhd32(shdr); break; + case ZVBINR32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 2; c = zrbhd32(shdr); break; + case ZBINR32: + if (Usevhdrs) + goto agn2; + Crc32r = 2; c = zrbhd32(shdr); break; + case HANGUP: + case TIMEOUT: + goto fifi; + case ZVBIN: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; c = zrbhdr(shdr); break; + case ZBIN: + if (Usevhdrs) + goto agn2; + Crc32r = 0; c = zrbhdr(shdr); break; + case ZVHEX: + if ((Rxhlen = c = zgethex()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; c = zrhhdr(shdr); break; + case ZHEX: + if (Usevhdrs) + goto agn2; + Crc32r = 0; c = zrhhdr(shdr); break; + case CAN: + goto gotcan; + default: + goto agn2; + } + for (n = Rxhlen; ++n < ZMAXHLEN; ) /* Clear unused hdr bytes */ + shdr[n] = 0; + Rxpos = shdr[ZP3] & 0377; + Rxpos = (Rxpos<<8) + (shdr[ZP2] & 0377); + Rxpos = (Rxpos<<8) + (shdr[ZP1] & 0377); + Rxpos = (Rxpos<<8) + (shdr[ZP0] & 0377); +fifi: + switch (c) { + case GOTCAN: + c = ZCAN; + /* **** FALL THRU TO **** */ + case ZNAK: + case ZCAN: + case TERROR: + case TIMEOUT: + case HANGUP: + Syslog('+', "Zmodem: Got %s", frametypes[c+FTOFFSET]); + /* **** FALL THRU TO **** */ + default: + if (c >= -FTOFFSET && c <= FRTYPES) + Syslog('z', "zgethdr: %c %d %s %ld", Rxframeind, Rxhlen, frametypes[c+FTOFFSET], Rxpos); + else + Syslog('z', "zgethdr: %c %d %ld", Rxframeind, c, Rxpos); + } + /* Use variable length headers if we got one */ + if (c >= 0 && c <= FRTYPES && Rxframeind & 040) + Usevhdrs = 1; + return c; +} + + + +/* + * Receive a binary style header (type and position) + */ +int zrbhdr(register char *shdr) +{ + register int c, n; + register unsigned short crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = updcrc16(c, 0); + + for (n=Rxhlen; --n >= 0; ++shdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc16(c, crc); + *shdr = c; + } + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc16(c, crc); + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc16(c, crc); + if (crc & 0xFFFF) { + Syslog('+', "Zmodem zrbhdr: Bad CRC"); + return TERROR; + } + return Rxtype; +} + + + +/* + * Receive a binary style header (type and position) with 32 bit FCS + */ +int zrbhd32(register char *shdr) +{ + register int c, n; + register unsigned long crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = 0xFFFFFFFFL; crc = updcrc32(c, crc); + + Syslog('Z', "zrbhd32 c=%X crc=%lX", c, crc); + + for (n=Rxhlen; --n >= 0; ++shdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc32(c, crc); + *shdr = c; + Syslog('Z', "zrbhd32 c=%X crc=%lX", c, crc); + } + for (n=4; --n >= 0;) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc32(c, crc); + Syslog('Z', "zrbhd32 c=%X crc=%lX", c, crc); + } + if (crc != 0xDEBB20E3) { + Syslog('+', "Zmodem zrbhd32: Bad CRC"); + return TERROR; + } + return Rxtype; +} + + + +/* + * Receive a hex style header (type and position) + */ +int zrhhdr(char *shdr) +{ + register int c; + register unsigned short crc; + register int n; + + if ((c = zgethex()) < 0) + return c; + Rxtype = c; + crc = updcrc16(c, 0); + + for (n=Rxhlen; --n >= 0; ++shdr) { + if ((c = zgethex()) < 0) + return c; + crc = updcrc16(c, crc); + *shdr = c; + } + if ((c = zgethex()) < 0) + return c; + crc = updcrc16(c, crc); + if ((c = zgethex()) < 0) + return c; + crc = updcrc16(c, crc); + if (crc & 0xFFFF) { + Syslog('+', "Zmodem zrhhdr: Bad CRC"); + return TERROR; + } + switch (c = GETCHAR(Rxtimeout)) { + case 0215: + Not8bit = c; + /* **** FALL THRU TO **** */ + case 015: + /* Throw away possible cr/lf */ + switch (c = GETCHAR(Rxtimeout)) { + case 012: + Not8bit |= c; + } + } + if (c < 0) + return c; + return Rxtype; +} + + + +/* + * Send a byte as two hex digits + */ +void zputhex(register int c) +{ + static char digits[] = "0123456789abcdef"; + + Syslog('Z', "zputhex: %02X", c); + BUFFER_BYTE(digits[(c&0xF0)>>4]); + BUFFER_BYTE(digits[(c)&0xF]); +} + + + +/* + * Send character c with ZMODEM escape sequence encoding. + * Escape XON, XOFF. Escape CR following @ (Telenet net escape) + */ +void zsendline(int c) +{ + /* Quick check for non control characters */ + if (c & 0140) + BUFFER_BYTE(lastsent = c); + else { + switch (c &= 0377) { + case ZDLE: + BUFFER_BYTE(ZDLE); + BUFFER_BYTE (lastsent = (c ^= 0100)); + break; + case 015: + case 0215: + if (!Zctlesc && (lastsent & 0177) != '@') + goto sendit; + /* **** FALL THRU TO **** */ + case 020: + case 021: + case 023: + case 0220: + case 0221: + case 0223: + BUFFER_BYTE(ZDLE); + c ^= 0100; + sendit: + BUFFER_BYTE(lastsent = c); + break; + default: + if (Zctlesc && ! (c & 0140)) { + BUFFER_BYTE(ZDLE); + c ^= 0100; + } + BUFFER_BYTE(lastsent = c); + } + } +} + + + +/* Decode two lower case hex digits into an 8 bit byte value */ +int zgethex(void) +{ + register int c; + + c = zgeth1(); + Syslog('Z', "zgethex: %02X", c); + return c; +} + + + +int zgeth1(void) +{ + register int c, n; + + if ((c = noxrd7()) < 0) + return c; + n = c - '0'; + if (n > 9) + n -= ('a' - ':'); + if (n & ~0xF) + return TERROR; + if ((c = noxrd7()) < 0) + return c; + c -= '0'; + if (c > 9) + c -= ('a' - ':'); + if (c & ~0xF) + return TERROR; + c += (n<<4); + return c; +} + + + +/* + * Read a byte, checking for ZMODEM escape encoding + * including CAN*5 which represents a quick abort + */ +int zdlread(void) +{ + register int c; + +again: + /* Quick check for non control characters */ + if ((c = GETCHAR(Rxtimeout)) & 0140) + return c; + switch (c) { + case ZDLE: + break; + case 023: + case 0223: + case 021: + case 0221: + goto again; + default: + if (Zctlesc && !(c & 0140)) { + goto again; + } + return c; + } +again2: + if ((c = GETCHAR(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = GETCHAR(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = GETCHAR(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = GETCHAR(Rxtimeout)) < 0) + return c; + switch (c) { + case CAN: + return GOTCAN; + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + return (c | GOTOR); + case ZRUB0: + return 0177; + case ZRUB1: + return 0377; + case 023: + case 0223: + case 021: + case 0221: + goto again2; + default: + if (Zctlesc && ! (c & 0140)) { + goto again2; + } + if ((c & 0140) == 0100) + return (c ^ 0100); + break; + } + Syslog('+', "Zmodem: Bad escape sequence 0x%x", c); + return TERROR; +} + + + +/* + * Read a character from the modem line with timeout. + * Eat parity, XON and XOFF characters. + */ +int noxrd7(void) +{ + register int c; + + for (;;) { + if ((c = GETCHAR(Rxtimeout)) < 0) + return c; + switch (c &= 0177) { + case XON: + case XOFF: + continue; + default: + if (Zctlesc && !(c & 0140)) + continue; + case '\r': + case '\n': + case ZDLE: + return c; + } + } +} + + + +/* + * Store long integer pos in Txhdr + */ +void stohdr(long pos) +{ + Txhdr[ZP0] = pos; + Txhdr[ZP1] = pos>>8; + Txhdr[ZP2] = pos>>16; + Txhdr[ZP3] = pos>>24; +} + + + +/* + * Recover a long integer from a header + */ +long rclhdr(register char *shdr) +{ + register long l; + + l = (shdr[ZP3] & 0377); + l = (l << 8) | (shdr[ZP2] & 0377); + l = (l << 8) | (shdr[ZP1] & 0377); + l = (l << 8) | (shdr[ZP0] & 0377); + return l; +} + +/* End of zmmisc.c */ diff --git a/mbcico/zmodem.h b/mbcico/zmodem.h new file mode 100644 index 00000000..4af097bc --- /dev/null +++ b/mbcico/zmodem.h @@ -0,0 +1,199 @@ +#ifndef ZMODEM_H +#define ZMODEM_H + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef OK +#define OK 0 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define RETRYMAX 10 +#define MAXBLOCK 8192 + +/* + * Z M O D E M . H Manifest constants for ZMODEM + * application to application file transfer protocol + * 04-17-89 Chuck Forsberg Omen Technology Inc + */ +#define ZPAD '*' /* 052 Padding character begins frames */ +#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ +#define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */ +#define ZBIN 'A' /* Binary frame indicator (CRC-16) */ +#define ZHEX 'B' /* HEX frame indicator */ +#define ZBIN32 'C' /* Binary frame with 32 bit FCS */ +#define ZBINR32 'D' /* RLE packed Binary frame with 32 bit FCS */ +#define ZVBIN 'a' /* Binary frame indicator (CRC-16) */ +#define ZVHEX 'b' /* HEX frame indicator */ +#define ZVBIN32 'c' /* Binary frame with 32 bit FCS */ +#define ZVBINR32 'd' /* RLE packed Binary frame with 32 bit FCS */ +#define ZRESC 0176 /* RLE flag/escape character */ +#define ZMAXHLEN 16 /* Max header information length NEVER CHANGE */ +#define ZMAXSPLEN 1024 /* Max subpacket length NEVER CHANGE */ + +/* Frame types (see array "frametypes" in zm.c) */ +#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 */ + +/* Parameters for ZRINIT header */ +#define ZRPXWN 8 /* 9th byte in header contains window size/256 */ +#define ZRPXQQ 9 /* 10th to 14th bytes contain quote mask */ +/* Bit Masks for ZRINIT flags byte ZF0 */ +#define CANFDX 01 /* Rx can send and receive true FDX */ +#define CANOVIO 02 /* Rx can receive data during disk I/O */ +#define CANBRK 04 /* Rx can send a break signal */ +#define CANRLE 010 /* Receiver can decode RLE */ +#define CANLZW 020 /* Receiver can uncompress */ +#define CANFC32 040 /* Receiver can use 32 bit Frame Check */ +#define ESCCTL 0100 /* Receiver expects ctl chars to be escaped */ +#define ESC8 0200 /* Receiver expects 8th bit to be escaped */ + +/* Bit Masks for ZRINIT flags byte ZF1 */ +#define CANVHDR 01 /* Variable headers OK */ +#define ZRRQWN 8 /* Receiver specified window size in ZRPXWN */ +#define ZRRQQQ 16 /* Additional control chars to quote in ZRPXQQ */ +#define ZRQNVH (ZRRQWN|ZRRQQQ) /* Variable len hdr reqd to access info */ + +/* Parameters for ZSINIT frame */ +#define ZATTNLEN 32 /* Max length of attention string */ +#define ALTCOFF ZF1 /* Offset to alternate canit string, 0 if not used */ +/* 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 ZMSKNOLOC 0200 /* Skip file if not present at rx */ +/* Management options, one of these ored in ZF1 */ +#define ZMMASK 037 /* Mask for the choices below */ +#define ZMNEWL 1 /* Transfer if source newer or longer */ +#define ZMCRC 2 /* Transfer if different file CRC or length */ +#define ZMAPND 3 /* Append contents to existing file (if any) */ +#define ZMCLOB 4 /* Replace existing file */ +#define ZMNEW 5 /* Transfer if source newer */ + /* Number 5 is alive ... */ +#define ZMDIFF 6 /* Transfer if dates or lengths different */ +#define ZMPROT 7 /* Protect destination file */ +#define ZMCHNG 8 /* Change filename if destination exists */ +/* Transport options, one of these in ZF2 */ +#define ZTLZW 1 /* Lempel-Ziv compression */ +#define ZTRLE 3 /* Run Length encoding */ +/* Extended options for ZF3, bit encoded */ +#define ZXSPARS 64 /* Encoding for sparse file operations */ +#define ZCANVHDR 01 /* Variable headers OK */ +/* Receiver window size override */ +#define ZRWOVR 4 /* byte position for receive window override/256 */ + +/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ +#define ZCACK1 1 /* Acknowledge, then do command */ + +long rclhdr(register char *); + +/* Globals used by ZMODEM functions */ +extern int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ +extern int Rxtype; /* Type of header received */ +extern int Rxcount; /* Count of data bytes received */ +extern int long Rxpos; /* Received file position */ +extern int long Txpos; /* Transmitted file position */ +extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ +extern int Crc32t; /* Display flag indicating 32 bit CRC being sent */ +extern int Crc32r; /* Display flag indicating 32 bit CRC being received */ +extern int Crc32; /* Display flag indicating 32 bit CRC being received */ +extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +extern char Rxhdr[]; +extern char Txhdr[]; +extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +extern char *Altcan; /* Alternate canit string */ +extern char *Zendnames[]; +extern char *txbuf; +extern char *rxbuf; + +/* End of ZMODEM.H */ + +char Zsendmask[33]; /* Additional control characters to mask */ + +extern int Effbaud; +extern int Zmodem; +extern int Zctlesc; +extern int Filesleft; +extern long Totalleft; + +extern char *frametypes[]; +#define FTOFFSET 16 + +extern void zsbhdr(int,int,char*); +extern void zshhdr(int,int,char*); +extern int zgethdr(char*); +extern void zsdata(char*,int,int); +extern int zrdata(char*,int); +extern void stohdr(long); + +extern void zsendline(int); +extern void zsdar32(char*,int,int); +extern int zrdatr32(char*,int); +extern int zdlread(void); + +extern unsigned short crc16xmodemtab[]; +extern unsigned long crc32tab[]; +#define updcrc16(cp,crc) (crc16xmodemtab[(((int)crc >> 8) & 0xff)] ^ (crc << 8) ^ cp) +#define updcrc32(cp,crc) (crc32tab[((int)crc ^ cp) & 0xff] ^ ((crc >> 8) & 0x00ffffff)) + +int zmsndfiles(file_list *); +int zmrcvfiles(void); + +#endif + diff --git a/mbcico/zmrecv.c b/mbcico/zmrecv.c new file mode 100644 index 00000000..9b15dd20 --- /dev/null +++ b/mbcico/zmrecv.c @@ -0,0 +1,577 @@ +/***************************************************************************** + * + * File ..................: mbcico/zmrecv.c + * Purpose ...............: Fidonet mailer + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "lutil.h" +#include "ttyio.h" +#include "session.h" +#include "zmodem.h" +#include "config.h" +#include "emsi.h" +#include "openfile.h" +#include "openport.h" + + +#ifndef BELEIVE_ZFIN +#define BELEIVE_ZFIN 2 +#endif + +static FILE *fout=NULL; + +static int Usevhdrs; +static long rxbytes; +static int Eofseen; /* indicates cpm eof (^Z) has been received */ +static int errors; +static time_t startime,etime; +static long sbytes; + +#define DEFBYTL 2000000000L /* default rx file size */ +static long Bytesleft; /* number of bytes of incoming file left */ +static long Modtime; /* Unix style mod time for incoming file */ +static int Filemode; /* Unix style mode for incoming file */ +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + +static int Thisbinary; /* current file is to be received in bin mode */ +char Lzconv; /* Local ZMODEM file conversion request */ +char Lzmanag; /* Local file management request */ + +static char *secbuf=0; + +static int tryzhdrtype; +static char zconv; /* ZMODEM file conversion request */ +static char zmanag; /* ZMODEM file management request */ +static char ztrans; /* ZMODEM file transport request */ + +static int resync(off_t); +static int tryz(void); +static int rzfiles(void); +static int rzfile(void); +static void zmputs(char*); +int closeit(int); +static int putsec(char*,int); +static int procheader(char*); +static int ackbibi(void); +static long getfree(void); + + +void get_frame_buffer(void); +void free_frame_buffer(void); + +extern unsigned long rcvdbytes; + + + +int zmrcvfiles(void) +{ + int rc; + + Syslog('+', "Zmodem: start %s receive", (emsi_local_protos & PROT_ZAP)?"ZedZap":"Zmodem"); + + get_frame_buffer(); + + if (secbuf == NULL) + secbuf = malloc(MAXBLOCK+1); + tryzhdrtype = ZRINIT; + if ((rc = tryz()) < 0) { + Syslog('+', "Zmodem: could not initiate receive, rc=%d",rc); + } else + switch (rc) { + case ZCOMPL: rc = 0; break; + case ZFILE: rc = rzfiles(); break; + } + + if (fout) { + if (closeit(0)) { + WriteError("Zmodem: Error closing file"); + } + } + + if (secbuf) + free(secbuf); + secbuf = NULL; + free_frame_buffer(); + + Syslog('z', "Zmodem: receive rc=%d",rc); + return abs(rc); +} + + + +/* + * Initialize for Zmodem receive attempt, try to activate Zmodem sender + * Handles ZSINIT frame + * Return ZFILE if Zmodem filename received, -1 on error, + * ZCOMPL if transaction finished, else 0 + */ +int tryz(void) +{ + int c, n; + int cmdzack1flg; + + for (n = 15; --n >= 0; ) { + /* + * Set buffer length (0) and capability flags + */ + Syslog('z', "tryz attempt %d", n); + stohdr(0L); + Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO; + if (Zctlesc) + Txhdr[ZF0] |= TESCCTL; + Txhdr[ZF0] |= CANRLE; + Txhdr[ZF1] = CANVHDR; + zshhdr(4, tryzhdrtype, Txhdr); + if (tryzhdrtype == ZSKIP) /* Don't skip too far */ + tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ +again: + switch (zgethdr(Rxhdr)) { + case ZRQINIT: + if (Rxhdr[ZF3] & 0x80) + Usevhdrs = TRUE; /* we can var header */ + continue; + case ZEOF: + continue; + case TIMEOUT: + Syslog('+', "Zmodem: tryz() timeout attempt %d", n); + continue; + case ZFILE: + zconv = Rxhdr[ZF0]; + zmanag = Rxhdr[ZF1]; + ztrans = Rxhdr[ZF2]; + if (Rxhdr[ZF3] & ZCANVHDR) + Usevhdrs = TRUE; + tryzhdrtype = ZRINIT; + c = zrdata(secbuf, MAXBLOCK); + if (c == GOTCRCW) + return ZFILE; + zshhdr(4,ZNAK, Txhdr); + goto again; + case ZSINIT: + Zctlesc = TESCCTL & Rxhdr[ZF0]; + if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { + stohdr(1L); + zshhdr(4,ZACK, Txhdr); + goto again; + } + zshhdr(4,ZNAK, Txhdr); + goto again; + case ZFREECNT: + stohdr(getfree()); + zshhdr(4,ZACK, Txhdr); + goto again; + case ZCOMMAND: + cmdzack1flg = Rxhdr[ZF0]; + if (zrdata(secbuf, MAXBLOCK) == GOTCRCW) { + if (cmdzack1flg & ZCACK1) + stohdr(0L); + else + Syslog('+', "Zmodem: request for command \"%s\" ignored", printable(secbuf,-32)); + stohdr(0L); + do { + zshhdr(4,ZCOMPL, Txhdr); + } while (++errors<20 && zgethdr(Rxhdr) != ZFIN); + return ackbibi(); + } + zshhdr(4,ZNAK, Txhdr); goto again; + case ZCOMPL: + goto again; + case ZRINIT: + case ZFIN: /* do not beleive in first ZFIN */ + ackbibi(); return ZCOMPL; + case TERROR: + case HANGUP: + case ZCAN: + return TERROR; + default: + continue; + } + } + return 0; +} + + + +/* + * Receive 1 or more files with ZMODEM protocol + */ +int rzfiles(void) +{ + int c; + + Syslog('z', "rzfiles"); + + for (;;) { + switch (c = rzfile()) { + case ZEOF: + case ZSKIP: + case ZFERR: + switch (tryz()) { + case ZCOMPL: + return OK; + default: + return TERROR; + case ZFILE: + break; + } + continue; + default: + return c; + case TERROR: + return TERROR; + } + } + /* NOTREACHED */ +} + + + +/* + * Receive a file with ZMODEM protocol + * Assumes file name frame is in secbuf + */ +int rzfile(void) +{ + int c, n; + + Syslog('z', "rzfile"); + + Eofseen=FALSE; + rxbytes = 0l; + if ((c = procheader(secbuf))) { + return (tryzhdrtype = c); + } + + n = 20; + + for (;;) { + stohdr(rxbytes); + zshhdr(4,ZRPOS, Txhdr); +nxthdr: + switch (c = zgethdr(Rxhdr)) { + default: + Syslog('z', "rzfile: Wrong header %d", c); + if ( --n < 0) { + Syslog('+', "Zmodem: wrong header %d", c); + return TERROR; + } + continue; + case ZCAN: + Syslog('+', "Zmodem: sender CANcelled"); + return TERROR; + case ZNAK: + if ( --n < 0) { + Syslog('+', "Zmodem: Got ZNAK"); + return TERROR; + } + continue; + case TIMEOUT: + if ( --n < 0) { + Syslog('+', "Zmodem: TIMEOUT"); + return TERROR; + } + continue; + case ZFILE: + zrdata(secbuf, MAXBLOCK); + continue; + case ZEOF: + if (rclhdr(Rxhdr) != rxbytes) { + /* + * Ignore eof if it's at wrong place - force + * a timeout because the eof might have gone + * out before we sent our zrpos. + */ + errors = 0; + goto nxthdr; + } + if (closeit(1)) { + tryzhdrtype = ZFERR; + Syslog('+', "Zmodem: error closing file"); + return TERROR; + } + fout=NULL; + Syslog('z', "rzfile: normal EOF"); + return c; + case HANGUP: + Syslog('+', "Zmodem: Lost Carrier"); + return TERROR; + case TERROR: /* Too much garbage in header search error */ + if (--n < 0) { + Syslog('+', "Zmodem: Too many errors"); + return TERROR; + } + zmputs(Attn); + continue; + case ZSKIP: + Modtime = 1; + closeit(1); + Syslog('+', "Zmodem: Sender SKIPPED file"); + return c; + case ZDATA: + if (rclhdr(Rxhdr) != rxbytes) { + if ( --n < 0) { + Syslog('+', "Zmodem: Data has bad address"); + return TERROR; + } + zmputs(Attn); continue; + } +moredata: + Syslog('z', "%7ld ZMODEM%s ", + rxbytes, Crc32r?" CRC-32":""); + Nopper(); + switch (c = zrdata(secbuf, MAXBLOCK)) { + case ZCAN: + Syslog('+', "Zmodem: sender CANcelled"); + return TERROR; + case HANGUP: + Syslog('+', "Zmodem: Lost Carrier"); + return TERROR; + case TERROR: /* CRC error */ + if (--n < 0) { + Syslog('+', "Zmodem: Too many errors"); + return TERROR; + } + zmputs(Attn); + continue; + case TIMEOUT: + if ( --n < 0) { + Syslog('+', "Zmodem: TIMEOUT"); + return TERROR; + } + continue; + case GOTCRCW: + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + stohdr(rxbytes); + PUTCHAR(XON); + zshhdr(4,ZACK, Txhdr); + goto nxthdr; + case GOTCRCQ: + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + stohdr(rxbytes); + zshhdr(4,ZACK, Txhdr); + goto moredata; + case GOTCRCG: + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + goto moredata; + case GOTCRCE: + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + goto nxthdr; + } + } + } +} + + + +/* + * Send a string to the modem, processing for \336 (sleep 1 sec) + * and \335 (break signal) + */ +void zmputs(char *s) +{ + int c; + + Syslog('z', "zmputs: \"%s\"", printable(s, strlen(s))); + + while (*s) { + switch (c = *s++) { + case '\336': + Syslog('z', "zmputs: sleep(1)"); + sleep(1); continue; + case '\335': + Syslog('z', "zmputs: send break"); + sendbrk(); continue; + default: + PUTCHAR(c); + } + } +} + + + +int resync(off_t off) +{ + return 0; +} + + + +int closeit(int success) +{ + int rc; + + rc = closefile(success); + fout = NULL; + sbytes = rxbytes - sbytes; + (void)time(&etime); + if ((startime = etime - startime) == 0L) + startime = 1L; + Syslog('+', "Zmodem: %s %lu bytes in %s (%ld cps)", success?"OK":"dropped after", + sbytes, str_time(startime), sbytes / startime); + rcvdbytes += sbytes; + return rc; +} + + + +/* + * Ack a ZFIN packet, let byegones be byegones + */ +int ackbibi(void) +{ + int n; + int c; + + Syslog('z', "ackbibi:"); + stohdr(0L); + for (n=3; --n>=0; ) { + zshhdr(4,ZFIN, Txhdr); + switch ((c=GETCHAR(10))) { + case 'O': + GETCHAR(1); /* Discard 2nd 'O' */ + Syslog('z', "Zmodem: ackbibi complete"); + return ZCOMPL; + case TERROR: + case HANGUP: + Syslog('z', "Zmodem: ackbibi got %d, ignore",c); + return 0; + case TIMEOUT: + default: + Syslog('z', "Zmodem: ackbibi got '%s', continue", printablec(c)); + break; + } + } + return ZCOMPL; +} + + + +/* + * Process incoming file information header + */ +int procheader(char *Name) +{ + register char *openmode, *p; + static int dummy; + char ctt[32]; + + Syslog('z', "procheader \"%s\"",printable(Name,0)); + /* set default parameters and overrides */ + openmode = (char *)"w"; + + /* + * Process ZMODEM remote file management requests + */ + Thisbinary = (zconv != ZCNL); /* Remote ASCII override */ + if (zmanag == ZMAPND) + openmode = (char *)"a"; + + Bytesleft = DEFBYTL; + Filemode = 0; + Modtime = 0L; + + p = Name + 1 + strlen(Name); + sscanf(p, "%ld%lo%o%o%d%d%d%d", &Bytesleft, &Modtime, &Filemode, &dummy, &dummy, &dummy, &dummy, &dummy); + strcpy(ctt,date(Modtime)); + Syslog('+', "Zmodem: \"%s\" %ld bytes, %s mode %o", Name, Bytesleft, ctt, Filemode); + + fout = openfile(Name,Modtime,Bytesleft,&rxbytes,resync); + (void)time(&startime); + sbytes = rxbytes; + + if (Bytesleft == rxbytes) { + Syslog('+', "Zmodem: Skipping %s", Name); + fout = NULL; + return ZSKIP; + } else if (!fout) + return ZFERR; + else + return 0; +} + + + +/* + * Putsec writes the n characters of buf to receive file fout. + * If not in binary mode, carriage returns, and all characters + * starting with CPMEOF are discarded. + */ +int putsec(char *buf, int n) +{ + register char *p; + + if (n == 0) + return OK; + + if (Thisbinary) { + for (p = buf; --n>=0; ) + putc( *p++, fout); + } else { + if (Eofseen) + return OK; + for (p = buf; --n>=0; ++p ) { + if ( *p == '\r') + continue; + if (*p == SUB) { + Eofseen=TRUE; + return OK; + } + putc(*p ,fout); + } + } + return OK; +} + + + +long getfree(void) +{ + struct statfs sfs; + + if (statfs(inbound, &sfs) != 0) { + WriteError("$cannot statfs \"%s\", assume enough space", inbound); + return -1L; + } else + return (sfs.f_bsize * sfs.f_bfree); +} + + diff --git a/mbcico/zmrle.c b/mbcico/zmrle.c new file mode 100644 index 00000000..3bdefd07 --- /dev/null +++ b/mbcico/zmrle.c @@ -0,0 +1,197 @@ +/* + * File: zmr.c + * Copyright 1988, 1994 Omen Technology Inc All Rights Reserved + * + * + * + * This module implements ZMODEM Run Length Encoding, an + * extension that was not funded by the original Telenet + * development contract. + * + * This software may be freely used for non commercial and + * educational (didactic only) purposes. This software may also + * be freely used to support file transfer operations to or from + * licensed Omen Technology products. Any programs which use + * part or all of this software must be provided in source form + * with this notice intact except by written permission from Omen + * Technology Incorporated. + * + * Use of this software for commercial or administrative purposes + * except when exclusively limited to interfacing Omen Technology + * products requires a per port license payment of $20.00 US per + * port (less in quantity). Use of this code by inclusion, + * decompilation, reverse engineering or any other means + * constitutes agreement to these conditions and acceptance of + * liability to license the materials and payment of reasonable + * legal costs necessary to enforce this license agreement. + * + * + * Omen Technology Inc FAX: 503-621-3745 + * Post Office Box 4681 + * Portland OR 97208 + * + * This code is made available in the hope it will be useful, + * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY + * DAMAGES OF ANY KIND. + * + * ZMODEM RLE compression and decompression functions + */ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "ttyio.h" +#include "session.h" +#include "zmodem.h" + + + +/* + * Send data subpacket RLE encoded with 32 bit FCS + */ +void zsdar32(char *buf, int length, int frameend) +{ + register int c, l, n; + register unsigned long crc; + + crc = 0xFFFFFFFFL; l = *buf++ & 0377; + if (length == 1) { + zsendline(l); crc = updcrc32(l, crc); + if (l == ZRESC) { + zsendline(1); crc = updcrc32(1, crc); + } + } else { + for (n = 0; --length >= 0; ++buf) { + if ((c = *buf & 0377) == l && n < 126 && length>0) { + ++n; continue; + } + switch (n) { + case 0: + zsendline(l); + crc = updcrc32(l, crc); + if (l == ZRESC) { + zsendline(0100); crc = updcrc32(0100, crc); + } + l = c; break; + case 1: + if (l != ZRESC) { + zsendline(l); zsendline(l); + crc = updcrc32(l, crc); + crc = updcrc32(l, crc); + n = 0; l = c; break; + } + /* **** FALL THRU TO **** */ + default: + zsendline(ZRESC); crc = updcrc32(ZRESC, crc); + if (l == 040 && n < 34) { + n += 036; + zsendline(n); crc = updcrc32(n, crc); + } + else { + n += 0101; + zsendline(n); crc = updcrc32(n, crc); + zsendline(l); crc = updcrc32(l, crc); + } + n = 0; l = c; break; + } + } + } + PUTCHAR(ZDLE); PUTCHAR(frameend); + crc = updcrc32(frameend, crc); + + crc = ~crc; + for (length=4; --length >= 0;) { + zsendline((int)crc); crc >>= 8; + } +} + + +/* + * Receive data subpacket RLE encoded with 32 bit FCS + */ +int zrdatr32(register char *buf, int length) +{ + register int c; + register unsigned long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length; + d = 0; /* Use for RLE decoder state */ + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; c &= 0377; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if (crc != 0xDEBB20E3) { + Syslog('+', "Zmodem zrdatr32: Bad CRC"); + return TERROR; + } + Rxcount = length - (end - buf); + + Syslog('z', "zrdatr32: %d %s", Rxcount, + Zendnames[(d-GOTCRCE)&3]); + + return d; + case GOTCAN: + Syslog('+', "Zmodem: Sender Canceled"); + return ZCAN; + case TIMEOUT: + Syslog('+', "Zmodem: TIMEOUT"); + return c; + default: + Syslog('+', "Zmodem: Bad data subpacket"); + return c; + } + } + crc = updcrc32(c, crc); + switch (d) { + case 0: + if (c == ZRESC) { + d = -1; continue; + } + *buf++ = c; continue; + case -1: + if (c >= 040 && c < 0100) { + d = c - 035; c = 040; goto spaces; + } + if (c == 0100) { + d = 0; + *buf++ = ZRESC; continue; + } + d = c; continue; + default: + d -= 0100; + if (d < 1) + goto badpkt; +spaces: + if ((buf + d) > end) + goto badpkt; + while ( --d >= 0) + *buf++ = c; + d = 0; continue; + } + } +badpkt: + Syslog('+', "Zmodem: Data subpacket too long"); + return TERROR; +} + diff --git a/mbcico/zmsend.c b/mbcico/zmsend.c new file mode 100644 index 00000000..23e4b432 --- /dev/null +++ b/mbcico/zmsend.c @@ -0,0 +1,695 @@ +/***************************************************************************** + * + * File ..................: mbcico/zmsend.c + * Purpose ...............: Fidonet mailer + * Last modification date : 07-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "zmodem.h" +#include "lutil.h" +#include "emsi.h" +#include "filelist.h" + +static int initsend(void); +static int sendfile(char*,char*); +static int finsend(void); + +static int getzrxinit(void); +static int sendzsinit(void); +static int zfilbuf(void); +static int zsendfile(char*,int); +static int zsendfdata(void); +static int getinsync(int); +void initzsendmsk(char *); + +static FILE *in; +static int Eofseen; /* EOF seen on input set by zfilbuf */ +static int Rxflags = 0; +static int Usevhdrs; +static int Wantfcs32=TRUE; /* Want to send 32 bit FCS */ +static int Rxbuflen; +static unsigned Txwindow; /* Control the size of the transmitted window */ +static unsigned Txwspac; /* Spacing between zcrcq requests */ +static unsigned Txwcnt; /* Counter used to space ack requests */ +//static long Tframlen = 0; /* Override for tx frame length */ +static int blklen = 128; /* Length of transmitted records */ +static int blkopt; /* Override value for zmodem blklen */ +static int errors; +static int Lastsync; +static long bytcnt; +static int Lrxpos=0; +static int Lztrans=0; +static int Lzmanag=0; +static int Lskipnocor=0; +static int Lzconv=0; +static int Beenhereb4; +static char Myattn[]={0}; +static long startime,endtime; +static long skipsize; + +extern unsigned long sentbytes; +extern int Rxhlen; +extern void get_frame_buffer(void); +extern void free_frame_buffer(void); + + +int zmsndfiles(file_list *lst) +{ + int rc, maxrc = 0; + file_list *tmpf; + + Syslog('+', "Zmodem: start %s send", (emsi_local_protos & PROT_ZAP)?"ZedZap":"Zmodem"); + + get_frame_buffer(); + + if ((rc = initsend())) { + if (txbuf) + free(txbuf); + txbuf = NULL; + free_frame_buffer(); + return abs(rc); + } + + for (tmpf = lst; tmpf && (maxrc < 2); tmpf = tmpf->next) { + if (tmpf->remote) { + rc = sendfile(tmpf->local, tmpf->remote); + rc = abs(rc); + if (rc > maxrc) + maxrc = rc; + if (rc == 0) + execute_disposition(tmpf); + } else if (maxrc == 0) + execute_disposition(tmpf); + } + + if (maxrc < 2) { + rc = finsend(); + rc = abs(rc); + } + + if (rc > maxrc) + maxrc = rc; + + if (txbuf) + free(txbuf); + txbuf = NULL; + free_frame_buffer(); + + Syslog('z', "Zmodem: send rc=%d", maxrc); + return (maxrc < 2)?0:maxrc; +} + + + +static int initsend(void) +{ + Syslog('z', "Zmodem: initsend"); + + PUTSTR((char *)"rz\r"); + stohdr(0x80L); /* Show we can do var header */ + zshhdr(4, ZRQINIT, Txhdr); + + if (getzrxinit()) { + Syslog('+', "Zmodem: Unable to initiate send"); + return 1; + } + + return 0; +} + + + +/* + * Say "bibi" to the receiver, try to do it cleanly + */ +static int finsend(void) +{ + int i, rc = 0; + + Syslog('z', "Zmodem: finsend"); + while (GETCHAR(1) >= 0) /*nothing*/; + for (i = 0; i < 30; i++) { + stohdr(0L); + zshhdr(4, ZFIN, Txhdr); + if ((rc = zgethdr(Rxhdr)) == ZFIN) + PUTSTR((char *)"OO"); + if ((rc == ZFIN) || (rc == ZCAN) || (rc < 0)) + break; + } + return (rc != ZFIN); +} + + + +static int sendfile(char *ln, char *rn) +{ + int rc=0; + struct stat st; + struct flock fl; + int bufl; + int sverr; + + fl.l_type = F_RDLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + if (txbuf == NULL) + txbuf = malloc(MAXBLOCK); + + skipsize = 0L; + if ((in = fopen(ln, "r")) == NULL) { + sverr = errno; + if ((sverr == ENOENT) || (sverr == EINVAL)) { + Syslog('+', "File %s doesn't exist, removing", MBSE_SS(ln)); + return 0; + } else { + WriteError("$Zmodem: cannot open file %s, skipping", MBSE_SS(ln)); + return 1; + } + } + + if (fcntl(fileno(in),F_SETLK,&fl) != 0) { + Syslog('+', "$Zmodem: cannot lock file %s, skipping",MBSE_SS(ln)); + fclose(in); + return 1; + } + + if (stat(ln,&st) != 0) { + Syslog('+', "$Zmodem: cannot access \"%s\", skipping",MBSE_SS(ln)); + fclose(in); + return 1; + } + + Syslog('+', "Zmodem: send \"%s\" as \"%s\"", MBSE_SS(ln), MBSE_SS(rn)); + Syslog('+', "Zmodem: size %lu bytes, dated %s", (unsigned long)st.st_size, date(st.st_mtime)); + (void)time(&startime); + + sprintf(txbuf,"%s %lu %lo %o 0 0 0", rn,(unsigned long)st.st_size, st.st_mtime+(st.st_mtime%2), st.st_mode); + bufl = strlen(txbuf); + *(strchr(txbuf,' ')) = '\0'; /*hope no blanks in filename*/ + + Eofseen = 0; + rc = zsendfile(txbuf,bufl); + if (rc == ZSKIP) { + Syslog('+', "Zmodem: remote skipped %s, is OK",MBSE_SS(ln)); + return 0; + } else if ((rc == OK) && (st.st_size - skipsize)) { + (void)time(&endtime); + if ((startime = endtime - startime) == 0) + startime = 1; + Syslog('+', "Zmodem: OK %lu bytes in %s (%ld cps)", (unsigned long)st.st_size - skipsize, str_time(startime), + (long)(st.st_size-skipsize) / startime); + sentbytes += (unsigned long)st.st_size - skipsize; + return 0; + } else + return 2; +} + + + +/* + * Get the receiver's init parameters + */ +int getzrxinit(void) // CHECKED BUT NOT WELL TESTED +{ + int n; + + Syslog('z', "getzrxinit"); + for (n=10; --n>=0; ) { + + switch (zgethdr(Rxhdr)) { + case ZCHALLENGE: /* Echo receiver's challenge numbr */ + stohdr(Rxpos); + zshhdr(4, ZACK, Txhdr); + continue; + case ZCOMMAND: /* They didn't see out ZRQINIT */ + stohdr(0L); + zshhdr(4, ZRQINIT, Txhdr); + continue; + case ZRINIT: + Rxflags = 0377 & Rxhdr[ZF0]; + Usevhdrs = Rxhdr[ZF1] & CANVHDR; + Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32)); + Zctlesc |= Rxflags & TESCCTL; + Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8); + if ( !(Rxflags & CANFDX)) + Txwindow = 0; + Syslog('z', "Zmodem: Remote allowed Rxbuflen=%d", Rxbuflen); + + /* Set initial subpacket length */ + if (blklen < 1024) { /* Command line override? */ + blklen = 1024; + } + if (Rxbuflen && blklen>Rxbuflen) + blklen = Rxbuflen; + if (blkopt && blklen > blkopt) + blklen = blkopt; + Syslog('z', "Rxbuflen=%d blklen=%d", Rxbuflen, blklen); + Syslog('z', "Txwindow = %u Txwspac = %d", Txwindow, Txwspac); + + if (Lztrans == ZTRLE && (Rxflags & CANRLE)) + Txfcs32 = 2; + else + Lztrans = 0; + + return (sendzsinit()); + case ZCAN: + case TIMEOUT: + return TERROR; + case HANGUP: + return HANGUP; + case ZRQINIT: + if (Rxhdr[ZF0] == ZCOMMAND) + continue; + default: + zshhdr(4, ZNAK, Txhdr); + continue; + } + } + return TERROR; +} + + + +/* + * Send send-init information + */ +int sendzsinit(void) +{ + int c; + + if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL))) + return OK; + errors = 0; + for (;;) { + stohdr(0L); + if (Zctlesc) { + Txhdr[ZF0] |= TESCCTL; zshhdr(4, ZSINIT, Txhdr); + } + else + zsbhdr(4, ZSINIT, Txhdr); + zsdata(Myattn, ZATTNLEN, ZCRCW); + c = zgethdr(Rxhdr); + switch (c) { + case ZCAN: + return TERROR; + case HANGUP: + return HANGUP; + case ZACK: + return OK; + default: + if (++errors > 19) + return TERROR; + continue; + } + } +} + + + +/* + * Fill buffer with blklen chars + */ +int zfilbuf(void) +{ + int n; + + n = fread(txbuf, 1, blklen, in); + if (n < blklen) { + Eofseen = 1; + Syslog('z', "zfilbuf return %d", n); + } + + return n; +} + + + +/* + * Send file name and related info + */ +int zsendfile(char *buf, int blen) +{ + int c; + register unsigned long crc = -1; + long lastcrcrq = -1; + + Syslog('z', "zsendfile %s (%d)", buf, blen); + for (errors=0; ++errors<11;) { + Txhdr[ZF0] = Lzconv; /* file conversion request */ + Txhdr[ZF1] = Lzmanag; /* file management request */ + if (Lskipnocor) + Txhdr[ZF1] |= ZMSKNOLOC; + Txhdr[ZF2] = Lztrans; /* file transport request */ + Txhdr[ZF3] = 0; + zsbhdr(4, ZFILE, Txhdr); + zsdata(buf, blen, ZCRCW); +again: + c = zgethdr(Rxhdr); + switch (c) { + case ZRINIT: + while ((c = GETCHAR(5)) > 0) + if (c == ZPAD) { + goto again; + } + continue; + case ZCAN: + case TIMEOUT: + case ZABORT: + case ZFIN: + Syslog('+', "Zmodem: Got %s on pathname", frametypes[c+FTOFFSET]); + return TERROR; + default: + Syslog('+', "Zmodem: Got %d frame type on pathname", c); + continue; + case TERROR: + case ZNAK: + continue; + case ZCRC: + if (Rxpos != lastcrcrq) { + lastcrcrq = Rxpos; + crc = 0xFFFFFFFFL; + fseek(in, 0L, 0); + Syslog('Z', "bytcnt=%ld crc=%08lX", bytcnt, crc); + while (((c = getc(in)) != EOF) && --lastcrcrq) + crc = updcrc32(c, crc); + crc = ~crc; + clearerr(in); /* Clear possible EOF */ + lastcrcrq = Rxpos; + } + stohdr(crc); + zsbhdr(4, ZCRC, Txhdr); + goto again; + case ZFERR: + case ZSKIP: + Syslog('+', "Zmodem: File skipped by receiver request"); + fclose(in); return c; + case ZRPOS: + /* + * Suppress zcrcw request otherwise triggered by + * lastyunc==bytcnt + */ + if (Rxpos > 0) + skipsize = Rxpos; + if (fseek(in, Rxpos, 0)) + return TERROR; + Lastsync = (bytcnt = Txpos = Lrxpos = Rxpos) -1; + return zsendfdata(); + } + } + fclose(in); return TERROR; +} + + + +/* + * Send the data in the file + */ +int zsendfdata(void) +{ + int c=0, e, n; + int newcnt; + int tcount = 0; + int junkcount; /* Counts garbage chars received by TX */ + int maxblklen, goodblks = 0, goodneeded = 8; + + if (emsi_local_protos & PROT_ZAP) + maxblklen = MAXBLOCK; + else + maxblklen = 1024; + Syslog('z', "zsendfdata() maxblklen=%d", maxblklen); + + junkcount = 0; + Beenhereb4 = 0; +somemore: + if (0) { +waitack: + junkcount = 0; + c = getinsync(0); +gotack: + switch (c) { + default: + case ZCAN: + fclose(in); + return TERROR; + case ZRINIT: + fclose(in); + return ZSKIP; + case ZSKIP: + fclose(in); + return c; + case ZACK: + break; // Possible bug, added 23-08-99 + case ZRPOS: + blklen = ((blklen >> 2) > 64) ? (blklen >> 2) : 64; + goodblks = 0; + goodneeded = ((goodneeded << 1) > 16) ? 16 : goodneeded << 1; + Syslog('z', "zmsend: blocklen now %d", blklen); + break; + case TIMEOUT: /* Put back here 08-09-1999 mb */ + Syslog('z', "zmsend: zsendfdata TIMEOUT"); + goto to; + case HANGUP: /* New, added 08-09-1999 mb */ + Syslog('z', "zmsend: zsendfdata HANGUP"); + fclose(in); + return c; + } + /* + * If the reverse channel can be tested for data, + * this logic may be used to detect error packets + * sent by the receiver, in place of setjmp/longjmp + * rdchk(fd) returns non 0 if a character is available + */ + if (TCHECK()) { + c = GETCHAR(1); + Syslog('z', "zsendfdata(): check getchar(1)=%d", c); + if (c < 0) { + return c; + } else switch (c) { + case CAN: + case ZPAD: + c = getinsync(1); + goto gotack; + case XOFF: /* Wait a while for an XON */ + case XOFF|0200: + GETCHAR(10); + } + } + } +to: + newcnt = Rxbuflen; + Txwcnt = 0; + stohdr(Txpos); + zsbhdr(4, ZDATA, Txhdr); + + do { + n = zfilbuf(); + if (Eofseen) + e = ZCRCE; + else if (junkcount > 3) + e = ZCRCW; + else if (bytcnt == Lastsync) + e = ZCRCW; + else if (Rxbuflen && (newcnt -= n) <= 0) + e = ZCRCW; + else if (Txwindow && (Txwcnt += n) >= Txwspac) { + Txwcnt = 0; e = ZCRCQ; + } else + e = ZCRCG; + Syslog('z', "%7ld ZMODEM%s ", + Txpos, Crc32t?" CRC-32":""); + Nopper(); + zsdata(txbuf, n, e); + bytcnt = Txpos += n; + + if ((blklen < maxblklen) && (++goodblks > goodneeded)) { + blklen = ((blklen << 1) < maxblklen) ? blklen << 1 : maxblklen; + goodblks = 0; + Syslog('z', "zmsend: blocklen now %d", blklen); + } + + if (e == ZCRCW) + goto waitack; + /* + * If the reverse channel can be tested for data, + * this logic may be used to detect error packets + * sent by the receiver, in place of setjmp/longjmp + * rdchk(fd) returns non 0 if a character is available + */ + if (TCHECK()) { + c = GETCHAR(1); + if (c < 0) { + return c; + } else switch (c) { + case CAN: + case ZPAD: + c = getinsync(1); + if (c == ZACK) + break; + /* zcrce - dinna wanna starta ping-pong game */ + zsdata(txbuf, 0, ZCRCE); + goto gotack; + case XOFF: /* Wait a while for an XON */ + case XOFF|0200: + GETCHAR(10); + default: + ++junkcount; + } + } + if (Txwindow) { + while ((tcount = (Txpos - Lrxpos)) >= Txwindow) { + Syslog('z', "%ld window >= %u", tcount, Txwindow); + if (e != ZCRCQ) + zsdata(txbuf, 0, e = ZCRCQ); + c = getinsync(1); + if (c != ZACK) { + zsdata(txbuf, 0, ZCRCE); + goto gotack; + } + } + Syslog('z', "window = %ld", tcount); + } + } while (!Eofseen); + + for (;;) { + stohdr(Txpos); + zsbhdr(4, ZEOF, Txhdr); +egotack: + switch (getinsync(0)) { + case ZACK: + Syslog('z', "zsendfdata() ZACK"); + goto egotack; // continue in old source + case ZRPOS: + goto somemore; + case ZRINIT: + fclose(in); + return OK; + case ZSKIP: + fclose(in); + Syslog('+', "Zmodem: File skipped by receiver request"); + return ZSKIP; + default: + Syslog('+', "Zmodem: Got %d trying to send end of file", c); + case TERROR: + fclose(in); + return TERROR; + } + } +} + + + +/* + * Respond to receiver's complaint, get back in sync with receiver + */ +int getinsync(int flag) +{ + int c = 0; + + Syslog('z', "getinsync(%d)", flag); + + for (;;) { + c = zgethdr(Rxhdr); + switch (c) { + case HANGUP: + return HANGUP; + case ZCAN: + case ZABORT: + case ZFIN: + case TERROR: + case TIMEOUT: + Syslog('+', "Zmodem: Got %s sending data", frametypes[c+FTOFFSET]); + return TERROR; + case ZRPOS: + /* ************************************* */ + /* If sending to a buffered modem, you */ + /* might send a break at this point to */ + /* dump the modem's buffer. */ + clearerr(in); /* In case file EOF seen */ + if (fseek(in, Rxpos, 0)) { + Syslog('+', "Zmodem: Bad Seek to %ld", Rxpos); + return TERROR; + } + Eofseen = 0; + bytcnt = Lrxpos = Txpos = Rxpos; + if (Lastsync == Rxpos) { + if (++Beenhereb4 > 12) { + Syslog('+', "Zmodem: Can't send block"); + return TERROR; + } + if (Beenhereb4 > 4) + if (blklen > 32) { + blklen /= 2; + Syslog('z', "Zmodem: blocklen now %d", blklen); + } + } + else + Beenhereb4=0; + Lastsync = Rxpos; + return c; + case ZACK: + Lrxpos = Rxpos; + if (flag || Txpos == Rxpos) + return ZACK; + continue; + case ZRINIT: + return c; + case ZSKIP: + Syslog('+', "Zmodem: File skipped by receiver request"); + return c; + default: + zsbhdr(4, ZNAK, Txhdr); + continue; + } + } +} + + + +/* + * Set additional control chars to mask in Zsendmask + * according to bit array stored in char array at p + */ +void initzsendmsk(register char *p) +{ + int c; + + for (c = 0; c < 33; ++c) { + if (p[c>>3] & (1 << (c & 7))) { + Zsendmask[c] = 1; + Syslog('z', "Zmodem: Escaping %02o", c); + } + } +} + + diff --git a/mbfido/Makefile.am b/mbfido/Makefile.am new file mode 100644 index 00000000..0ef3c30a --- /dev/null +++ b/mbfido/Makefile.am @@ -0,0 +1,65 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +EXTRA_DIST = maptabs.tgz paths.h.in README + +noinst_PROGRAMS = mbfido mbmail mbseq mbaff mbindex mbdiff mbfile mbmsg + +mbfido_SOURCES = flock.c tosspkt.c mbfido.c hatch.c maketags.c \ +importmsg.c echoout.c tracker.c makestat.c scannews.c lhash.c \ +pack.c ulock.c tic.c ptic.c utic.c mover.c hash.c mkftnhdr.c \ +addbbs.c magic.c fsort.c toberep.c mkrfcmsg.c atoul.c ping.c \ +cookie.c forward.c sendmail.c scan.c addpkt.c importnet.c \ +areamgr.c filemgr.c notify.c mgrutil.c rollover.c bwrite.c \ +rnews.c newspost.c aliasdb.c postemail.c postnetmail.c backalias.c \ +flock.h tosspkt.h mbfido.h hatch.h maketags.h \ +importmsg.h echoout.h tracker.h makestat.h scannews.h lhash.h \ +pack.h ulock.h tic.h ptic.h utic.h mover.h hash.h mkftnhdr.h \ +addbbs.h magic.h fsort.h toberep.h mkrfcmsg.h atoul.h ping.h \ +cookie.h forward.h sendmail.h scan.h addpkt.h importnet.h \ +areamgr.h filemgr.h notify.h mgrutil.h rollover.h bwrite.h \ +rnews.h newspost.h aliasdb.h postemail.h postnetmail.h backalias.h + +mbmail_SOURCES = message.c hash.c lhash.c atoul.c \ +bread.c bwrite.c flock.c mkftnhdr.c mbmail.c tracker.c \ +viadate.c importnet.c aliasdb.c \ +message.h hash.h lhash.h atoul.h \ +bread.h bwrite.h flock.h mkftnhdr.h mbmail.h tracker.h \ +viadate.h importnet.h aliasdb.h + +mbseq_SOURCES = mbseq.c mbseq.h + +mbaff_SOURCES = announce.c fflist.c filefind.c grlist.c mbaff.c msgutil.c \ +announce.h fflist.h filefind.h grlist.h mbaff.h msgutil.h + +mbindex_SOURCES = mbindex.c mbindex.h + +mbdiff_SOURCES = mbdiff.c mbdiff.h + +mbfile_SOURCES = mbfile.c mbfile.h + +mbmsg_SOURCES = post.c mbmsg.c post.h mbmsg.h + +mbfido_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a ../lib/libmbinet.a +mbmail_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbseq_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbaff_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbindex_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbdiff_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbfile_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbmsg_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbfido $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbmail $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbseq $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbaff $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbindex $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbdiff $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbfile $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbmsg $(bindir) + rm -f $(bindir)/mbnews + ln -s $(bindir)/mbfido $(bindir)/mbnews + (cd ${exec_prefix}; tar xfz @PACKAGE@-@VERSION@/mbfido/maptabs.tgz; chown mbse.bbs etc/maptabs/*) + diff --git a/mbfido/Makefile.in b/mbfido/Makefile.in new file mode 100644 index 00000000..c05108f2 --- /dev/null +++ b/mbfido/Makefile.in @@ -0,0 +1,678 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = maptabs.tgz paths.h.in README + +noinst_PROGRAMS = mbfido mbmail mbseq mbaff mbindex mbdiff mbfile mbmsg + +mbfido_SOURCES = flock.c tosspkt.c mbfido.c hatch.c maketags.c importmsg.c echoout.c tracker.c makestat.c scannews.c lhash.c pack.c ulock.c tic.c ptic.c utic.c mover.c hash.c mkftnhdr.c addbbs.c magic.c fsort.c toberep.c mkrfcmsg.c atoul.c ping.c cookie.c forward.c sendmail.c scan.c addpkt.c importnet.c areamgr.c filemgr.c notify.c mgrutil.c rollover.c bwrite.c rnews.c newspost.c aliasdb.c postemail.c postnetmail.c backalias.c flock.h tosspkt.h mbfido.h hatch.h maketags.h importmsg.h echoout.h tracker.h makestat.h scannews.h lhash.h pack.h ulock.h tic.h ptic.h utic.h mover.h hash.h mkftnhdr.h addbbs.h magic.h fsort.h toberep.h mkrfcmsg.h atoul.h ping.h cookie.h forward.h sendmail.h scan.h addpkt.h importnet.h areamgr.h filemgr.h notify.h mgrutil.h rollover.h bwrite.h rnews.h newspost.h aliasdb.h postemail.h postnetmail.h backalias.h + + +mbmail_SOURCES = message.c hash.c lhash.c atoul.c bread.c bwrite.c flock.c mkftnhdr.c mbmail.c tracker.c viadate.c importnet.c aliasdb.c message.h hash.h lhash.h atoul.h bread.h bwrite.h flock.h mkftnhdr.h mbmail.h tracker.h viadate.h importnet.h aliasdb.h + + +mbseq_SOURCES = mbseq.c mbseq.h + +mbaff_SOURCES = announce.c fflist.c filefind.c grlist.c mbaff.c msgutil.c announce.h fflist.h filefind.h grlist.h mbaff.h msgutil.h + + +mbindex_SOURCES = mbindex.c mbindex.h + +mbdiff_SOURCES = mbdiff.c mbdiff.h + +mbfile_SOURCES = mbfile.c mbfile.h + +mbmsg_SOURCES = post.c mbmsg.c post.h mbmsg.h + +mbfido_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a ../lib/libmbinet.a +mbmail_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbseq_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbaff_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbindex_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbdiff_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbfile_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbmsg_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = paths.h +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbfido_OBJECTS = flock.o tosspkt.o mbfido.o hatch.o maketags.o \ +importmsg.o echoout.o tracker.o makestat.o scannews.o lhash.o pack.o \ +ulock.o tic.o ptic.o utic.o mover.o hash.o mkftnhdr.o addbbs.o magic.o \ +fsort.o toberep.o mkrfcmsg.o atoul.o ping.o cookie.o forward.o \ +sendmail.o scan.o addpkt.o importnet.o areamgr.o filemgr.o notify.o \ +mgrutil.o rollover.o bwrite.o rnews.o newspost.o aliasdb.o postemail.o \ +postnetmail.o backalias.o +mbfido_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a \ +../lib/libmbinet.a +mbfido_LDFLAGS = +mbmail_OBJECTS = message.o hash.o lhash.o atoul.o bread.o bwrite.o \ +flock.o mkftnhdr.o mbmail.o tracker.o viadate.o importnet.o aliasdb.o +mbmail_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbmail_LDFLAGS = +mbseq_OBJECTS = mbseq.o +mbseq_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbseq_LDFLAGS = +mbaff_OBJECTS = announce.o fflist.o filefind.o grlist.o mbaff.o \ +msgutil.o +mbaff_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbaff_LDFLAGS = +mbindex_OBJECTS = mbindex.o +mbindex_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbindex_LDFLAGS = +mbdiff_OBJECTS = mbdiff.o +mbdiff_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbdiff_LDFLAGS = +mbfile_OBJECTS = mbfile.o +mbfile_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbfile_LDFLAGS = +mbmsg_OBJECTS = post.o mbmsg.o +mbmsg_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbmsg_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = README Makefile.am Makefile.in paths.h.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbfido_SOURCES) $(mbmail_SOURCES) $(mbseq_SOURCES) $(mbaff_SOURCES) $(mbindex_SOURCES) $(mbdiff_SOURCES) $(mbfile_SOURCES) $(mbmsg_SOURCES) +OBJECTS = $(mbfido_OBJECTS) $(mbmail_OBJECTS) $(mbseq_OBJECTS) $(mbaff_OBJECTS) $(mbindex_OBJECTS) $(mbdiff_OBJECTS) $(mbfile_OBJECTS) $(mbmsg_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbfido/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +paths.h: $(top_builddir)/config.status paths.h.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbfido: $(mbfido_OBJECTS) $(mbfido_DEPENDENCIES) + @rm -f mbfido + $(LINK) $(mbfido_LDFLAGS) $(mbfido_OBJECTS) $(mbfido_LDADD) $(LIBS) + +mbmail: $(mbmail_OBJECTS) $(mbmail_DEPENDENCIES) + @rm -f mbmail + $(LINK) $(mbmail_LDFLAGS) $(mbmail_OBJECTS) $(mbmail_LDADD) $(LIBS) + +mbseq: $(mbseq_OBJECTS) $(mbseq_DEPENDENCIES) + @rm -f mbseq + $(LINK) $(mbseq_LDFLAGS) $(mbseq_OBJECTS) $(mbseq_LDADD) $(LIBS) + +mbaff: $(mbaff_OBJECTS) $(mbaff_DEPENDENCIES) + @rm -f mbaff + $(LINK) $(mbaff_LDFLAGS) $(mbaff_OBJECTS) $(mbaff_LDADD) $(LIBS) + +mbindex: $(mbindex_OBJECTS) $(mbindex_DEPENDENCIES) + @rm -f mbindex + $(LINK) $(mbindex_LDFLAGS) $(mbindex_OBJECTS) $(mbindex_LDADD) $(LIBS) + +mbdiff: $(mbdiff_OBJECTS) $(mbdiff_DEPENDENCIES) + @rm -f mbdiff + $(LINK) $(mbdiff_LDFLAGS) $(mbdiff_OBJECTS) $(mbdiff_LDADD) $(LIBS) + +mbfile: $(mbfile_OBJECTS) $(mbfile_DEPENDENCIES) + @rm -f mbfile + $(LINK) $(mbfile_LDFLAGS) $(mbfile_OBJECTS) $(mbfile_LDADD) $(LIBS) + +mbmsg: $(mbmsg_OBJECTS) $(mbmsg_DEPENDENCIES) + @rm -f mbmsg + $(LINK) $(mbmsg_LDFLAGS) $(mbmsg_OBJECTS) $(mbmsg_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbfido + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +addbbs.o: addbbs.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h tic.h fsort.h addbbs.h +addpkt.o: addpkt.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h ../lib/dbnode.h ../lib/dbmsgs.h \ + pack.h addpkt.h +aliasdb.o: aliasdb.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h aliasdb.h +announce.o: announce.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + ../lib/msgtext.h grlist.h msgutil.h announce.h +areamgr.o: areamgr.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbmsgs.h ../lib/dbdupe.h \ + ../lib/dbuser.h ../lib/dbftn.h sendmail.h mgrutil.h scan.h \ + areamgr.h +atoul.o: atoul.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h atoul.h +backalias.o: backalias.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ../lib/dbcfg.h backalias.h +bread.o: bread.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h bread.h +bwrite.o: bwrite.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h bwrite.h +cookie.o: cookie.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h cookie.h +echoout.o: echoout.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ../lib/dbnode.h ../lib/dbmsgs.h addpkt.h \ + echoout.h +fflist.o: fflist.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h ../lib/msg.h fflist.h +filefind.o: filefind.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + ../lib/msgtext.h fflist.h filefind.h msgutil.h +filemgr.o: filemgr.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbtic.h ../lib/dbdupe.h \ + ../lib/dbuser.h ../lib/dbftn.h sendmail.h mgrutil.h filemgr.h +flock.o: flock.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h flock.h +forward.o: forward.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h ../lib/dbtic.h \ + tic.h cookie.h sendmail.h rollover.h forward.h +fsort.o: fsort.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h fsort.h +grlist.o: grlist.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h grlist.h +hash.o: hash.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h hash.h lhash.h +hatch.o: hatch.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbtic.h utic.h \ + rollover.h hatch.h +importmsg.o: importmsg.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbmsgs.h ../lib/dbdupe.h \ + ../lib/dbuser.h ../lib/dbftn.h echoout.h mkrfcmsg.h importmsg.h \ + postnetmail.h rollover.h +importnet.o: importnet.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbmsgs.h ../lib/dbuser.h rollover.h importnet.h +lhash.o: lhash.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h lhash.h +magic.o: magic.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbtic.h tic.h utic.h \ + magic.h +makestat.o: makestat.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h makestat.h +maketags.o: maketags.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h maketags.h +mbaff.o: mbaff.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + announce.h filefind.h mbaff.h +mbdiff.o: mbdiff.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbdiff.h +mbfido.o: mbfido.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h \ + ../lib/dbdupe.h ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbmsgs.h \ + ../lib/dbuser.h ../lib/dbftn.h ../lib/dbtic.h ../lib/msg.h \ + flock.h tosspkt.h pack.h ulock.h tic.h fsort.h scan.h mbfido.h \ + tracker.h notify.h rollover.h hatch.h scannews.h maketags.h \ + makestat.h newspost.h rnews.h backalias.h +mbfile.o: mbfile.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbfile.h +mbindex.o: mbindex.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbftn.h \ + mbindex.h +mbmail.o: mbmail.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbftn.h ../lib/dbcfg.h \ + ../lib/dbnode.h ../lib/dbmsgs.h ../lib/dbuser.h hash.h \ + mkftnhdr.h message.h +mbmsg.o: mbmsg.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/dbcfg.h \ + post.h mbmsg.h +mbseq.o: mbseq.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbseq.h +message.o: message.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbuser.h \ + bread.h bwrite.h hash.h mkftnhdr.h tracker.h viadate.h \ + importnet.h +mgrutil.o: mgrutil.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h sendmail.h \ + mgrutil.h +mkftnhdr.o: mkftnhdr.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h atoul.h hash.h \ + aliasdb.h mkftnhdr.h +mkrfcmsg.o: mkrfcmsg.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/dbftn.h ../lib/dbdupe.h ../lib/dbuser.h ../lib/common.h \ + ../lib/clcomm.h rollover.h aliasdb.h postemail.h backalias.h \ + mkrfcmsg.h +mover.o: mover.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h tic.h mover.h +msgutil.o: msgutil.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + ../lib/msgtext.h msgutil.h +newspost.o: newspost.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/mbinet.h newspost.h +notify.o: notify.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbnode.h filemgr.h areamgr.h sendmail.h notify.h +pack.o: pack.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbftn.h ../lib/clcomm.h ../lib/dbnode.h \ + pack.h +ping.o: ping.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbtic.h ../lib/dbdupe.h \ + ../lib/dbuser.h ../lib/dbftn.h sendmail.h mgrutil.h \ + postnetmail.h ping.h +post.o: post.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + ../lib/msgtext.h post.h +postemail.o: postemail.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/dbuser.h ../lib/common.h ../lib/clcomm.h ../lib/mbinet.h \ + postemail.h +postnetmail.o: postnetmail.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/dbcfg.h ../lib/dbuser.h ../lib/dbnode.h ../lib/dbftn.h \ + ../lib/common.h ../lib/clcomm.h tracker.h addpkt.h importnet.h \ + mkrfcmsg.h areamgr.h filemgr.h ping.h postemail.h +ptic.o: ptic.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbtic.h ../lib/clcomm.h ../lib/dbnode.h \ + ../lib/dbdupe.h ulock.h mover.h toberep.h tic.h utic.h addbbs.h \ + magic.h forward.h rollover.h ptic.h +rnews.o: rnews.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/mbinet.h ../lib/dbdupe.h \ + ../lib/dbnode.h ../lib/dbmsgs.h ../lib/msg.h ../lib/msgtext.h \ + pack.h scannews.h mbfido.h rnews.h +rollover.o: rollover.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h rollover.h +scan.o: scan.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/msg.h ../lib/clcomm.h ../lib/msgtext.h \ + ../lib/dbnode.h ../lib/dbmsgs.h addpkt.h pack.h tracker.h \ + mkrfcmsg.h postemail.h scan.h +scannews.o: scannews.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/mbinet.h ../lib/dbdupe.h \ + ../lib/dbnode.h ../lib/dbmsgs.h ../lib/msg.h ../lib/msgtext.h \ + mkftnhdr.h hash.h echoout.h rollover.h pack.h scannews.h +sendmail.o: sendmail.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbnode.h ../lib/clcomm.h ../lib/dbmsgs.h \ + addpkt.h rollover.h sendmail.h +tic.o: tic.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbftn.h ../lib/clcomm.h ulock.h ptic.h \ + fsort.h pack.h tic.h +toberep.o: toberep.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h tic.h toberep.h +tosspkt.o: tosspkt.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h importmsg.h \ + tosspkt.h +tracker.o: tracker.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h ../lib/dbftn.h \ + tracker.h +ulock.o: ulock.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h flock.h ulock.h +utic.o: utic.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h tic.h mover.h utic.h +viadate.o: viadate.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + viadate.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbfido $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbmail $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbseq $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbaff $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbindex $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbdiff $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbfile $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbmsg $(bindir) + rm -f $(bindir)/mbnews + ln -s $(bindir)/mbfido $(bindir)/mbnews + (cd ${exec_prefix}; tar xfz @PACKAGE@-@VERSION@/mbfido/maptabs.tgz; chown mbse.bbs etc/maptabs/*) + +# 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/mbfido/README b/mbfido/README new file mode 100644 index 00000000..35615030 --- /dev/null +++ b/mbfido/README @@ -0,0 +1,16 @@ + Mailflow roadmap (in progress)! + + + + + RFC +---------------+ + ------->| postemail |--> SMTP + +---------------+ + + +---------------+ + FTN | |--> Outbound + ------->| postnetmail |--> MsgBase + | |--> mkrfcmsg --> postemail + +---------------+ + + diff --git a/mbfido/addbbs.c b/mbfido/addbbs.c new file mode 100644 index 00000000..3f115ea6 --- /dev/null +++ b/mbfido/addbbs.c @@ -0,0 +1,341 @@ +/***************************************************************************** + * + * File ..................: mbfido/addbbs.c + * Purpose ...............: Add TIC file to the BBS + * Last modification date : 21-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tic.h" +#include "fsort.h" +#include "addbbs.h" + + +extern int tic_imp; + + +/* + * Add file to the BBS file database and place it in the download + * directory. If it is replacing a file, a file with a matching name + * will be deleted. If there is a limit on the number of files with + * the same name pattern, the oldest files will be deleted. The + * files database will be packed if necessary. All modifications are + * done on temp files first. + */ +int Add_BBS() +{ + struct FILERecord frec; + int i, Insert, Done = FALSE, Found = FALSE; + char fdbname[128], fdbtemp[128]; + char temp1[128], temp2[128], *fname; + FILE *fdb, *fdt; + int Keep = 0, DidDelete = FALSE; + fd_list *fdl = NULL; + + /* + * Create filedatabase record. + */ + memset(&frec, 0, sizeof(frec)); + strcpy(frec.Name, TIC.NewName); + strcpy(frec.LName, TIC.NewName); +// strcpy(frec.TicArea, TIC.TicIn.Area); /* TIJDELIJK IVM VELDLENGTE */ + frec.Size = TIC.FileSize; + frec.Crc32 = TIC.Crc_Int; + frec.Announced = TRUE; + sprintf(frec.Uploader, "Filemgr"); + frec.UploadDate = time(NULL); + frec.FileDate = TIC.FileDate; + for (i = 0; i <= TIC.File_Id_Ct; i++) { + strcpy(frec.Desc[i], TIC.File_Id[i]); + if (i == 24) + break; + } + if (strlen(TIC.TicIn.Magic)) + sprintf(frec.Desc[i], "Magic Request: %s", TIC.TicIn.Magic); + + sprintf(temp1, "%s%s", TIC.FilePath, TIC.NewName); + sprintf(temp2, "%s/%s", TIC.BBSpath, TIC.NewName); + mkdirs(temp2); + + if (file_cp(temp1, temp2) != 0) { + WriteError("$Copy to %s failed", temp2); + return FALSE; + } + chmod(temp2, 0644); + + sprintf(fdbname, "%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), tic.FileArea); + sprintf(fdbtemp, "%s/fdb/fdb%ld.temp", getenv("MBSE_ROOT"), tic.FileArea); + + if ((fdb = fopen(fdbname, "r+")) == NULL) { + Syslog('+', "Fdb %s doesn't exist, creating", fdbname); + if ((fdb = fopen(fdbname, "a+")) == NULL) { + WriteError("$Can't create %s", fdbname); + return FALSE; + } + } + + /* + * If there are no files in this area, we append the first + * one and leave immediatly, keepnum and replace have no + * use at this point. + */ + fseek(fdb, 0, SEEK_END); + if (ftell(fdb) == 0) { + fwrite(&frec, sizeof(frec), 1, fdb); + fclose(fdb); + if (!TIC.NoMove) + file_rm(temp1); + tic_imp++; + return TRUE; + } + + /* + * There are already files in the area. We must now see at + * which position to insert the new file, replace or + * remove the old entry. + */ + fseek(fdb, 0, SEEK_SET); + + Insert = 0; + do { + if (fread(&file, sizeof(file), 1, fdb) != 1) + Done = TRUE; + if (!Done) { + if (strcmp(frec.Name, file.Name) == 0) { + Found = TRUE; + Insert++; + } else + if (strcmp(frec.Name, file.Name) < 0) + Found = TRUE; + else + Insert++; + } + } while ((!Found) && (!Done)); + + if (Found) { + if ((fdt = fopen(fdbtemp, "a+")) == NULL) { + WriteError("$Can't create %s", fdbtemp); + fclose(fdb); + return FALSE; + } + + fseek(fdb, 0, SEEK_SET); + /* + * Copy entries till the insert point. + */ + for (i = 0; i < Insert; i++) { + fread(&file, sizeof(file), 1, fdb); + /* + * Check if we are importing a file with the same + * name, if so, don't copy the original database + * record. The file is also overwritten. + */ + if (strcmp(file.Name, frec.Name) != 0) + fwrite(&file, sizeof(file), 1, fdt); + } + + if (area.AddAlpha) { + /* + * Insert the new entry + */ + fwrite(&frec, sizeof(frec), 1, fdt); + } + + /* + * Append the rest of the entries. + */ + while (fread(&file, sizeof(file), 1, fdb) == 1) { + /* + * Check if we find a file with the same name, + * then we skip the record what was origionaly + * in the database record. + */ + if (strcmp(file.Name, frec.Name) != 0) + fwrite(&file, sizeof(file), 1, fdt); + } + + if (!area.AddAlpha) { + /* + * Append the new entry + */ + fwrite(&frec, sizeof(frec), 1, fdt); + } + fclose(fdt); + fclose(fdb); + + /* + * Now make the changes for real. + */ + if (unlink(fdbname) == 0) { + rename(fdbtemp, fdbname); + } else { + WriteError("$Can't unlink %s", fdbname); + unlink(fdbtemp); + return FALSE; + } + + } else { + /* + * Append the new entry + */ + fseek(fdb, 0, SEEK_END); + fwrite(&frec, sizeof(frec), 1, fdb); + fclose(fdb); + } + + /* + * Delete file from the inbound + */ + if (!TIC.NoMove) { + if ((i = file_rm(temp1))) + WriteError("$ %d = file_rm(%s)", i, temp1); + } + + /* + * Handle the replace option. + */ + if ((strlen(TIC.TicIn.Replace)) && (tic.Replace)) { + Syslog('f', "Must Replace: %s", TIC.TicIn.Replace); + + if ((fdb = fopen(fdbname, "r+")) != NULL) { + + while (fread(&file, sizeof(file), 1, fdb) == 1) { + if (strlen(file.Name) == strlen(TIC.NewName)) { + if (strcasecmp(file.Name, TIC.NewName) != 0) { + Found = TRUE; + for (i = 0; i < strlen(TIC.NewName); i++) { + if ((TIC.TicIn.Replace[i] != '?') && + (toupper(TIC.TicIn.Replace[i]) != toupper(file.Name[i]))) + Found = FALSE; + } + if (Found) { + Syslog('+', "Replace: Deleting: %s", file.Name); + file.Deleted = TRUE; + fseek(fdb, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, fdb); + DidDelete = TRUE; + } + } + } + } + fclose(fdb); + } + } + + /* + * Handle the Keep number of files option + */ + if (TIC.KeepNum) { + if ((fdb = fopen(fdbname, "r")) != NULL) { + + while (fread(&file, sizeof(file), 1, fdb) == 1) { + + if ((strlen(file.Name) == strlen(TIC.NewName)) && (!file.Deleted)) { + Found = TRUE; + + for (i = 0; i < strlen(file.Name); i++) { + if ((TIC.NewName[i] < '0') || (TIC.NewName[i] > '9')) { + if (TIC.NewName[i] != file.Name[i]) { + Found = FALSE; + } + } + } + if (Found) { + Keep++; + fill_fdlist(&fdl, file.Name, file.UploadDate); + } + } + } + fclose(fdb); + } + + /* + * If there are files to delete, mark them. + */ + if (Keep > TIC.KeepNum) { + sort_fdlist(&fdl); + + if ((fdb = fopen(fdbname, "r+")) != NULL) { + for (i = 0; i < (Keep - TIC.KeepNum); i++) { + fname = pull_fdlist(&fdl); + fseek(fdb, 0, SEEK_SET); + + while (fread(&file, sizeof(file), 1, fdb) == 1) { + if (strcmp(file.Name, fname) == 0) { + Syslog('+', "Keep %d files, deleting: %s", TIC.KeepNum, file.Name); + file.Deleted = TRUE; + fseek(fdb, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, fdb); + DidDelete = TRUE; + } + } + } + fclose(fdb); + } + } + tidy_fdlist(&fdl); + } + + /* + * Now realy delete the marked files and clean the file + * database. + */ + if (DidDelete) { + if ((fdb = fopen(fdbname, "r")) != NULL) { + if ((fdt = fopen(fdbtemp, "a+")) != NULL) { + while (fread(&file, sizeof(file), 1, fdb) == 1) + if (!file.Deleted) + fwrite(&file, sizeof(file), 1, fdt); + else { + sprintf(temp2, "%s/%s", area.Path, file.Name); + if (unlink(temp2) != 0) + WriteError("$Can't unlink file %s", temp2); + } + fclose(fdb); + fclose(fdt); + if (unlink(fdbname) == 0) { + rename(fdbtemp, fdbname); + } else { + WriteError("$Can't unlink %s", fdbname); + unlink(fdbtemp); + } + } else { + fclose(fdb); + } + DidDelete = FALSE; + } + } + + tic_imp++; + return TRUE; +} + + diff --git a/mbfido/addbbs.h b/mbfido/addbbs.h new file mode 100644 index 00000000..aefb025c --- /dev/null +++ b/mbfido/addbbs.h @@ -0,0 +1,9 @@ +#ifndef _ADDBBS_H +#define _ADDBBS_H + + +int Add_BBS(void); + + +#endif + diff --git a/mbfido/addpkt.c b/mbfido/addpkt.c new file mode 100644 index 00000000..e02e7f15 --- /dev/null +++ b/mbfido/addpkt.c @@ -0,0 +1,244 @@ +/***************************************************************************** + * + * File ..................: mbfido/addpkt.c + * Purpose ...............: Add mail to .pkt + * Last modification date : 02-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "pack.h" +#include "addpkt.h" + + + +static char *months[]={(char *)"Jan",(char *)"Feb",(char *)"Mar", + (char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep", + (char *)"Oct",(char *)"Nov",(char *)"Dec"}; + +extern int do_unprot; + + +FILE *CreatePkt(char *, fidoaddr, fidoaddr, char *); +FILE *CreatePkt(char *Queue, fidoaddr Orig, fidoaddr Dest, char *Extension) +{ + FILE *qp; + unsigned char buffer[0x3a]; + time_t Now; + int i; + struct tm *Tm; + char str[81]; + + if ((qp = fopen(Queue, "a")) == NULL) { + WriteError("$Can't create Queue %s", Queue); + return NULL; + } + + /* + * Write .PKT header, see FSC-0039 rev. 4 + */ + memset(&buffer, 0, sizeof(buffer)); + time(&Now); + Tm = localtime(&Now); + if (Tm->tm_sec > 59) + Tm->tm_sec = 59; + + buffer[0x00] = (Orig.node & 0x00ff); + buffer[0x01] = (Orig.node & 0xff00) >> 8; + buffer[0x02] = (Dest.node & 0x00ff); + buffer[0x03] = (Dest.node & 0xff00) >> 8; + buffer[0x04] = ((Tm->tm_year + 1900) & 0x00ff); + buffer[0x05] = ((Tm->tm_year + 1900) & 0xff00) >> 8; + buffer[0x06] = Tm->tm_mon; + buffer[0x08] = Tm->tm_mday; + buffer[0x0a] = Tm->tm_hour; + buffer[0x0c] = Tm->tm_min; + buffer[0x0e] = Tm->tm_sec; + buffer[0x12] = 2; + buffer[0x14] = (Orig.net & 0x00ff); + buffer[0x15] = (Orig.net & 0xff00) >> 8; + buffer[0x16] = (Dest.net & 0x00ff); + buffer[0x17] = (Dest.net & 0xff00) >> 8; + buffer[0x18] = 0xfe; + + memset(&str, 0, 8); /* Packet password */ + if (SearchNode(Dest)) { + if (strlen(nodes.Epasswd)) { + sprintf(str, "%s", nodes.Epasswd); + } + } + + for (i = 0; i < 8; i++) + buffer[0x1a + i] = str[i]; + + buffer[0x22] = (Orig.zone & 0x00ff); + buffer[0x23] = (Orig.zone & 0xff00) >> 8; + buffer[0x24] = (Dest.zone & 0x00ff); + buffer[0x25] = (Dest.zone & 0xff00) >> 8; + buffer[0x29] = 1; + buffer[0x2c] = 1; + buffer[0x2e] = buffer[0x22]; + buffer[0x2f] = buffer[0x23]; + buffer[0x30] = buffer[0x24]; + buffer[0x31] = buffer[0x25]; + buffer[0x32] = (Orig.point & 0x00ff); + buffer[0x33] = (Orig.point & 0xff00) >> 8; + buffer[0x34] = (Dest.point & 0x00ff); + buffer[0x35] = (Dest.point & 0xff00) >> 8; + buffer[0x36] = 'm'; + buffer[0x37] = 'b'; + buffer[0x38] = 's'; + buffer[0x39] = 'e'; + fwrite(buffer, 1, 0x3a, qp); + + fsync(fileno(qp)); + return qp; +} + + + +/* + * Open a .pkt file on the queue, create a fresh one if needed. + * If CFG.maxpktsize is set then it will add the .pkt to the + * ARCmail archive when possible. + */ +FILE *OpenPkt(fidoaddr Orig, fidoaddr Dest, char *Extension) +{ + char Queue[128], qname[128]; + FILE *qp; + + sprintf(Queue, "%s/tmp/%d.%d.%d.%d.%s", getenv("MBSE_ROOT"), + Dest.zone, Dest.net, Dest.node, Dest.point, Extension); + + if (file_exist(Queue, R_OK)) + qp = CreatePkt(Queue, Orig, Dest, Extension); + else { + if ((qp = fopen(Queue, "a")) == NULL) { + WriteError("$Can't reopen Queue %s", Queue); + return NULL; + } + + if (CFG.maxpktsize && (ftell(qp) >= (CFG.maxpktsize * 1024)) && + (strncmp(Extension, "qqq", 3) == 0)) { + /* + * It's a pkt that's meant to be send archived and it's + * bigger then maxpktsize. Try to add this pkt to the + * outbound archive for this node. + */ + sprintf(qname, "%s/tmp", getenv("MBSE_ROOT")); + chdir(qname); + sprintf(qname, "%d.%d.%d.%d.qqq", Dest.zone, Dest.net, Dest.node, Dest.point); + fsync(fileno(qp)); + fclose(qp); + if (pack_queue(qname) == TRUE) { + /* + * If the pack succeeded create a fresh packet. + */ + qp = CreatePkt(Queue, Orig, Dest, Extension); + } else { + /* + * If the pack failed the existing queue is + * reopened and we continue adding to that + * existing packet. This is the case when the + * node is locked. + */ + Syslog('s', "pack_queue failed"); + qp = fopen(Queue, "a"); + } + + /* + * Go back to the original inbound directory. + */ + if (do_unprot) + chdir(CFG.inbound); + else + chdir(CFG.pinbound); + } + } + + return qp; +} + + + +int AddMsgHdr(FILE *fp, faddr *f, faddr *t, int flags, int cost, time_t date, char *tname, char *fname, char *subj) +{ + unsigned char buffer[0x0e]; + struct tm *Tm; + + if ((tname == NULL) || (strlen(tname) > 36) || + (fname == NULL) || (strlen(fname) > 36) || + (subj == NULL) || (strlen(subj) > 72)) + return 1; + + buffer[0x00] = 2; + buffer[0x01] = 0; + buffer[0x02] = (f->node & 0x00ff); + buffer[0x03] = (f->node & 0xff00) >> 8; + buffer[0x04] = (t->node & 0x00ff); + buffer[0x05] = (t->node & 0xff00) >> 8; + buffer[0x06] = (f->net & 0x00ff); + buffer[0x07] = (f->net & 0xff00) >> 8; + buffer[0x08] = (t->net & 0x00ff); + buffer[0x09] = (t->net & 0xff00) >> 8; + buffer[0x0a] = (flags & 0x00ff); + buffer[0x0b] = (flags & 0xff00) >> 8; + buffer[0x0c] = (cost & 0x00ff); + buffer[0x0d] = (cost & 0xff00) >> 8; + fwrite(buffer, 1, sizeof(buffer), fp); + + if (date == (time_t)0) { + date = time(NULL); + Tm = localtime(&date); + } else + Tm = gmtime(&date); + + /* + * According to the manpage the tm_sec value is in the range 0..61 + * to allow leap seconds. FTN networks don't allow this, so if this + * happens we reset the leap seconds. + */ + if (Tm->tm_sec > 59) + Tm->tm_sec = 59; + + fprintf(fp, "%02d %-3.3s %02d %02d:%02d:%02d%c", + Tm->tm_mday % 100, months[Tm->tm_mon], Tm->tm_year % 100, + Tm->tm_hour % 100, Tm->tm_min % 100, Tm->tm_sec % 100, '\0'); + + fprintf(fp, "%s%c", tname, '\0'); + fprintf(fp, "%s%c", fname, '\0'); + fprintf(fp, "%s%c", subj, '\0'); + fsync(fileno(fp)); + return 0; +} + diff --git a/mbfido/addpkt.h b/mbfido/addpkt.h new file mode 100644 index 00000000..c47b53c7 --- /dev/null +++ b/mbfido/addpkt.h @@ -0,0 +1,10 @@ +#ifndef _ADDPKT_H +#define _ADDPKT_H + + +FILE *OpenPkt(fidoaddr, fidoaddr, char *); +int AddMsgHdr(FILE *, faddr *, faddr *, int, int, time_t, char *, char *, char *); + + +#endif + diff --git a/mbfido/aliasdb.c b/mbfido/aliasdb.c new file mode 100644 index 00000000..935ead89 --- /dev/null +++ b/mbfido/aliasdb.c @@ -0,0 +1,217 @@ +/***************************************************************************** + * + * File ..................: mbfido/aliasdb.c + * Purpose ...............: Alias Database + * Last modification date : 11-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "aliasdb.h" + + + +typedef struct _aliasrec { + char freename[MAXNAME]; /* Internet address */ + char address[128]; /* Fidonet address */ + time_t dtime; /* Time the record is added/updated */ +} aliasrec; + + +static int opened = 0; +FILE *afp = NULL; + + +static int alias_db_init(void); +void close_alias_db(void); + + +static int alias_db_init(void) +{ + char buf[PATH_MAX]; + struct stat stbuf; + int tries = 0; + struct flock txflock; + + txflock.l_type = F_WRLCK; + txflock.l_whence = SEEK_SET; + txflock.l_start = 0L; + txflock.l_len = 0L; + + if (opened == -1) + return -1; + if (opened) + return 0; + + sprintf(buf, "%s/var/aliases.data", getenv("MBSE_ROOT")); + if (stat(buf, &stbuf) != 0) { + afp = fopen(buf,"a"); + if (afp) + fclose(afp); + } + + if ((afp = fopen(buf, "r+")) == NULL) { + WriteError("$Can't open %s", buf); + return -1; + } + + /* + * Now lock it. + */ + while (fcntl(fileno(afp), F_SETLK, &txflock) != 0) { + if (tries > 4) + Syslog('+', "Alias database locked %d errno=%d %s", tries +1, errno, strerror(errno)); + usleep(250000); + if (++tries >= 60) { + fclose(afp); + afp = NULL; + WriteError("$Error locking alias database"); + return -1; + } + } + + opened = 1; + return 0; +} + + + +int registrate(char *freename, char *address) +{ + char buf[128], *p, *q; + int first; + aliasrec key; + + if (alias_db_init()) + return 1; + + if (strlen(freename) > MAXNAME) + freename[MAXNAME] = '\0'; + strncpy(buf, freename, sizeof(buf)-1); + first = TRUE; + for (p = buf, q = buf; *p; p++) + switch (*p) { + case '.': *p=' '; /* fallthrough */ + case ' ': if (first) { + *(q++) = *p; + first = FALSE; + } + break; + default: *(q++) = *p; + first = 1; + break; + } + + *q = '\0'; + Syslog('m', "Registrate \"%s\" \"%s\"", MBSE_SS(buf), MBSE_SS(address)); + + while (fread(&key, sizeof(key), 1, afp)) { + if (!strcmp(key.freename, buf)) { + /* + * Already present, update date/time. + */ + time(&key.dtime); + fseek(afp, - sizeof(key), SEEK_CUR); + fwrite(&key, sizeof(key), 1, afp); + close_alias_db(); + return 1; + } + } + + sprintf(key.freename, "%s", buf); + sprintf(key.address, "%s", address); + time(&key.dtime); + + if (fwrite(&key, sizeof(key), 1, afp) != 1) { + WriteError("$Cannot store: \"%s\" \"%s\"", MBSE_SS(buf), MBSE_SS(address)); + } else { + Syslog('m', "Registered \"%s\" as \"%s\"", MBSE_SS(buf), MBSE_SS(address)); + } + close_alias_db(); + return 1; +} + + + +char *lookup(char *freename) +{ + static char buf[128], *p, *q; + int first; + aliasrec key; + + if (alias_db_init()) + return NULL; + + strncpy(buf, freename, sizeof(buf) -1); + first = TRUE; + for (p = buf, q = buf; *p; p++) + switch (*p) { + case '.': *p=' '; /* fallthrough */ + case ' ': if (first) { + *(q++) = *p; + first = FALSE; + } + break; + default: *(q++) = *p; + first = TRUE; + break; + } + + *q = '\0'; + Syslog('m', "Lookup \"%s\"", MBSE_SS(freename)); + + while (fread(&key, sizeof(key), 1, afp)) { + if (!strcmp(key.freename, buf)) { + /* + * Already present + */ + close_alias_db(); + Syslog('m',"Found: \"%s\"",buf); + return buf; + } + } + + Syslog('m',"Not found: \"%s\"",buf); + close_alias_db(); + return NULL; +} + + + +void close_alias_db(void) +{ + if (opened != 1) + return; + fclose(afp); + afp = NULL; + opened = 0; +} + + diff --git a/mbfido/aliasdb.h b/mbfido/aliasdb.h new file mode 100644 index 00000000..951d21b3 --- /dev/null +++ b/mbfido/aliasdb.h @@ -0,0 +1,12 @@ +#ifndef _ALIASDB_H +#define _ALIASDB_H + + +#define MAXNAME 35 + +int registrate(char *, char *); +char *lookup(char *); + + +#endif + diff --git a/mbfido/announce.c b/mbfido/announce.c new file mode 100644 index 00000000..f45b49e4 --- /dev/null +++ b/mbfido/announce.c @@ -0,0 +1,470 @@ +/***************************************************************************** + * + * File ..................: mbaff/announce.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "grlist.h" +#include "msgutil.h" +#include "announce.h" + + +extern int do_quiet; /* Supress screen output */ +struct _filerecord T_File; /* Internal announce record */ +int TotalFiles; /* Total announced files */ +unsigned long TotalSize; /* Total size in KBytes. */ +int MsgCount; /* Message counter */ + + + +/* + * Add a file whos data is in T_File to the toberep.data file. + */ +int Add_ToBeRep(void); +int Add_ToBeRep() +{ + char *fname; + struct _filerecord Temp; + FILE *tbr; + int Found = FALSE; + + fname = calloc(PATH_MAX, sizeof(char)); + sprintf(fname, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + if ((tbr = fopen(fname, "a+")) == NULL) { + WriteError("$Can't create %s", fname); + free(fname); + return FALSE; + } + free(fname); + + fseek(tbr, 0, SEEK_SET); + while (fread(&Temp, sizeof(Temp), 1, tbr) == 1) { + if ((strcmp(Temp.Name, T_File.Name) == 0) && + (Temp.Fdate = T_File.Fdate)) + Found = TRUE; + } + + if (Found) { + Syslog('!', "File %s already in toberep.data", T_File.Name); + fclose(tbr); + return FALSE; + } + + fwrite(&T_File, sizeof(T_File), 1, tbr); + fclose(tbr); + return TRUE; +} + + + +/* + * Check for uploads, these are files in the files database with + * the announced flag not yet set. + */ +void Uploads(void); +void Uploads() +{ + FILE *pAreas, *pFile; + char *sAreas, *fAreas; + int Count = 0, i = 0, j, k; + + sAreas = calloc(PATH_MAX, sizeof(char)); + fAreas = calloc(PATH_MAX, sizeof(char)); + + Syslog('+', "Checking for uploads"); + IsDoing("Check uploads"); + + if (!do_quiet) { + colour(3, 0); + printf(" Checking uploads...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(sAreas, "r")) == NULL) { + WriteError("$Can't open %s", sAreas); + free(sAreas); + free(fAreas); + return; + } + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + i++; + + if (CFG.slow_util && do_quiet) + usleep(1); + + if ((area.Available) && strlen(area.NewGroup)) { + + if (!do_quiet) { + printf("\r %4d => %-44s", i, area.Name); + fflush(stdout); + } + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), i); + if ((pFile = fopen(fAreas, "r+")) != NULL) { + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if (!file.Announced) { + Syslog('m', " %d %s", i, file.Name); + memset(&T_File, 0, sizeof(T_File)); + sprintf(T_File.Echo, "AREA %d", i); + sprintf(T_File.Group, "%s", area.NewGroup); + sprintf(T_File.Comment, "%s", area.Name); + sprintf(T_File.Name, "%s", file.Name); + T_File.Size = file.Size; + T_File.SizeKb = file.Size / 1024; + T_File.Fdate = file.FileDate; + sprintf(T_File.Crc, "%08lx", file.Crc32); + sprintf(T_File.Desc, "%s %s %s %s", file.Desc[0], file.Desc[1], file.Desc[2], file.Desc[3]); + k = 0; + for (j = 0; j < 25; j++) { + if (strlen(file.Desc[j])) { + sprintf(T_File.LDesc[k], "%s", file.Desc[j]); + T_File.LDesc[k][49] = '\0'; + k++; + } + } + T_File.TotLdesc = k; + T_File.Cost = file.Cost; + T_File.Announce = TRUE; + if (Add_ToBeRep()) + Count++; + /* + * Mark file is announced. + */ + file.Announced = TRUE; + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + } + } + + fclose(pFile); + } + } + } + + if (!do_quiet) { + printf("\r \r"); + if (Count) + printf(" %d new uploads\n", Count); + fflush(stdout); + } + + if (Count) + Syslog('+', "%d new uploads", Count); + + fclose(pAreas); + free(sAreas); + free(fAreas); +} + + + +int StartMsg(void); +int StartMsg(void) +{ + if (!Msg_Open(newfiles.Area)) + return FALSE; + + if (!Msg_Lock(30L)) { + Msg_Close(); + return FALSE; + } + Msg_New(); + + CountPosted(newfiles.Area); + + sprintf(Msg.From, "%s", newfiles.From); + sprintf(Msg.To, "%s", newfiles.Too); + if (MsgCount == 1) { + sprintf(Msg.Subject, "%s", newfiles.Subject); + TotalSize = TotalFiles = 0; + } else + sprintf(Msg.Subject, "%s #%d", newfiles.Subject, MsgCount); + sprintf(Msg.FromAddress, "%s", aka2str(newfiles.UseAka)); + Msg.Written = time(NULL); + Msg.Arrived = time(NULL); + Msg.Local = TRUE; + Msg.Echomail = TRUE; + + /* + * Start message text including kludges + */ + Msg_Id(newfiles.UseAka); + Msg_Pid(); + Msg_Top(); + return TRUE; +} + + + +void FinishMsg(int); +void FinishMsg(int Final) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + + if (Final) { + MsgText_Add2((char *)""); + sprintf(temp, "This is a total of %d files, %lu Kbytes", TotalFiles, TotalSize); + MsgText_Add2(temp); + } else { + MsgText_Add2((char *)""); + MsgText_Add2((char *)"to be continued..."); + MsgCount++; + } + + if (strlen(newfiles.Origin)) + Msg_Bot(newfiles.UseAka, newfiles.Origin); + else + Msg_Bot(newfiles.UseAka, CFG.origin); + + Msg_AddMsg(); + Msg_UnLock(); + Syslog('+', "Posted message %ld, %d bytes", Msg.Id, Msg.Size); + + sprintf(temp, "%s/tmp/echomail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "a")) != NULL) { + fprintf(fp, "%s %lu\n", newfiles.Area, Msg.Id); + fclose(fp); + } + Msg_Close(); + + free(temp); +} + + + +void Report(gr_list *); +void Report(gr_list *ta) +{ + FILE *fp; + char *temp; + int i, Total = 0; + unsigned long Size = 0; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + return; + } + + while (fread(&T_File, sizeof(T_File), 1, fp) == 1) { + if ((!strcmp(T_File.Echo, ta->echo)) && + (!strcmp(T_File.Group, ta->group))) + break; + } + + sprintf(temp, "Area %s - %s", T_File.Echo, T_File.Comment); + MsgText_Add2(temp); + + fseek(fp, 0, SEEK_SET); + MsgText_Add2((char *)"------------------------------------------------------------------------"); + while (fread(&T_File, sizeof(T_File), 1, fp) == 1) { + if ((!strcmp(T_File.Echo, ta->echo)) && + (!strcmp(T_File.Group, ta->group))) { + + if (CFG.slow_util && do_quiet) + usleep(1); + + sprintf(temp, "%-12s %5lu Kb. %s", tu(T_File.Name), T_File.SizeKb, To_Low(T_File.LDesc[0],newfiles.HiAscii)); + MsgText_Add2(temp); + if (T_File.TotLdesc > 0) + for (i = 1; i < T_File.TotLdesc; i++) { + sprintf(temp, " %s", To_Low(T_File.LDesc[i],newfiles.HiAscii)); + MsgText_Add2(temp); + } + Total++; + Size += T_File.SizeKb; + + /* + * Split message the hard way. + */ + if (Msg.Size > (CFG.new_force * 1024)) { + FinishMsg(FALSE); + StartMsg(); + } + } + } + MsgText_Add2((char *)"------------------------------------------------------------------------"); + + sprintf(temp, "%d files, %lu Kb", Total, Size); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + MsgText_Add2((char *)""); + fclose(fp); + free(temp); + + /* + * Split messages the gently way. + */ + if (Msg.Size > (CFG.new_split * 1024)) { + FinishMsg(FALSE); + StartMsg(); + } + + TotalFiles += Total; + TotalSize += Size; +} + + + +int Announce() +{ + gr_list *fgr = NULL, *tmp; + char *temp; + FILE *fp; + int Count = 0, rc = FALSE; + long filepos; + char group[13]; + int i, groups, any; + + if (!do_quiet) { + colour(3, 0); + printf("Announce new files\n"); + } + + Uploads(); + + IsDoing("Announce files"); + + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + Syslog('+', "No new files to announce"); + free(temp); + if (!do_quiet) { + printf(" No new files.\n"); + } + return FALSE; + } + + if (!do_quiet) + printf(" Preparing reports...\n"); + + while (fread(&T_File, sizeof(T_File), 1, fp) == 1) { + if (T_File.Announce) { + fill_grlist(&fgr, T_File.Group, T_File.Echo); + Count++; + } + } + + fclose(fp); + + if (Count == 0) { + unlink(temp); + if (!do_quiet) + printf(" No new files.\n"); + Syslog('+', "No new files to announce"); + free(temp); + return FALSE; + } + + if (!do_quiet) + printf(" %d new files found\n", Count); + + sort_grlist(&fgr); + + /* + * At this point we have a sorted list of groups with a counter + * indicating howmany files to report in each group. + */ + sprintf(temp, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + if (!do_quiet) + printf(" No newfile reports defined\n"); + free(temp); + return FALSE; + } + fread(&newfileshdr, sizeof(newfileshdr), 1, fp); + groups = newfileshdr.grpsize / 13; + + while (fread(&newfiles, newfileshdr.recsize, 1, fp) == 1) { + if (newfiles.Active) { + filepos = ftell(fp); + if (!do_quiet) { + printf(" %s\n", newfiles.Comment); + } + any = FALSE; + + for (i = 0; i < groups; i++) { + fread(&group, 13, 1, fp); + for (tmp = fgr; tmp; tmp = tmp->next) + if (strcmp(tmp->group, group) == 0) + any = TRUE; + } + if (any) { + fseek(fp, filepos, SEEK_SET); + rc = TRUE; + Syslog('+', "Create report: %s", newfiles.Comment); + MsgCount = 1; + if (StartMsg()) { + while (fread(&group, 13, 1, fp) == 1) { + for (tmp = fgr; tmp; tmp = tmp->next) + if (!strcmp(tmp->group, group)) { + Report(tmp); + } + } + } + FinishMsg(TRUE); + } + + fseek(fp, filepos, SEEK_SET); + } + + fseek(fp, newfileshdr.grpsize, SEEK_CUR); + } + fclose(fp); + + tidy_grlist(&fgr); + + if (rc) { + sprintf(temp, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + unlink(temp); + } + + free(temp); + return rc; +} + + diff --git a/mbfido/announce.h b/mbfido/announce.h new file mode 100644 index 00000000..70fbbf7d --- /dev/null +++ b/mbfido/announce.h @@ -0,0 +1,9 @@ +#ifndef _MBAFF_H_ +#define _MBAFF_H + + +int Announce(void); /* Announce files */ + + +#endif + diff --git a/mbfido/areamgr.c b/mbfido/areamgr.c new file mode 100644 index 00000000..e7be7e70 --- /dev/null +++ b/mbfido/areamgr.c @@ -0,0 +1,1105 @@ +/***************************************************************************** + * + * File ..................: mbfido/areamgr.c + * Purpose ...............: AreaMgr + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "sendmail.h" +#include "mgrutil.h" +#include "scan.h" +#include "areamgr.h" + + + +/* + * External declarations + */ +extern int do_quiet; + + + +/* + * Global variables + */ +extern int net_in; /* Netmails received */ +extern int net_out; /* Netmails forwarded */ +extern int net_bad; /* Bad netmails (tracking errors */ +extern int echo_in; /* Echomail received */ +extern int echo_imp; /* Echomail imported */ +extern int echo_out; /* Echomail forwarded */ +extern int echo_bad; /* Bad echomail */ +extern int echo_dupe; /* Dupe echomail */ +extern char *subj; /* Message subject */ +extern char *msgid; /* Original message id */ + +int areamgr = 0; /* Nr of AreaMgr messages */ +int a_help = FALSE; +int a_list = FALSE; +int a_query = FALSE; +int a_stat = FALSE; +int a_unlnk = FALSE; +int a_flow = FALSE; +unsigned long a_msgs = 0; + + + +void A_Help(faddr *); +void A_Help(faddr *t) +{ + FILE *fp; + + Syslog('+', "AreaMgr: Help"); + + if ((fp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"AreaMgr help", msgid)) != NULL) { + fprintf(fp, "Address all requests to '%s' (without quotes)\r", (char *)"Areamgr"); + fprintf(fp, "Youre AreaMgr password goes on the subject line.\r\r"); + + fprintf(fp, "In the body of the message to AreaMgr:\r\r"); + + fprintf(fp, "+ To connect to an echomail area\r"); + fprintf(fp, "- To disconnect from an echomail area\r"); + fprintf(fp, "%%+ALL To connect to all echomail areas\r"); + fprintf(fp, "%%-ALL To disconnect from all echomail areas\r"); + fprintf(fp, "%%+ To connect all echomail areas of a group\r"); + fprintf(fp, "%%- To disconnect from all echomail areas of a group\r"); + fprintf(fp, "%%HELP To request this help message\r"); + fprintf(fp, "%%LIST To request a list of echomail areas available to you\r"); + fprintf(fp, "%%QUERY To request a list of echomail areas for which you are active\r"); + fprintf(fp, "%%UNLINKED To request a list of echomail areas available to you\r"); + fprintf(fp, " to which you are not already connected\r"); + fprintf(fp, "%%FLOW To request a flow report of available areas\r"); + fprintf(fp, "%%STATUS To request a status report for your system\r"); +// fprintf(fp, "%%PAUSE To temporary disconnect from the connected echomail areas\r"); +// fprintf(fp, "%%RESUME To reconnect the temporary disconnected echomail areas\r"); + fprintf(fp, "%%PWD=newpwd To set a new AreaMgr and FileMgr password\r"); + fprintf(fp, "%%MSGS To set max. number of messages to be rescanned\r"); + fprintf(fp, "%%RESCAN To request messages from 'area' again\r"); + fprintf(fp, "%%NOTIFY=On/Off To switch the notify function on or off\r"); + fprintf(fp, "[---] Everything below the tearline is ignored\r\r"); + + fprintf(fp, "Example:\r\r"); + + fprintf(fp, " By: %s\r", nodes.Sysop); + fprintf(fp, " To: %s, %s\r", (char *)"Areamgr", ascfnode(bestaka_s(t), 0xf)); + fprintf(fp, " Re: %s\r", nodes.Apasswd); + fprintf(fp, " St: Pvt Local Kill\r"); + fprintf(fp, " ----------------------------------------------------------\r"); + fprintf(fp, " +SYSOPS\r"); + fprintf(fp, " -GENERAL\r"); + fprintf(fp, " %%QUERY\r"); + fprintf(fp, " %%LIST\r\r"); + + fprintf(fp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(fp, t); + net_out++; + } else + WriteError("Can't create netmail"); +} + + + +void A_Query(faddr *); +void A_Query(faddr *t) +{ + FILE *qp, *gp, *mp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[5]; + faddr *f; + sysconnect System; + + Syslog('+', "AreaMgr: Query"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"Your query request", msgid)) != NULL) { + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all connected message areas\r\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", mgroup.Name, mgroup.Comment); + fprintf(qp, "Con Message area Description\r"); + fprintf(qp, "----------------------------------------------------------------------------\r"); + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if (!strcmp(Group, msgs.Group) && msgs.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, mp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + if (System.cutoff) + Stat[3] = 'C'; + } + } + + if (Stat[0] == 'S' || Stat[1] == 'R') { + fprintf(qp, "%s %-25s %s\r", Stat, msgs.Tag, msgs.Name); + SubTot++; + Total++; + } + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + + fprintf(qp, "----------------------------------------------------------------------------\r"); + fprintf(qp, "%d connected area(s)\r\r\r", SubTot); + } + } + } + fprintf(qp, "Total: %d connected area(s)\r\r\r", Total); + + fclose(mp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive mail from my system\r"); + fprintf(qp, " S - You may send mail to my system\r"); + fprintf(qp, " P - The message area is temporary paused\r"); + fprintf(qp, " C - You are cutoff from this area\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void A_List(faddr *t, int Notify) +{ + FILE *qp, *gp, *mp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[5]; + faddr *f; + sysconnect System; + + if (Notify) + Syslog('+', "AreaMgr: Notify to %s", ascfnode(t, 0xff)); + else + Syslog('+', "AreaMgr: List"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"AreaMgr List", msgid)) != NULL) { + + WriteMailGroups(qp, f); + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all message areas\r\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", mgroup.Name, mgroup.Comment); + fprintf(qp, "Con Message area Description\r"); + fprintf(qp, "----------------------------------------------------------------------------\r"); + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if (!strcmp(Group, msgs.Group) && msgs.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, mp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + if (System.cutoff) + Stat[3] = 'C'; + } + } + fprintf(qp, "%s %-25s %s\r", Stat, msgs.Tag, msgs.Name); + SubTot++; + Total++; + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + + fprintf(qp, "----------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + fprintf(qp, "Total: %d available area(s)\r\r\r", Total); + + fclose(mp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive mail from my system\r"); + fprintf(qp, " S - You may send mail to my system\r"); + fprintf(qp, " P - The message area is temporary paused\r"); + fprintf(qp, " C - You are cutoff from this area\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void A_Flow(faddr *t, int Notify) +{ + FILE *qp, *gp, *mp; + char *temp, *Group; + int i, First = TRUE, Cons; + char Stat[2]; + faddr *f; + sysconnect System; + time_t Now; + struct tm *tt; + int lmonth; + long lw, lm; + + Now = time(NULL); + tt = localtime(&Now); + lmonth = tt->tm_mon; + if (lmonth) + lmonth--; + else + lmonth = 11; + + if (Notify) + Syslog('+', "AreaMgr: Flow report to %s", ascfnode(t, 0xff)); + else + Syslog('+', "AreaMgr: Flow report"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"AreaMgr Flow report", msgid)) != NULL) { + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + fprintf(qp, "The following is a flow report of all message areas\r\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + lm = lw = 0; + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + fprintf(qp, "Group %s - %s\r\r", mgroup.Name, mgroup.Comment); +// 1 2 3 4 5 6 7 +// 12345678901234567890123456789012345678901234567890123456789012345678901234567890 + fprintf(qp, "Con Message area Last week Last Month\r"); + fprintf(qp, "---------------------------------------------------------------------------\r"); + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if (!strcmp(Group, msgs.Group) && msgs.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, mp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if ((System.receivefrom || System.sendto) && + (!System.pause) && (!System.cutoff)) + Stat[0] = 'C'; + } + } + fprintf(qp, "%s %s %9lu %10lu\r", + Stat, padleft(msgs.Tag, 50, ' '), + msgs.Received.lweek, + msgs.Received.month[lmonth]); + lm += msgs.Received.month[lmonth]; + lw += msgs.Received.lweek; + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + + fprintf(qp, "---------------------------------------------------------------------------\r"); + fprintf(qp, "Total %58lu %10lu\r\r\r", lw, lm); + } + } + } + + fclose(mp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " C - You connected to this area\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void A_Status(faddr *); +void A_Status(faddr *t) +{ + FILE *fp; + int i; + + Syslog('+', "AreaMgr: Status"); + if (Miy == 0) + i = 11; + else + i = Miy - 1; + + if ((fp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"AreaMgr status", msgid)) != NULL) { + + fprintf(fp, "Here is your (echo)mail status:\r\r"); + + fprintf(fp, "Netmail direct %s\r", GetBool(nodes.Direct)); + fprintf(fp, "Netmail crash %s\r", GetBool(nodes.Crash)); + fprintf(fp, "Netmail hold %s\r", GetBool(nodes.Hold)); + if (nodes.RouteVia.zone) + fprintf(fp, "Route via %s\r", aka2str(nodes.RouteVia)); + + fprintf(fp, "\r\rMailflow:\r\r"); + + fprintf(fp, " Last week Last month Total ever\r"); + fprintf(fp, " ---------- ---------- ----------\r"); + fprintf(fp, "Messages to you %-10ld %-10ld %-10ld\r", nodes.MailSent.lweek, nodes.MailSent.month[i], nodes.MailSent.total); + fprintf(fp, "Messages from you %-10ld %-10ld %-10ld\r", nodes.MailRcvd.lweek, nodes.MailRcvd.month[i], nodes.MailRcvd.total); + + fprintf(fp, "\rWith regards, %s\r\r", CFG.sysop_name); + + fprintf(fp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(fp, t); + net_out++; + } else + WriteError("Can't create netmail"); +} + + + +void A_Unlinked(faddr *); +void A_Unlinked(faddr *t) +{ + FILE *qp, *gp, *mp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[5]; + faddr *f; + sysconnect System; + + Syslog('+', "AreaMgr: Unlinked"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"Your unlinked request", msgid)) != NULL) { + + WriteMailGroups(qp, f); + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all available message areas\r\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", mgroup.Name, mgroup.Comment); + fprintf(qp, "Con Message area Description\r"); + fprintf(qp, "----------------------------------------------------------------------------\r"); + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if (!strcmp(Group, msgs.Group) && msgs.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, mp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + if (System.cutoff) + Stat[3] = 'C'; + } + } + + if ((!System.sendto) && (!System.receivefrom)) { + fprintf(qp, "%s %-25s %s\r", Stat, msgs.Tag, msgs.Name); + SubTot++; + Total++; + } + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + + fprintf(qp, "----------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + + fclose(mp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive mail from my system\r"); + fprintf(qp, " S - You may send mail to my system\r"); + fprintf(qp, " P - The message area is temporary paused\r"); + fprintf(qp, " C - You are cutoff from this area\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void A_Global(faddr *, char *, FILE *); +void A_Global(faddr *t, char *Cmd, FILE *tmp) +{ + ShiftBuf(Cmd, 1); + Syslog('m', " AreaMgr node %s global %s", ascfnode(t, 0x1f), Cmd); +} + + + +void A_Disconnect(faddr *, char *, FILE *); +void A_Disconnect(faddr *t, char *Area, FILE *tmp) +{ + int i, First; + char *Group; + faddr *b; + sysconnect Sys; + + Syslog('+', "AreaMgr: \"%s\"", Area); + ShiftBuf(Area, 1); + for (i=0; i < strlen(Area); i++ ) + Area[i]=toupper(Area[i]); + + if (!SearchMsgs(Area)) { + fprintf(tmp, "Area %s not found\n", Area); + Syslog('m', " Area not found"); + return; + } + + Syslog('m', " Found %s group %s", msgs.Tag, mgroup.Name); + + First = TRUE; + while ((Group = GetNodeMailGrp(First)) != NULL) { + First = FALSE; + if (strcmp(Group, mgroup.Name) == 0) + break; + } + if (Group == NULL) { + fprintf(tmp, "You may not disconnect from area %s\n", Area); + Syslog('m', " Group %s not available for node", mgroup.Name); + return; + } + + b = bestaka_s(t); + i = metric(b, fido2faddr(mgroup.UseAka)); + Syslog('m', "Aka match level is %d", i); + + if (i > METRIC_POINT) { + fprintf(tmp, "You may not disconnect area %s with nodenumber %s\n", Area, ascfnode(t, 0x1f)); + Syslog('m', " Node may not disconnect from group %s", mgroup.Name); + return; + } + + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = FALSE; + Sys.receivefrom = FALSE; + + if (!MsgSystemConnected(Sys)) { + fprintf(tmp, "You are not connected to %s\n", Area); + Syslog('m', " Node is not connected to %s", Area); + return; + } + + if (MsgSystemConnect(&Sys, FALSE)) { + + /* + * Make sure to write an overview afterwards. + */ + a_list = TRUE; + Syslog('+', "Disconnected echo area %s", Area); + fprintf(tmp, "Disconnected from area %s\n", Area); + return; + } + + fprintf(tmp, "You may not disconnect area %s\n", Area); + Syslog('+', "Didn't disconnect %s from mandatory or cutoff echo area %s", ascfnode(t, 0x1f), Area); +} + + + +void A_Connect(faddr *, char *, FILE *); +void A_Connect(faddr *t, char *Area, FILE *tmp) +{ + int i, First; + char *Group; + faddr *b; + sysconnect Sys; + + Syslog('+', "AreaMgr: \"%s\"", printable(Area, 0)); + + if (Area[0] == '+') + ShiftBuf(Area, 1); + for (i=0; i < strlen(Area); i++ ) + Area[i]=toupper(Area[i]); + + if (!SearchMsgs(Area)) { + fprintf(tmp, "Area %s not found\n", Area); + Syslog('m', " Area not found"); + /* SHOULD CHECK FOR AREAS FILE AND ASK UPLINK + CHECK ALL GROUPRECORDS FOR AKA MATCH + IF MATCH CHECK FOR UPLINK AND AREAS FILE + IF FOUND, CREATE MSG AREA, CONNECT UPLINK + RESTORE NODERECORD (IS GONE!) + FALLTHRU TO CONNECT DOWNLINK + */ + return; + } + + Syslog('m', " Found %s group %s", msgs.Tag, mgroup.Name); + + First = TRUE; + while ((Group = GetNodeMailGrp(First)) != NULL) { + First = FALSE; + if (strcmp(Group, mgroup.Name) == 0) + break; + } + if (Group == NULL) { + fprintf(tmp, "You may not connect to area %s\n", Area); + Syslog('m', " Group %s not available for node %s", mgroup.Name); + return; + } + + b = bestaka_s(t); + i = metric(b, fido2faddr(mgroup.UseAka)); + Syslog('m', "Aka match level is %d", i); + + if (i > METRIC_POINT) { + fprintf(tmp, "You may not connect area %s with nodenumber %s\n", Area, ascfnode(t, 0x1f)); + Syslog('m', " Node may not connect to group %s", mgroup.Name); + return; + } + + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = TRUE; + Sys.receivefrom = TRUE; + + if (MsgSystemConnected(Sys)) { + fprintf(tmp, "You are already connected to %s\n", Area); + Syslog('m', " Node is already connected to %s", Area); + return; + } + + if (MsgSystemConnect(&Sys, TRUE)) { + + /* + * Make sure to write an overview afterwards. + */ + a_list = TRUE; + Syslog('+', "Connected echo area %s", Area); + fprintf(tmp, "Connected to area %s\n", Area); + return; + } + + fprintf(tmp, "Not connected to %s, this is not allowed\n", Area); + WriteError("Can't connect node %s to echo area %s", ascfnode(t, 0x1f), Area); +} + + + +void A_All(faddr *, int, FILE *, char *); +void A_All(faddr *t, int Connect, FILE *tmp, char *Grp) +{ + FILE *mp, *gp; + char *Group, temp[81]; + faddr *f; + int i, Link, First = TRUE, Cons; + sysconnect Sys; + long Pos; + + if (Grp == NULL) { + if (Connect) + Syslog('+', "AreaMgr: Connect All"); + else + Syslog('+', "AreaMgr: Disconnect All"); + } else { + if (Connect) + Syslog('+', "AreaMgr: Connect group %s", Grp); + else + Syslog('+', "AreaMgr: Disconnect group %s", Grp); + } + + f = bestaka_s(t); + Syslog('m', "Bestaka for %s is %s", ascfnode(t, 0x1f), ascfnode(f, 0x1f)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r+"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(Sys); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + ((Grp == NULL) || (!strcmp(Group, Grp)))) { + + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if ((!strcmp(Group, msgs.Group)) && + (msgs.Active) && (!msgs.Mandatory) && + (metric(fido2faddr(mgroup.UseAka), f) == METRIC_EQUAL)) { + + if (Connect) { + Link = FALSE; + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, mp); + if (metric(fido2faddr(Sys.aka), t) == METRIC_EQUAL) + Link = TRUE; + } + if (!Link) { + Pos = ftell(mp); + fseek(mp, - msgshdr.syssize, SEEK_CUR); + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, mp); + if (!Sys.aka.zone) { + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = TRUE; + Sys.receivefrom = TRUE; + fseek(mp, - sizeof(Sys), SEEK_CUR); + fwrite(&Sys, sizeof(Sys), 1, mp); + Syslog('+', "AreaMgr: Connected %s", msgs.Tag); + fprintf(tmp, "Connected area %s\n", msgs.Tag); + a_list = TRUE; + break; + } + } + fseek(mp, Pos, SEEK_SET); + } + } else { + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, mp); + if ((metric(fido2faddr(Sys.aka), t) == METRIC_EQUAL) && + (!Sys.cutoff)) { + memset(&Sys, 0, sizeof(Sys)); + fseek(mp, - sizeof(Sys), SEEK_CUR); + fwrite(&Sys, sizeof(Sys), 1, mp); + Syslog('+', "AreaMgr: Disconnected %s", msgs.Tag); + fprintf(tmp, "Disconnected area %s\n", msgs.Tag); + a_list = TRUE; + } + } + } + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + } + } + } + fclose(gp); + fclose(mp); +} + + + +void A_Group(faddr *, char *, int, FILE *); +void A_Group(faddr *t, char *Area, int Connect, FILE *tmp) +{ + int i; + + ShiftBuf(Area, 2); + CleanBuf(Area); + for (i=0; i < strlen(Area); i++ ) + Area[i]=toupper(Area[i]); + A_All(t, Connect, tmp, Area); +} + + + +void A_Pause(faddr *, int, FILE *); +void A_Pause(faddr *t, int Pause, FILE *tmp) +{ + return; + if (Pause) + Syslog('+', "AreaMgr: Pause"); + else + Syslog('+', "AreaMgr: Resume"); +} + + + +void A_Rescan(faddr *, char *, FILE *); +void A_Rescan(faddr *t, char *Area, FILE *tmp) +{ + int i,result; + + /* + * First strip leading garbage + */ + ShiftBuf(Area, 7); + CleanBuf(Area); + for (i=0; i < strlen(Area); i++ ) + Area[i]=toupper(Area[i]); + Syslog('+', "AreaMgr: Rescan %s, MSGS=%lu", Area, a_msgs); + result=RescanOne(t, Area, a_msgs); + if (result==0){ + if (a_msgs>0) + fprintf(tmp, "Rescan area %s, %lu last msgs.\n", Area, a_msgs); + else + fprintf(tmp, "Rescan area %s \n", Area); + } else if (result==1) + fprintf(tmp, "Can't rescan unknown area %s\n", Area); + else if (result==2) + fprintf(tmp, "%s can't rescan area %s\n", ascfnode(t, 0x1f), Area); + else + fprintf(tmp, "Fatal Error Rescanning area %s\n", Area); +} + + + +void A_Msgs(char *, int); +void A_Msgs(char *Buf, int skip) +{ + /* + * First strip leading garbage + */ + ShiftBuf(Buf, skip); + CleanBuf(Buf); + a_msgs = strtoul( Buf, (char **)NULL, 10 ); + Syslog('+', "AreaMgr: msgs %s ", Buf ); +} + + + +int AreaMgr(faddr *f, faddr *t, time_t mdate, int flags, FILE *fp) +{ + int i, rc = 0, spaces; + char *Buf; + FILE *tmp, *np; + fidoaddr Node; + + a_help = a_stat = a_unlnk = a_list = a_query = FALSE; + areamgr++; + if (SearchFidonet(f->zone)) + f->domain = xstrcpy(fidonet.domain); + + Syslog('+', "AreaMgr msg from %s", ascfnode(f, 0xff)); + + /* + * If the password failed, we return silently and don't respond. + */ + if ((!strlen(subj)) || (strcasecmp(subj, nodes.Apasswd))) { + WriteError("AreaMgr: password expected \"%s\", got \"%s\"", nodes.Apasswd, subj); + net_bad++; + return FALSE; + } + + if ((tmp = tmpfile()) == NULL) { + WriteError("$AreaMgr: Can't open tmpfile()"); + net_bad++; + return FALSE; + } + + Buf = calloc(2049, sizeof(char)); + rewind(fp); + + while ((fgets(Buf, 2048, fp)) != NULL) { + + /* + * Make sure we have the nodes record loaded + */ + memcpy(&Node, faddr2fido(f), sizeof(fidoaddr)); + SearchNode(Node); + + spaces = 0; + for (i = 0; i < strlen(Buf); i++) { + if (*(Buf + i) == ' ') + spaces++; + if (*(Buf + i) == '\t') + spaces++; + if (*(Buf + i) == '\0') + break; + if (*(Buf + i) == '\n') + *(Buf + i) = '\0'; + if (*(Buf + i) == '\r') + *(Buf + i) = '\0'; + } + + if (!strncmp(Buf, "---", 3)) + break; + + if (strlen(Buf) && (*(Buf) != '\001') && (spaces <= 1)) { + + if (!strncasecmp(Buf, "%help", 5)) + a_help = TRUE; + else if (!strncasecmp(Buf, "%query", 6)) + a_query = TRUE; + else if (!strncasecmp(Buf, "%linked", 7)) + a_query = TRUE; + else if (!strncasecmp(Buf, "%list", 5)) + a_list = TRUE; + else if (!strncasecmp(Buf, "%status", 7)) + a_stat = TRUE; + else if (!strncasecmp(Buf, "%unlinked", 9)) + a_unlnk = TRUE; + else if (!strncasecmp(Buf, "%flow", 5)) + a_flow = TRUE; + else if (!strncasecmp(Buf, "%msgs", 5)) + A_Msgs(Buf, 5); + else if (!strncasecmp(Buf, "%rescan", 7)) + A_Rescan(f, Buf, tmp); + else if (!strncasecmp(Buf, "%+all", 5)) + A_All(f, TRUE, tmp, NULL); + else if (!strncasecmp(Buf, "%-all", 5)) + A_All(f, FALSE, tmp, NULL); + else if (!strncasecmp(Buf, "%+*", 3)) + A_All(f, TRUE, tmp, NULL); + else if (!strncasecmp(Buf, "%-*", 3)) + A_All(f, FALSE, tmp, NULL); + else if (!strncasecmp(Buf, "%+", 2)) + A_Group(f, Buf, TRUE, tmp); + else if (!strncasecmp(Buf, "%-", 2)) + A_Group(f, Buf, FALSE, tmp); + else if (!strncasecmp(Buf, "%pause", 6)) + A_Pause(f, TRUE, tmp); + else if (!strncasecmp(Buf, "%resume", 7)) + A_Pause(f, FALSE, tmp); + else if (!strncasecmp(Buf, "%password", 9)) + MgrPasswd(f, Buf, tmp, 9); + else if (!strncasecmp(Buf, "%pwd", 4)) + MgrPasswd(f, Buf, tmp, 4); + else if (!strncasecmp(Buf, "%notify", 7)) + MgrNotify(f, Buf, tmp); + else if (*(Buf) == '%') + A_Global(f, Buf, tmp); + else if (*(Buf) == '-') + A_Disconnect(f, Buf, tmp); + else + A_Connect(f, Buf, tmp); + } + } + + /* + * If the temporary response file isn't empty, + * create a response netmail about what we did. + */ + if (ftell(tmp)) { + if ((np = SendMgrMail(f, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"Your AreaMgr request", msgid)) != NULL) { + + fprintf(np, " Dear %s\r\r", nodes.Sysop); + fprintf(np, "Here is the result of your AreaMgr request:\r\r"); + fseek(tmp, 0, SEEK_SET); + + while ((fgets(Buf, 2048, tmp)) != NULL) { + Buf[strlen(Buf)-1] = '\0'; + fprintf(np, "%s\r", Buf); + Syslog('m', "Rep: %s", Buf); + } + + fprintf(np, "\rWith regards, %s\r\r", CFG.sysop_name); + fprintf(np, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(np, t); + net_out++; + } else + WriteError("Can't create netmail"); + } + + free(Buf); + fclose(tmp); + + if (a_stat) + A_Status(f); + + if (a_query) + A_Query(f); + + if (a_list) + A_List(f, FALSE); + + if (a_flow) + A_Flow(f, FALSE); + + if (a_unlnk) + A_Unlinked(f); + + if (a_help) + A_Help(f); + + return rc; +} + + + diff --git a/mbfido/areamgr.h b/mbfido/areamgr.h new file mode 100644 index 00000000..caef8df0 --- /dev/null +++ b/mbfido/areamgr.h @@ -0,0 +1,12 @@ +#ifndef _AREAMGR_H +#define _AREAMGR_H + + +void A_Status(faddr *); +void A_List(faddr *, int); +void A_Flow(faddr *, int); +int AreaMgr(faddr *, faddr *, time_t, int, FILE *); + + +#endif + diff --git a/mbfido/atoul.c b/mbfido/atoul.c new file mode 100644 index 00000000..71a6054d --- /dev/null +++ b/mbfido/atoul.c @@ -0,0 +1,46 @@ +/***************************************************************************** + * + * File ..................: mbmail/atoul.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "atoul.h" + + +unsigned long atoul(char *str) +{ + unsigned long x; + + if (sscanf(str,"%lu",&x) == 1) + return x; + else + return 0xffffffff; +} + diff --git a/mbfido/atoul.h b/mbfido/atoul.h new file mode 100644 index 00000000..87bd34c7 --- /dev/null +++ b/mbfido/atoul.h @@ -0,0 +1,8 @@ +#ifndef _ATOUL_H +#define _ATOUL_H + + +unsigned long atoul(char*); + +#endif + diff --git a/mbfido/backalias.c b/mbfido/backalias.c new file mode 100644 index 00000000..f563357a --- /dev/null +++ b/mbfido/backalias.c @@ -0,0 +1,98 @@ +/***************************************************************************** + * + * File ..................: mbfido/backalias.c + * Purpose ...............: Alias functions. + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "backalias.h" + + + +static struct aliaslist { + struct aliaslist *next; + faddr *addr; + char *alias; +} *alist = NULL; + + + +char *backalias(faddr *fa) +{ + struct aliaslist *tmp; + + for (tmp = alist; tmp; tmp = tmp->next) + if ((!fa->domain || !tmp->addr->domain || !strcasecmp(fa->domain,tmp->addr->domain)) && + (!fa->zone || (fa->zone == tmp->addr->zone)) && (fa->net == tmp->addr->net) && + (fa->node == tmp->addr->node) && (fa->point == tmp->addr->point) && (fa->name) && + (tmp->addr->name) && (strcasecmp(fa->name,tmp->addr->name) == 0)) { + Syslog('m', "Address \"%s\" has local alias \"%s\"", ascinode(fa,0x7f), MBSE_SS(tmp->alias)); + return tmp->alias; + } + return NULL; +} + + + +void readalias(char *fn) +{ + FILE *fp; + char buf[256], *k, *v; + struct aliaslist *tmp = NULL; + faddr *ta = NULL; + + if ((fp = fopen(fn,"r")) == NULL) { + WriteError("$cannot open system alias file %s", MBSE_SS(fn)); + return; + } + + while (fgets(buf, sizeof(buf)-1, fp)) { + k = strtok(buf, " \t:"); + v = strtok(NULL, " \t\n\r\0:"); + if (k && v) + if ((ta = parsefaddr(v))) { + if (alist) { + tmp->next = (struct aliaslist *) xmalloc(sizeof(struct aliaslist)); + tmp = tmp->next; + } else { + alist = (struct aliaslist *) xmalloc(sizeof(struct aliaslist)); + tmp = alist; + } + tmp->next = NULL; + tmp->addr = ta; + ta = NULL; + tmp->alias = xstrcpy(k); + } + } + fclose(fp); +} + diff --git a/mbfido/backalias.h b/mbfido/backalias.h new file mode 100644 index 00000000..ea82bfef --- /dev/null +++ b/mbfido/backalias.h @@ -0,0 +1,8 @@ +#ifndef _BACKALIAS_H +#define _BACKALIAS_H + +char *backalias(faddr *); +void readalias(char *); + +#endif + diff --git a/mbfido/bread.c b/mbfido/bread.c new file mode 100644 index 00000000..cb9657a6 --- /dev/null +++ b/mbfido/bread.c @@ -0,0 +1,111 @@ +/***************************************************************************** + * + * File ..................: mbmail/bread.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 20-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "bread.h" + + +extern int pgpsigned; + + + +/* + * read short (16bit) integer in "standart" byte order + */ +int iread(FILE *fp) +{ + unsigned char lo,hi; + + fread(&lo,1,1,fp); + fread(&hi,1,1,fp); + return (hi<<8) | lo; +} + + + +/* + * read long (32bit) integer in "standart" byte order + */ +long lread(FILE *fp) +{ + int c; + unsigned char buf; + long ret = 0L; + + for (c = 0; c < 32; c += 8) { + fread(&buf, 1, 1, fp); + ret |= ((unsigned long)buf << c); + } + return ret; +} + + + +static int at_zero=0; + +char *aread(char *s, int count, FILE *fp) +{ + int i,c,next; + + if (feof(fp)) + return(NULL); + if (s == NULL) + return NULL; + if (at_zero) { + at_zero=0; + return NULL; + } + + for (i = 0, next = 1; (i> 8) & 0xff,fp); + return 0; +} + + +/* + * write long (32bit) integer in "standart" byte order + */ +int lwrite(long i, FILE *fp) +{ + int c; + + for (c = 0; c < 32; c += 8) + putc((i >> c) & 0xff,fp); + return 0; +} + + +int awrite(char *s, FILE *fp) +{ + if (s) + while (*s) + putc(*(s++), fp); + putc(0,fp); + return 0; +} + + + +/* + * write an arbitrary line to message body: change \n to \r, + */ +int cwrite(char *s, FILE *fp, int postlocal) +{ + while (*s) { + if ((*s == '\n') && !postlocal) + putc('\r',fp); + else if ((*s == '\r') && postlocal) + putc('\n',fp); + else + putc(*s, fp); + s++; + } + return 0; +} + + + +/* + * write (multiline) header to kluge: change \n to ' ' and end line with \r + */ +int kwrite(char *s, FILE *fp, int postlocal) +{ + while (*s) { + if (*s != '\n') + putc(*s, fp); + else if (*(s+1)) + putc(' ',fp); + s++; + } + if (postlocal) + putc('\n',fp); + else + putc('\r',fp); + return 0; +} + diff --git a/mbfido/bwrite.h b/mbfido/bwrite.h new file mode 100644 index 00000000..0a3b729f --- /dev/null +++ b/mbfido/bwrite.h @@ -0,0 +1,11 @@ +#ifndef _BWRITE_H +#define _BWRITE_H + +int iwrite(int,FILE *); +int lwrite(long,FILE *); +int awrite(char *,FILE *); +int cwrite(char *,FILE *, int); +int kwrite(char *,FILE *, int); + +#endif + diff --git a/mbfido/cookie.c b/mbfido/cookie.c new file mode 100644 index 00000000..fd036cb7 --- /dev/null +++ b/mbfido/cookie.c @@ -0,0 +1,90 @@ +/***************************************************************************** + * + * File ..................: mbfido/cookie.h + * Purpose ...............: Create a cookie + * Last modification date : 19-Mar-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "cookie.h" + + + +char *Cookie() +{ + FILE *olf; + char fname[81]; + int i, j, in, id; + int recno = 0; + long offset; + int nrecno; + static char temp[81]; + + sprintf(fname, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if ((olf = fopen(fname, "r")) == NULL) { + WriteError("$Can't open %s", fname); + return '\0'; + } + + fread(&olhdr, sizeof(olhdr), 1, olf); + while (fread(&ol, olhdr.recsize, 1, olf) == 1) { + recno++; + } + nrecno = recno; + + /* + * Generate random record number + */ + while (TRUE) { + in = nrecno; + id = getpid(); + + i = rand(); + j = i % id; + if ((j <= in)) + break; + } + + offset = olhdr.hdrsize + (j * olhdr.recsize); + if (fseek(olf, offset, SEEK_SET) != 0) { + WriteError("$Can't move pointer in %s", fname); + return '\0'; + } + fread(&ol, olhdr.recsize, 1, olf); + fclose(olf); + + memset(&temp, 0, sizeof(temp)); + strcpy(temp, ol.Oneline); + return temp; +} + + diff --git a/mbfido/cookie.h b/mbfido/cookie.h new file mode 100644 index 00000000..e2ff1462 --- /dev/null +++ b/mbfido/cookie.h @@ -0,0 +1,8 @@ +#ifndef _COOKIE_H +#define _COOKIE_H + + +char *Cookie(void); + +#endif + diff --git a/mbfido/echoout.c b/mbfido/echoout.c new file mode 100644 index 00000000..4304c6f4 --- /dev/null +++ b/mbfido/echoout.c @@ -0,0 +1,85 @@ +/***************************************************************************** + * + * File ..................: tosser/echoout.c + * Purpose ...............: Forward echomail packets + * Last modification date : 23-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "addpkt.h" +#include "echoout.h" + + + +/* + * External declarations + */ +extern char *toname; /* To user */ +extern char *fromname; /* From user */ +extern char *subj; /* Message subject */ + + + + +void EchoOut(faddr *fa, fidoaddr aka, FILE *fp, int flags, int cost, time_t date) +{ + char *buf; + FILE *qp; + faddr *From, *To; + + if ((qp = OpenPkt(msgs.Aka, aka, (char *)"qqq")) == NULL) + return; + + From = fido2faddr(msgs.Aka); + To = fido2faddr(aka); + if (AddMsgHdr(qp, From, To, flags, cost, date, toname, fromname, subj)) { + tidy_faddr(From); + tidy_faddr(To); + return; + } + + rewind(fp); + buf = calloc(2048, sizeof(char)); + + while ((fgets(buf, 2048, fp)) != NULL) { + Striplf(buf); + fprintf(qp, "%s\r", buf); + } + + free(buf); + putc(0, qp); + fsync(fileno(qp)); + fclose(qp); +} + + + diff --git a/mbfido/echoout.h b/mbfido/echoout.h new file mode 100644 index 00000000..a31d7193 --- /dev/null +++ b/mbfido/echoout.h @@ -0,0 +1,8 @@ +#ifndef _ECHOOUT_H +#define _ECHOOUT_H + + +void EchoOut(faddr *, fidoaddr, FILE *, int, int, time_t); + +#endif + diff --git a/mbfido/fflist.c b/mbfido/fflist.c new file mode 100644 index 00000000..f5b0f6cf --- /dev/null +++ b/mbfido/fflist.c @@ -0,0 +1,149 @@ +/***************************************************************************** + * + * File ..................: mbaff/fflist.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 27-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "fflist.h" + + +/* + * Tidy the filefind array + */ +void tidy_fflist(ff_list ** fdp) +{ + ff_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a search record to the array + */ +void fill_fflist(ff_list **fdp) +{ + char *b; + ff_list *tmp, *ta; + + b = calloc(44, sizeof(char)); + sprintf(b, "%s~", Msg.FromAddress); + + /* + * Add a new record + */ + tmp = (ff_list *)malloc(sizeof(ff_list)); + tmp->next = NULL; + sprintf(tmp->from, "%s", Msg.From); + sprintf(tmp->subject, "%s", Msg.Subject); + if (strchr(b, '.') == NULL) { + tmp->zone = atoi(strtok(b, ":")); + tmp->net = atoi(strtok(NULL, "/")); + tmp->node = atoi(strtok(NULL, "~")); + } else { + tmp->zone = atoi(strtok(b, ":")); + tmp->net = atoi(strtok(NULL, "/")); + tmp->node = atoi(strtok(NULL, ".")); + tmp->point = atoi(strtok(NULL, "~")); + } + sprintf(tmp->msgid, "%s", Msg.Msgid); + tmp->msgnr = Msg.Id; + tmp->done = FALSE; + + /* + * New record goes at the end. + */ + if (*fdp == NULL) + *fdp = tmp; + else + for (ta = *fdp; ta; ta = ta->next) + if (ta->next == NULL) { + ta->next = (ff_list *)tmp; + break; + } + + free(b); +} + + + +/* + * Tidy the reply files array + */ +void tidy_rflist(rf_list ** fdp) +{ + rf_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a reply file to the array + */ +void fill_rflist(rf_list **fdp, char *fname, unsigned long area) +{ + rf_list *tmp, *ta; + + /* + * Add a new record + */ + tmp = (rf_list *)malloc(sizeof(rf_list)); + tmp->next = NULL; + sprintf(tmp->filename, "%s", fname); + tmp->area = area; + + /* + * New record goes at the end. + */ + if (*fdp == NULL) + *fdp = tmp; + else + for (ta = *fdp; ta; ta = ta->next) + if (ta->next == NULL) { + ta->next = (rf_list *)tmp; + break; + } +} + + + diff --git a/mbfido/fflist.h b/mbfido/fflist.h new file mode 100644 index 00000000..c7765894 --- /dev/null +++ b/mbfido/fflist.h @@ -0,0 +1,34 @@ +#ifndef _FFLIST_H_ +#define _FFLIST_H + + +typedef struct _ff_list { /* Filefind array */ + struct _ff_list *next; + char from[36]; /* From username */ + char subject[72]; /* Search parameters */ + unsigned short zone; /* Original zone */ + unsigned short net; /* Original net */ + unsigned short node; /* Original node */ + unsigned short point; /* Original point */ + char msgid[81]; /* Original msgid */ + unsigned long msgnr; /* Original message number */ + unsigned done : 1; /* True if processed with success */ +} ff_list; + + + +typedef struct _rf_list { /* Reply filenames array */ + struct _rf_list *next; + char filename[15]; /* Filename found */ + unsigned long area; /* BBS file area number */ +} rf_list; + + +void tidy_fflist(ff_list **); +void fill_fflist(ff_list **); +void tidy_rflist(rf_list **); +void fill_rflist(rf_list **, char *, unsigned long); + + +#endif + diff --git a/mbfido/filefind.c b/mbfido/filefind.c new file mode 100644 index 00000000..6c4183a3 --- /dev/null +++ b/mbfido/filefind.c @@ -0,0 +1,523 @@ +/***************************************************************************** + * + * File ..................: mbaff/filefind.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "fflist.h" +#include "filefind.h" +#include "msgutil.h" + +/* + * The next constants are to prevent overflowing the echomail areas + * with huge replies. MAX_DESC_LINES limits the number of file description + * lines, 5 should be enough. The other two are the maximum files to report + * if in the same area or different area. + * For netmail replies there is a different limit. + */ +#define MAX_DESC_LINES 5 +#define MAX_FILES_SAMEBOARD 15 +#define MAX_FILES_OTHERBOARD 50 +#define MAX_FILES_NETMAIL 100 + + +extern int do_quiet; /* Supress screen output */ +struct _filerecord T_File; /* Internal announce record */ +int Requests = 0; /* Total found request */ +int Replies = 0; /* Total generated replies */ + + +void Back(int); +void Back(int count) +{ + int i; + + if (do_quiet) + return; + + for (i = 0; i < count; i++) + printf("\b"); + fflush(stdout); +} + + + +void Clean(int); +void Clean(int count) +{ + int i; + + if (do_quiet) + return; + + for (i = 0; i < count; i++) + printf(" "); + Back(count); +} + + + +void ScanArea(ff_list **); +void ScanArea(ff_list **ffl) +{ + unsigned long Number, Highest; + + if (!do_quiet) { + colour(3, 0); + printf("\r %-40s", scanmgr.Comment); + colour(12, 0); + printf(" (Scanning) "); + colour(13, 0); + fflush(stdout); + } + Syslog('+', "Scanning %s", scanmgr.Comment); + if (Msg_Open(scanmgr.ScanBoard)) { + Number = Msg_Lowest(); + Highest = Msg_Highest(); + + do { + if (!do_quiet) { + printf("%6lu / %6lu", Number, Highest); + Back(15); + } + + if (CFG.slow_util && do_quiet) + usleep(1); + + if (Msg_ReadHeader(Number) == TRUE) { + if (((!strcasecmp(Msg.To, "allfix")) || + (!strcasecmp(Msg.To, "filefind"))) && + (!Msg.Received)) { + Syslog('m', "Msg: %s (%lu) [%s]", Msg.From, Number, Msg.Subject); + Msg.Received = TRUE; + Msg.Read = time(NULL); + if (Msg_Lock(30L)) { + Msg_WriteHeader(Number); + Msg_UnLock(); + Syslog('m', "Marked message received"); + } + if (strlen(Msg.Subject) && strlen(Msg.FromAddress)) { + fill_fflist(ffl); + Requests++; + } + } + } + + } while (Msg_Next(&Number) == TRUE); + + Msg_Close(); + Clean(15); + } else + WriteError("$Can't open %s", scanmgr.ScanBoard); + + Back(54); + Clean(54); +} + + + +int StartReply(ff_list *); +int StartReply(ff_list *ffl) +{ + char *temp; + unsigned long crc = -1; + + if (strlen(scanmgr.ReplBoard)) { + if (!Msg_Open(scanmgr.ReplBoard)) + return FALSE; + else + CountPosted(scanmgr.ReplBoard); + } else { + if (!Msg_Open(scanmgr.ScanBoard)) + return FALSE; + else + CountPosted(scanmgr.ScanBoard); + } + + if (!Msg_Lock(30L)) { + Msg_Close(); + return FALSE; + } + Msg_New(); + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(Msg.From, "%s", CFG.sysop_name); + sprintf(Msg.To, "%s", ffl->from); + sprintf(Msg.Subject, "Re: %s", ffl->subject); + sprintf(Msg.FromAddress, "%s", aka2str(scanmgr.Aka)); + Msg.Written = time(NULL); + Msg.Arrived = time(NULL); + Msg.Local = TRUE; + if (scanmgr.NetReply) + Msg.Netmail = TRUE; + else + Msg.Echomail = TRUE; + + /* + * Start message text including kludges + */ + Msg_Id(scanmgr.Aka); + sprintf(temp, "\001REPLYID: %s", ffl->msgid); + MsgText_Add2(temp); + Msg.ReplyCRC = upd_crc32(temp, crc, strlen(temp)); + Msg_Pid(); + Msg_Top(); + + return TRUE; +} + + + +void FinishReply(int, int); +void FinishReply(int Reported, int Total) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + + MsgText_Add2((char *)""); + if (Reported < Total) { + sprintf(temp, "Listed %d out of %d files matching your search request", Reported, Total); + MsgText_Add2(temp); + MsgText_Add2((char *)"For more information, visit our BBS"); + } else { + sprintf(temp, "Found %d files matching your search request", Reported); + MsgText_Add2(temp); + } + + if (strlen(scanmgr.Origin)) + Msg_Bot(scanmgr.Aka, scanmgr.Origin); + else + Msg_Bot(scanmgr.Aka, CFG.origin); + Msg_AddMsg(); + Msg_UnLock(); + Syslog('+', "Posted message %ld", Msg.Id); + + sprintf(temp, "%s/tmp/echomail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "a")) != NULL) { + if (strlen(scanmgr.ReplBoard)) + fprintf(fp, "%s %lu\n", scanmgr.ReplBoard, Msg.Id); + else + fprintf(fp, "%s %lu\n", scanmgr.ScanBoard, Msg.Id); + fclose(fp); + } + + Msg_Close(); + free(temp); +} + + + +/* + * Scan for files for one request. + */ +void ScanFiles(ff_list *); +void ScanFiles(ff_list *tmp) +{ + char *temp, *kwd, *BigDesc; + FILE *pAreas, *pFile; + unsigned long areanr = 0, found = 0; + int i, j, k, keywrd, Found; + rf_list *rfl = NULL, *rft; + int Rep = 0, Sub = 0, Stop = FALSE; + + /* + * Check for local generated requests. + */ + if (!CFG.ct_LocalRep) { + } + + kwd = calloc(81, sizeof(char)); + temp = calloc(1024, sizeof(char)); + BigDesc = calloc(1230, sizeof(char)); + + sprintf(temp, "%s (%d:%d/%d.%d)", tmp->from, tmp->zone, tmp->net, tmp->node, tmp->point); + Syslog('+', "ff: %s [%s]", temp, tmp->subject); + + if (!do_quiet) { + colour(3, 0); + temp[40] = '\0'; + printf("\r %-40s", temp); + colour(12, 0); + printf(" (Searching)"); + colour(13, 0); + fflush(stdout); + } + + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(temp, "r")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + areanr++; + + if (CFG.slow_util && do_quiet) + usleep(1); + + if (!do_quiet) { + printf("%6lu / %6lu", areanr, found); + Back(15); + } + if (area.Available && area.FileFind) { + sprintf(temp, "%s/fdb/fdb%lu.data", getenv("MBSE_ROOT"), areanr); + if ((pFile = fopen(temp, "r")) != NULL) { + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + for (i = 0; i < 25; i++) + sprintf(BigDesc, "%s%s", BigDesc, *(file.Desc + i)); + sprintf(temp, "%s", tmp->subject); + + Found = FALSE; + while (strlen(temp) && (!Found)) { + /* + * Split the search request in + * separate words. + */ + k = strlen(temp); + for (i = 0; i < k; i++) + if (temp[i] == ' ') + break; + if (i < k) { + strncpy(kwd, temp, i); + kwd[i] = '\0'; + for (j = 0; j < (k - i -1); j++) + temp[j] = temp[j+i+1]; + temp[j] = '\0'; + } else { + sprintf(kwd, "%s", temp); + temp[0] = '\0'; + } + + /* + * Check if it's a filename search + * or a keyword search. + */ + keywrd = FALSE; + if ((kwd[0] == '/') || (kwd[0] == '\\')) { + keywrd = TRUE; + for (i = 1; i < strlen(kwd); i++) + kwd[i-1] = kwd[i]; + kwd[i-1] = '\0'; + } + tl(kwd); + + if (strlen(kwd) > 3) { + if (strstr(file.Name, kwd) != NULL) { + Found = TRUE; + Syslog('m', "Found %s in %s in filename", kwd, file.Name); + } + if (keywrd && (strstr(tl(BigDesc), kwd) != NULL)) { + Found = TRUE; + Syslog('m', "Found %s in %s in description", kwd, file.Name); + } + } + } + if (Found) { + found++; + Syslog('m', "Found %s area %d", file.Name, areanr); + fill_rflist(&rfl, file.Name, areanr); + } + strcpy(BigDesc, ""); + } + + fclose(pFile); + } else + WriteError("$Can't open %s", temp); + } + } + fclose(pAreas); + Clean(15); + } else + WriteError("$Can't open %s", temp); + + Back(12); + Clean(12); + + if (found) { + if (!do_quiet) { + colour(14, 0); + printf(" (Replying)"); + fflush(stdout); + } + + if (StartReply(tmp)) { + areanr = 0; + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(temp, "r")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + for (rft = rfl; rft; rft = rft->next) { + + if ((areanr != rft->area) && (Sub)) { + MsgText_Add2((char *)"------------------------------------------------------------------------"); + sprintf(temp, "Found %d file(s)", Sub); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + MsgText_Add2((char *)""); + Sub = 0; + } + + if (areanr != rft->area) { + fseek(pAreas, ((rft->area - 1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + sprintf(temp, "Area %lu - %s", rft->area, area.Name); + MsgText_Add2(temp); + MsgText_Add2((char *)"------------------------------------------------------------------------"); + areanr = rft->area; + } + + sprintf(temp, "%s/fdb/fdb%lu.data", getenv("MBSE_ROOT"), rft->area); + if ((pFile = fopen(temp, "r")) != NULL) { + while (fread(&file, sizeof(file), 1, pFile) == 1) + if (!strcmp(rft->filename, file.Name)) + break; + fclose(pFile); + sprintf(temp, "%-12s %5lu Kb. %s", tu(file.Name), file.Size / 1024, To_Low(file.Desc[0],scanmgr.HiAscii)); + MsgText_Add2(temp); + + /* + * We add no more then 5 description lines + * to prevent unnecesary long messages. + */ + for (i = 1; i < MAX_DESC_LINES; i++) + if (strlen(file.Desc[i])) { + sprintf(temp, " %s", To_Low(file.Desc[i],scanmgr.HiAscii)); + MsgText_Add2(temp); + } + } + Rep++; + Sub++; + + if (!scanmgr.NetReply) { + if (strlen(scanmgr.ReplBoard)) { + if (Rep >= MAX_FILES_OTHERBOARD) + Stop = TRUE; + } else { + if (Rep >= MAX_FILES_SAMEBOARD) + Stop = TRUE; + } + } else { + if (Rep >= MAX_FILES_NETMAIL) + Stop = TRUE; + } + if (Stop) + break; + } + + if (Sub) { + MsgText_Add2((char *)"------------------------------------------------------------------------"); + sprintf(temp, "Found %d file(s)", Sub); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + MsgText_Add2((char *)""); + } + + fclose(pAreas); + } + FinishReply(Rep, found); + Replies++; + } + + Back(11); + Clean(11); + } + + Back(42); + Clean(42); + + tidy_rflist(&rfl); + free(BigDesc); + free(temp); + free(kwd); +} + + + +int Filefind() +{ + char *temp; + int rc = FALSE; + FILE *fp; + ff_list *ffl = NULL, *tmp; + + IsDoing("FileFind"); + + if (!do_quiet) { + colour(3, 0); + printf("Processing FileFind requests\n"); + } + Syslog('+', "Processing FileFind requests"); + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return FALSE; + } + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fp); + + while (fread(&scanmgr, scanmgrhdr.recsize, 1, fp) == 1) { + if (scanmgr.Active) { + ScanArea(&ffl); + + for (tmp = ffl; tmp; tmp = tmp->next) { + ScanFiles(tmp); + } + tidy_fflist(&ffl); + } + } + fclose(fp); + + free(temp); + + if (Requests) { + Syslog('+', "Processed %d requests, created %d replies", Requests, Replies); + if (Replies) + rc = TRUE; + if (!do_quiet) { + colour(3, 0); + printf("Processed %d requests, created %d replies\n", Requests, Replies); + } + } + + return rc; +} + + diff --git a/mbfido/filefind.h b/mbfido/filefind.h new file mode 100644 index 00000000..3c6330ef --- /dev/null +++ b/mbfido/filefind.h @@ -0,0 +1,9 @@ +#ifndef _FILEFIND_H +#define _FILEFIND_H + + +int Filefind(void); + + +#endif + diff --git a/mbfido/filemgr.c b/mbfido/filemgr.c new file mode 100644 index 00000000..5c33e4b5 --- /dev/null +++ b/mbfido/filemgr.c @@ -0,0 +1,974 @@ +/***************************************************************************** + * + * File ..................: mbfido/filemgr.c + * Purpose ...............: FileMgr + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbtic.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "sendmail.h" +#include "mgrutil.h" +#include "filemgr.h" + + + +/* + * External declarations + */ +extern int do_quiet; + + + +/* + * Global variables + */ +extern int net_in; /* Netmails received */ +extern int net_out; /* Netmails forwarded */ +extern int net_bad; /* Bad netmails (tracking errors */ +extern int echo_in; /* Echomail received */ +extern int echo_imp; /* Echomail imported */ +extern int echo_out; /* Echomail forwarded */ +extern int echo_bad; /* Bad fileecho */ +extern int echo_dupe; /* Dupe fileecho */ +extern char *subj; /* Message subject */ +extern char *msgid; /* Original message id */ + +int filemgr = 0; /* Nr of FileMgr messages */ +int f_help = FALSE; +int f_list = FALSE; +int f_query = FALSE; +int f_stat = FALSE; +int f_unlnk = FALSE; + + + +void F_Help(faddr *); +void F_Help(faddr *t) +{ + FILE *fp; + + Syslog('+', "FileMgr: Help"); + + if ((fp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"FileMgr help", msgid)) != NULL) { + fprintf(fp, "Address all requests to '%s' (without quotes)\r", (char *)"Filemgr"); + fprintf(fp, "Youre FileMgr password goes on the subject line.\r\r"); + + fprintf(fp, "In the body of the message to FileMgr:\r\r"); + + fprintf(fp, "+ To connect to an fileecho area\r"); + fprintf(fp, "- To disconnect from an fileecho area\r"); + fprintf(fp, "%%+ALL To connect to all fileecho areas\r"); + fprintf(fp, "%%-ALL To disconnect from all fileecho areas\r"); + fprintf(fp, "%%+ To connect all fileecho areas of a group\r"); + fprintf(fp, "%%- To disconnect from all fileecho areas of a group\r"); + fprintf(fp, "%%HELP To request this help message\r"); + fprintf(fp, "%%LIST To request a list of available fileecho areas\r"); + fprintf(fp, "%%QUERY To request a list of active fileecho areas\r"); + fprintf(fp, "%%UNLINKED To request a list of available fileecho areas\r"); + fprintf(fp, " to which you are not already connected\r"); + fprintf(fp, "%%STATUS To request a status report for your system\r"); +// fprintf(fp, "%%PAUSE To temporary disconnect from the connected areas\r"); +// fprintf(fp, "%%RESUME To reconnect the temporary disconnected areas\r); + fprintf(fp, "%%PWD=newpwd To set a new AreaMgr and FileMgr password\r"); +// fprintf(fp, "%%RESCAN To request all files from 'area' again\r"); + fprintf(fp, "%%MESSGAE=On/Off To switch the message function on or off\r"); + fprintf(fp, "%%TICK=On/Off/Advanced To set the tic file mode off, normal or advanced\r"); + fprintf(fp, "%%NOTIFY=On/Off To switch the notify function on or off\r"); +// fprintf(fp, "%%RESEND To resend file 'name' with tic file\r"); + fprintf(fp, "[---] Everything below the tearline is ignored\r\r"); + + fprintf(fp, "Example:\r\r"); + + fprintf(fp, " By: %s\r", nodes.Sysop); + fprintf(fp, " To: %s, %s\r", (char *)"Filemgr", ascfnode(bestaka_s(t), 0xf)); + fprintf(fp, " Re: %s\r", nodes.Fpasswd); + fprintf(fp, " St: Pvt Local Kill\r"); + fprintf(fp, " ----------------------------------------------------------\r"); + fprintf(fp, " +MBSE_BBS\r"); + fprintf(fp, " -NODELIST\r"); + fprintf(fp, " %%QUERY\r"); + fprintf(fp, " %%LIST\r\r"); + + fprintf(fp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(fp, t); + net_out++; + } else + WriteError("Can't create netmail"); +} + + + +void F_Query(faddr *); +void F_Query(faddr *t) +{ + FILE *qp, *gp, *fp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[4]; + faddr *f; + sysconnect System; + + Syslog('+', "FileMgr: Query"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"Your query request", msgid)) != NULL) { + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + fp = fopen(temp, "r"); + fread(&tichdr, sizeof(tichdr), 1, fp); + Cons = tichdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all connected file areas\r\r"); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + (fgroup.UseAka.zone == f->zone) && + (fgroup.UseAka.net == f->net) && + (fgroup.UseAka.node == f->node) && + (fgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", fgroup.Name, fgroup.Comment); + fprintf(qp, "Con File tic Description\r"); + fprintf(qp, "------------------------------------------------------------------------\r"); + fseek(fp, tichdr.hdrsize, SEEK_SET); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + if (!strcmp(Group, tic.Group) && tic.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits. + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, fp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + + if (System.sendto || System.receivefrom) { + fprintf(qp, "%s %-20s %s\r", Stat, tic.Name, tic.Comment); + SubTot++; + Total++; + } + } + } + } else + fseek(fp, tichdr.syssize, SEEK_CUR); + } + + fprintf(qp, "------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + + fclose(fp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive files from my system\r"); + fprintf(qp, " S - You may send files in this area\r"); + fprintf(qp, " P - The file area is temporary paused\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void F_List(faddr *t, int Notify) +{ + FILE *qp, *gp, *fp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[4]; + faddr *f; + sysconnect System; + + if (Notify) + Syslog('+', "FileMgr: Notify to %s", ascfnode(t, 0xff)); + else + Syslog('+', "FileMgr: List"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"FileMgr List", msgid)) != NULL) { + + WriteFileGroups(qp, f); + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + fp = fopen(temp, "r"); + fread(&tichdr, sizeof(tichdr), 1, fp); + Cons = tichdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all file areas\r\r"); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + (fgroup.UseAka.zone == f->zone) && + (fgroup.UseAka.net == f->net) && + (fgroup.UseAka.node == f->node) && + (fgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", fgroup.Name, fgroup.Comment); + fprintf(qp, "Con File tic Description\r"); + fprintf(qp, "------------------------------------------------------------------------\r"); + fseek(fp, tichdr.hdrsize, SEEK_SET); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + if (!strcmp(Group, tic.Group) && tic.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits. + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, fp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + } + } + fprintf(qp, "%s %-20s %s\r", Stat, tic.Name, tic.Comment); + SubTot++; + Total++; + } else + fseek(fp, tichdr.syssize, SEEK_CUR); + } + + fprintf(qp, "------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + + fclose(fp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive files from my system\r"); + fprintf(qp, " S - You may send files in this area\r"); + fprintf(qp, " P - The file area is temporary paused\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void F_Status(faddr *); +void F_Status(faddr *t) +{ + FILE *fp; + int i; + + Syslog('+', "FileMgr: Status"); + if (Miy == 0) + i = 11; + else + i = Miy - 1; + + if ((fp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"FileMgr Status", msgid)) != NULL) { + + fprintf(fp, "Here is your fileecho status:\r\r"); + + fprintf(fp, "Netmail message %s\r", GetBool(nodes.Message)); + fprintf(fp, "TIC files %s\r", GetBool(nodes.Tic)); + if (nodes.Tic) + fprintf(fp, "Andvanced TIC files %s\r", GetBool(nodes.AdvTic)); + fprintf(fp, "Notify messages %s\r", GetBool(nodes.Notify)); + fprintf(fp, "Cost sharing %s\r", GetBool(nodes.Billing)); + if (nodes.Billing) { + fprintf(fp, "Send bill direct %s\r", GetBool(nodes.BillDirect)); + fprintf(fp, "Units debet %ld\r", nodes.Debet); + fprintf(fp, "Units credit %ld\r", nodes.Credit); + fprintf(fp, "Warning level %ld\r", nodes.WarnLevel); + } + + fprintf(fp, "\r\rRecent flow:\r\r"); + + fprintf(fp, " Last week Last month Total ever\r"); + fprintf(fp, " ---------- ---------- ----------\r"); + fprintf(fp, "Files sent %-10ld %-10ld %-10ld\r", nodes.FilesSent.lweek, nodes.FilesSent.month[i], nodes.FilesSent.total); + fprintf(fp, "KBytes sent %-10ld %-10ld %-10ld\r", nodes.F_KbSent.lweek, nodes.F_KbSent.month[i], nodes.F_KbSent.total); + fprintf(fp, "Files received %-10ld %-10ld %-10ld\r", nodes.FilesRcvd.lweek, nodes.FilesRcvd.month[i], nodes.FilesRcvd.total); + fprintf(fp, "KBytes received %-10ld %-10ld %-10ld\r", nodes.F_KbRcvd.lweek, nodes.F_KbRcvd.month[i], nodes.F_KbRcvd.total); + + fprintf(fp, "\rWith regards, %s\r\r", CFG.sysop_name); + + fprintf(fp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(fp, t); + net_out++; + } else + WriteError("Can't create netmail"); +} + + + +void F_Unlinked(faddr *); +void F_Unlinked(faddr *t) +{ + FILE *qp, *gp, *fp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[4]; + faddr *f; + sysconnect System; + + Syslog('+', "FileMgr: Unlinked"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"Your unlinked request", msgid)) != NULL) { + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + fp = fopen(temp, "r"); + fread(&tichdr, sizeof(tichdr), 1, fp); + Cons = tichdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all available file areas\r\r"); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + (fgroup.UseAka.zone == f->zone) && + (fgroup.UseAka.net == f->net) && + (fgroup.UseAka.node == f->node) && + (fgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", fgroup.Name, fgroup.Comment); + fprintf(qp, "Con File tic Description\r"); + fprintf(qp, "------------------------------------------------------------------------\r"); + fseek(fp, tichdr.hdrsize, SEEK_SET); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + if (!strcmp(Group, tic.Group) && tic.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits. + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, fp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + } + } + + if ((!System.sendto) && (!System.receivefrom)) { + fprintf(qp, "%s %-20s %s\r", Stat, tic.Name, tic.Comment); + SubTot++; + Total++; + } + } else + fseek(fp, tichdr.syssize, SEEK_CUR); + } + + fprintf(qp, "------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + + fclose(fp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive files from my system\r"); + fprintf(qp, " S - You may send files in this area\r"); + fprintf(qp, " P - The file area is temporary paused\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void F_Global(faddr *, char *, FILE *); +void F_Global(faddr *t, char *Cmd, FILE *tmp) +{ + ShiftBuf(Cmd, 1); + Syslog('m', " FileMgr node %s global %s", ascfnode(t, 0x1f), Cmd); +} + + + +void F_Disconnect(faddr *, char *, FILE *); +void F_Disconnect(faddr *t, char *Area, FILE *tmp) +{ + int i, First; + char *Group; + faddr *b; + sysconnect Sys; + + Syslog('+', "FileMgr: %s", Area); + ShiftBuf(Area, 1); + + if (!SearchTic(Area)) { + fprintf(tmp, "Area %s not found\n", Area); + Syslog('m', " Area not found"); + return; + } + + Syslog('m', " Found %s group %s", tic.Name, fgroup.Name); + + First = TRUE; + while ((Group = GetNodeFileGrp(First)) != NULL) { + First = FALSE; + if (strcmp(Group, fgroup.Name) == 0) + break; + } + if (Group == NULL) { + fprintf(tmp, "You may not disconnect from area %s\n", Area); + Syslog('m', " Group %s not available for node", fgroup.Name); + return; + } + + b = bestaka_s(t); + i = metric(b, fido2faddr(fgroup.UseAka)); + Syslog('m', "Aka match level is %d", i); + + if (i > METRIC_POINT) { + fprintf(tmp, "You may not disconnect area %s with nodenumber %s\n", Area, ascfnode(t, 0x1f)); + Syslog('m', " Node may not disconnect from group %s", fgroup.Name); + return; + } + + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = FALSE; + Sys.receivefrom = FALSE; + + if (!TicSystemConnected(Sys)) { + fprintf(tmp, "You are not connected to %s\n", Area); + Syslog('m', " Node is not connected to %s", Area); + return; + } + + if (!TicSystemConnect(&Sys, FALSE)) { + + /* + * Make sure to write an overview afterwards + */ + f_list = TRUE; + Syslog('+', "Disconnected file area %s", Area); + fprintf(tmp, "Disconnected from area %s\n", Area); + return; + } + + fprintf(tmp, "You may not disconnect area %s, area is mandatory\n", Area); + Syslog('+', "Didn't disconnect %s from mandatory file area %s", ascfnode(t, 0x1f), Area); +} + + + +void F_Connect(faddr *, char *, FILE *); +void F_Connect(faddr *t, char *Area, FILE *tmp) +{ + int i, First; + char *Group; + faddr *b; + sysconnect Sys; + + Syslog('+', "FileMgr: %s", Area); + + if (Area[0] == '+') + ShiftBuf(Area, 1); + + if (!SearchTic(Area)) { + fprintf(tmp, "Area %s not found\n", Area); + Syslog('m', " Area not found"); + /* SHOULD CHECK FOR AREAS FILE AND ASK UPLINK + CHECK ALL GROUPRECORDS FOR AKA MATCH + IF MATCH CHECK FOR UPLINK AND AREAS FILE + IF FOUND, CREATE TIC AREA, CONNECT UPLINK + RESTORE NODERECORD (IS GONE!) + FALLTHRU TO CONNECT DOWNLINK + */ + return; + } + + Syslog('m', " Found %s group %s", tic.Name, fgroup.Name); + + First = TRUE; + while ((Group = GetNodeFileGrp(First)) != NULL) { + First = FALSE; + if (strcmp(Group, fgroup.Name) == 0) + break; + } + if (Group == NULL) { + fprintf(tmp, "You may not connect to area %s\n", Area); + Syslog('m', " Group %s not available for node %s", fgroup.Name); + return; + } + + b = bestaka_s(t); + i = metric(b, fido2faddr(fgroup.UseAka)); + Syslog('m', "Aka match level is %d", i); + + if (i > METRIC_POINT) { + fprintf(tmp, "You may not connect area %s with nodenumber %s\n", Area, ascfnode(t, 0x1f)); + Syslog('m', " Node may not connect to group %s", fgroup.Name); + return; + } + + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = TRUE; + + if (TicSystemConnected(Sys)) { + fprintf(tmp, "You are already connected to %s\n", Area); + Syslog('m', " Node is already connected to %s", Area); + return; + } + + if (TicSystemConnect(&Sys, TRUE)) { + + /* + * Make sure to write an overview afterwards + */ + f_list = TRUE; + Syslog('+', "Connected to file area %s", Area); + fprintf(tmp, "Connected to area %s\n", Area); + return; + } + + fprintf(tmp, "Not connected to %s, internal error, sysop is notified\n", Area); + WriteError("Can't connect node %s to file area %s", ascfnode(t, 0x1f), Area); +} + + + +void F_All(faddr *, int, FILE *, char *); +void F_All(faddr *t, int Connect, FILE *tmp, char *Grp) +{ + FILE *fp, *gp; + char *Group, temp[81]; + faddr *f; + int i, Link, First = TRUE, Cons; + sysconnect Sys; + long Pos; + + if (Grp == NULL) { + if (Connect) + Syslog('+', "FileMgr: Connect All"); + else + Syslog('+', "FileMgr: Disconnect All"); + } else { + if (Connect) + Syslog('+', "FileMgr: Connect group %s", Grp); + else + Syslog('+', "FileMgr: Disconnect group %s", Grp); + } + + f = bestaka_s(t); + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + fp = fopen(temp, "r+"); + fread(&tichdr, sizeof(tichdr), 1, fp); + Cons = tichdr.syssize / sizeof(Sys); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + ((Grp == NULL) || (!strcmp(Group, Grp)))) { + + fseek(fp, tichdr.hdrsize, SEEK_SET); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + + if ((!strcmp(Group, tic.Group)) && tic.Active && + (metric(fido2faddr(fgroup.UseAka), f) == METRIC_EQUAL)) { + + if (Connect) { + Link = FALSE; + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, fp); + if (metric(fido2faddr(Sys.aka), t) == METRIC_EQUAL) + Link = TRUE; + } + if (!Link) { + Pos = ftell(fp); + fseek(fp, - tichdr.syssize, SEEK_CUR); + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, fp); + if (!Sys.aka.zone) { + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = TRUE; + fseek(fp, - sizeof(Sys), SEEK_CUR); + fwrite(&Sys, sizeof(Sys), 1, fp); + Syslog('+', "FileMgr: Connected %s", tic.Name); + fprintf(tmp, "Connected area %s\n", tic.Name); + f_list = TRUE; + break; + } + } + fseek(fp, Pos, SEEK_SET); + } + } else { + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, fp); + if (metric(fido2faddr(Sys.aka), t) == METRIC_EQUAL) { + memset(&Sys, 0, sizeof(Sys)); + fseek(fp, - sizeof(Sys), SEEK_CUR); + fwrite(&Sys, sizeof(Sys), 1, fp); + Syslog('+', "FileMgr: Disconnected %s", tic.Name); + fprintf(tmp, "Disconnected area %s\n", tic.Name); + f_list = TRUE; + } + } + } + } else + fseek(fp, tichdr.syssize, SEEK_CUR); + } + } + } + } + fclose(gp); + fclose(fp); +} + + + +void F_Group(faddr *, char *, int, FILE *); +void F_Group(faddr *t, char *Area, int Connect, FILE *tmp) +{ + ShiftBuf(Area, 2); + CleanBuf(Area); + F_All(t, Connect, tmp, Area); +} + + + +void F_Pause(faddr *, int, FILE *); +void F_Pause(faddr *t, int Pause, FILE *tmp) +{ + if (Pause) + Syslog('+', "FileMgr: Pause"); + else + Syslog('+', "FileMgr: Resume"); +} + + + +void F_Message(faddr *t, char *Buf, FILE *tmp) +{ + fidoaddr Node; + + ShiftBuf(Buf, 8); + CleanBuf(Buf); + + if (!strncasecmp(Buf, "on", 2)) + nodes.Message = TRUE; + else if (!strncasecmp(Buf, "off", 3)) + nodes.Message = FALSE; + else + return; + + UpdateNode(); + memcpy(&Node, faddr2fido(t), sizeof(fidoaddr)); + SearchNode(Node); + Syslog('+', "FileMgr: Message %s", GetBool(nodes.Message)); + fprintf(tmp, "FileMgr Message file is %s\n", GetBool(nodes.Message)); +} + + + +void F_Tick(faddr *t, char *Buf, FILE *tmp) +{ + fidoaddr Node; + + ShiftBuf(Buf, 5); + CleanBuf(Buf); + + if (!strncasecmp(Buf, "on", 2)) { + nodes.Tic = TRUE; + nodes.AdvTic = FALSE; + } else if (!strncasecmp(Buf, "off", 3)) { + nodes.Tic = nodes.AdvTic = FALSE; + } else if (!strncasecmp(Buf, "advanced", 8)) { + nodes.Tic = nodes.AdvTic = TRUE; + } else + return; + + UpdateNode(); + memcpy(&Node, faddr2fido(t), sizeof(fidoaddr)); + SearchNode(Node); + Syslog('+', "FileMgr: Tick %s, Advanced %s", nodes.Tic, nodes.AdvTic); + if (nodes.Tic) + if (nodes.AdvTic) + fprintf(tmp, "Tick mode is advanced"); + else + fprintf(tmp, "Tick mode is normal"); + else + fprintf(tmp, "Tick mode is off"); +} + + + +int FileMgr(faddr *f, faddr *t, time_t mdate, int flags, FILE *fp) +{ + int i, rc = 0, spaces; + char *Buf; + FILE *tmp, *np; + fidoaddr Node; + + f_help = f_stat = f_unlnk = f_list = f_query = FALSE; + filemgr++; + if (SearchFidonet(f->zone)) + f->domain = xstrcpy(fidonet.domain); + + Syslog('+', "FileMgr msg from %s", ascfnode(f, 0xff)); + + /* + * If the password failed, we return silently and don't respond. + */ + if ((!strlen(subj)) || (strcasecmp(subj, nodes.Fpasswd))) { + WriteError("FileMgr: password expected \"%s\", got \"%s\"", nodes.Fpasswd, subj); + net_bad++; + return FALSE; + } + + if ((tmp = tmpfile()) == NULL) { + WriteError("$FileMsr: Can't open tmpfile()"); + net_bad++; + return FALSE; + } + + Buf = calloc(2049, sizeof(char)); + rewind(fp); + + while ((fgets(Buf, 2048, fp)) != NULL) { + + /* + * Make sure we refresh the nodes record. + */ + memcpy(&Node, faddr2fido(f), sizeof(fidoaddr)); + SearchNode(Node); + + spaces = 0; + for (i = 0; i < strlen(Buf); i++) { + if (*(Buf + i) == ' ') + spaces++; + if (*(Buf + i) == '\t') + spaces++; + if (*(Buf + i) == '\0') + break; + if (*(Buf + i) == '\n') + *(Buf + i) = '\0'; + if (*(Buf + i) == '\r') + *(Buf + i) = '\0'; + } + + if (!strncmp(Buf, "---", 3)) + break; + + if (strlen(Buf) && (*(Buf) != '\001') && (spaces <= 1)) { + + if (!strncasecmp(Buf, "%help", 5)) + f_help = TRUE; + else if (!strncasecmp(Buf, "%query", 6)) + f_query = TRUE; + else if (!strncasecmp(Buf, "%linked", 7)) + f_query = TRUE; + else if (!strncasecmp(Buf, "%list", 5)) + f_list = TRUE; + else if (!strncasecmp(Buf, "%status", 7)) + f_stat = TRUE; + else if (!strncasecmp(Buf, "%unlinked", 9)) + f_unlnk = TRUE; + else if (!strncasecmp(Buf, "%+all", 5)) + F_All(f, TRUE, tmp, NULL); + else if (!strncasecmp(Buf, "%-all", 5)) + F_All(f, FALSE, tmp, NULL); + else if (!strncasecmp(Buf, "%+*", 3)) + F_All(f, TRUE, tmp, NULL); + else if (!strncasecmp(Buf, "%-*", 3)) + F_All(f, FALSE, tmp, NULL); + else if (!strncasecmp(Buf, "%+", 2)) + F_Group(f, Buf, TRUE, tmp); + else if (!strncasecmp(Buf, "%-", 2)) + F_Group(f, Buf, FALSE, tmp); + else if (!strncasecmp(Buf, "%pause", 6)) + F_Pause(f, TRUE, tmp); + else if (!strncasecmp(Buf, "%resume", 7)) + F_Pause(f, FALSE, tmp); + else if (!strncasecmp(Buf, "%password", 9)) + MgrPasswd(f, Buf, tmp, 9); + else if (!strncasecmp(Buf, "%pwd", 4)) + MgrPasswd(f, Buf, tmp, 4); + else if (!strncasecmp(Buf, "%notify", 7)) + MgrNotify(f, Buf, tmp); + else if (!strncasecmp(Buf, "%message", 8)) + F_Message(f, Buf, tmp); + else if (!strncasecmp(Buf, "%tick", 5)) + F_Tick(f, Buf, tmp); + else if (*(Buf) == '%') + F_Global(f, Buf, tmp); + else if (*(Buf) == '-') + F_Disconnect(f, Buf, tmp); + else + F_Connect(f, Buf, tmp); + } + } + + if (ftell(tmp)) { + if ((np = SendMgrMail(f, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"Your FileMgr request", msgid)) != NULL) { + + fprintf(np, " Dear %s\r\r", nodes.Sysop); + fprintf(np, "Here is the result of your FileMgr request:\r\r"); + fseek(tmp, 0, SEEK_SET); + + while ((fgets(Buf, 2048, tmp)) != NULL) { + Buf[strlen(Buf)-1] = '\0'; + fprintf(np, "%s\r", Buf); + Syslog('m', "Rep: %s", Buf); + } + + fprintf(np, "\rWith regards, %s\r\r", CFG.sysop_name); + fprintf(np, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(np, t); + net_out++; + } else + WriteError("Can't create netmail"); + } + + free(Buf); + fclose(tmp); + + if (f_stat) + F_Status(f); + + if (f_query) + F_Query(f); + + if (f_list) + F_List(f, FALSE); + + if (f_unlnk) + F_Unlinked(f); + + if (f_help) + F_Help(f); + + return rc; +} + + diff --git a/mbfido/filemgr.h b/mbfido/filemgr.h new file mode 100644 index 00000000..306c2079 --- /dev/null +++ b/mbfido/filemgr.h @@ -0,0 +1,11 @@ +#ifndef _FILEMGR_H +#define _FILEMGR_H + + +void F_Status(faddr *); +void F_List(faddr *, int); +int FileMgr(faddr *, faddr *, time_t, int, FILE *); + + +#endif + diff --git a/mbfido/flock.c b/mbfido/flock.c new file mode 100644 index 00000000..cad5fbed --- /dev/null +++ b/mbfido/flock.c @@ -0,0 +1,82 @@ +/***************************************************************************** + * + * File ..................: tosser/flock.c + * Purpose ...............: File locker + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "flock.h" + + +int f_lock(char *fn) +{ + int lfd=-1; + struct flock fl; + struct stat st; + + if (fn) { + if ((lfd = open(fn,O_RDWR | O_CREAT)) < 0) { + perror(""); + WriteError("Error opening file %s", fn); + return -1; + } + + fl.l_type=F_WRLCK; + fl.l_whence=0; + fl.l_start=0L; + fl.l_len=0L; + fl.l_pid=getpid(); + + if (fcntl(lfd,F_SETLK,&fl) != 0) { + if (errno != EAGAIN) + Syslog('+', "Error locking file %s",fn); + close(lfd); + return -1; + } + + if (stat(fn,&st) != 0) { + perror(""); + WriteError("Error accessing file %s",fn); + close(lfd); + return -1; + } + } + return lfd; +} + + + +void funlock(int fd) +{ + close(fd); + return; +} + + + diff --git a/mbfido/flock.h b/mbfido/flock.h new file mode 100644 index 00000000..b13a1749 --- /dev/null +++ b/mbfido/flock.h @@ -0,0 +1,10 @@ +/* flock.h */ + +#ifndef _FLOCK_H +#define _FLOCK_H + +int f_lock(char *); +void funlock(int); + +#endif + diff --git a/mbfido/forward.c b/mbfido/forward.c new file mode 100644 index 00000000..8e8a6376 --- /dev/null +++ b/mbfido/forward.c @@ -0,0 +1,300 @@ +/***************************************************************************** + * + * File ..................: mbfido/forward.c + * Purpose ...............: File forward to a node + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "../lib/dbtic.h" +#include "tic.h" +#include "cookie.h" +#include "sendmail.h" +#include "rollover.h" +#include "forward.h" + + + +void ForwardFile(fidoaddr Node, fa_list *sbl) +{ + char *subject = NULL, *fwdfile = NULL, *ticfile = NULL, fname[128]; + FILE *fp, *net; + char flavor; + faddr *dest, *route, *Fa; + int i, z, n; + time_t now; + fa_list *tmp; + + Syslog('+', "Forward file to %s", aka2str(Node)); + + if (!SearchNode(Node)) { + WriteError("No forward, node %s not known", Node); + return; + } + + /* + * Hier moet een nieuwe SEEN-BY check komen, maar dan wel zo dat + * de net toegevoegde seenby niet getest wordt. + */ + + /* + * Check if this node has enough credits for this file. + */ + T_File.Cost = TIC.FileCost + (TIC.FileCost * nodes.AddPerc / 1000); + if ((nodes.Credit < (nodes.StopLevel + T_File.Cost)) && (!TIC.Charge)) { + Syslog('!', "No forward to %s, not enough credit left", aka2str(Node)); + exit; + } + + /* + * Check if we are passing the warning level + */ + if ((nodes.Credit > nodes.WarnLevel) && + ((nodes.Credit - T_File.Cost) <= nodes.WarnLevel)) { + Syslog('+', "Low credit warning to %s", aka2str(Node)); + /* CREATE NETMAIL */ + } + + fwdfile = calloc(128, sizeof(char)); + /* + * Create the full filename + */ + if (TIC.SendOrg) + sprintf(fwdfile, "%s/%s", TIC.FilePath, TIC.TicIn.OrgName); + else + sprintf(fwdfile, "%s/%s", TIC.BBSpath, TIC.NewName); + + flavor = 'f'; + if (nodes.Crash) + flavor = 'c'; + if (nodes.Hold) + flavor = 'h'; + + if (nodes.RouteVia.zone) + route = fido2faddr(nodes.RouteVia); + else + route = fido2faddr(Node); + dest = fido2faddr(Node); + attach(*route, fwdfile, LEAVE, flavor); + + if (strlen(CFG.dospath)) + subject = xstrcpy(Unix2Dos(fwdfile)); + else + subject = xstrcpy(fwdfile); + + ticfile = calloc(128, sizeof(char)); + if (nodes.Tic) { + sprintf(ticfile, "%s/%08lx.tic", CFG.ticout, sequencer()); + subject = xstrcat(subject, (char *)" "); + if (strlen(CFG.dospath)) + subject = xstrcat(subject, Unix2Dos(ticfile)); + else + subject = xstrcat(subject, ticfile); + } + + /* + * Send netmail message if the node has it turned on. + */ + if (nodes.Message) { + if ((net = SendMgrMail(fido2faddr(Node), CFG.ct_KeepMgr, TRUE, (char *)"Filemgr", subject, NULL)) != NULL) { + fprintf(net, " Dear %s\r", nodes.Sysop); + fprintf(net, "\r"); + fprintf(net, "I sent the following file to your system:\r"); + fprintf(net, "\r"); + fprintf(net, "File : %s\r", TIC.TicIn.OrgName); + fprintf(net, "Description : %s\r", TIC.TicIn.Desc); + fprintf(net, "Area : %s %s\r", TIC.TicIn.Area, TIC.TicIn.AreaDesc); + fprintf(net, "Size : %ld\r", TIC.FileSize); + fprintf(net, "CRC : %s\r", TIC.TicIn.Crc); + fprintf(net, "Origin : %s\r", TIC.TicIn.Origin); + if (strlen(TIC.TicIn.Magic)) + fprintf(net, "Magic : %s\r", TIC.TicIn.Magic); + if (strlen(TIC.TicIn.Replace)) + fprintf(net, "Replaces : %s\r", TIC.TicIn.Replace); + fprintf(net, "\r\r"); + fprintf(net, "With regards, %s\r\r", CFG.sysop_name); + fprintf(net, "... %s\r\r", Cookie()); + fprintf(net, "--- MBSE BBS %s\r", VERSION); + CloseMail(net, fido2faddr(Node)); + } else { + WriteError("$Can't create netmail"); + } + } + free(subject); + + /* + * If we need a .TIC file, start creating it. + */ + if (nodes.Tic) { + mkdirs(ticfile); + if ((fp = fopen(ticfile, "a+")) != NULL) { +// subject = calloc(128, sizeof(char)); + fprintf(fp, "Area %s\r\n", TIC.TicIn.Area); + fprintf(fp, "Origin %s\r\n", TIC.TicIn.Origin); + Fa = fido2faddr(tic.Aka); + fprintf(fp, "From %s\r\n", ascfnode(Fa, 0x0f)); + free(Fa); + if (strlen(TIC.TicIn.Replace)) + fprintf(fp, "Replaces %s\r\n", TIC.TicIn.Replace); + if (strlen(TIC.TicIn.Magic)) + fprintf(fp, "Magic %s\r\n", TIC.TicIn.Magic); + if ((TIC.PassThru) || (TIC.SendOrg)) + subject = xstrcpy(TIC.TicIn.OrgName); + else + subject = xstrcpy(TIC.NewName); + fprintf(fp, "File %s\r\n", tu(subject)); + free(subject); + fprintf(fp, "Desc %s\r\n", TIC.TicIn.Desc); + fprintf(fp, "Crc %s\r\n", TIC.TicIn.Crc); + if (nodes.AdvTic) { + fprintf(fp, "To %s %s\r\n", nodes.Sysop, ascfnode(dest, 0x1f)); + fprintf(fp, "Areadesc %s\r\n", tic.Comment); + fprintf(fp, "Fdn %s\r\n", fgroup.Comment); + /* + * According to Harald Harms this field must + * be multiplied with 100. + */ + if (TIC.FileCost) + fprintf(fp, "Cost %ld.00\r\n", T_File.Cost); + if (TIC.TicIn.TotLDesc) + for (i = 0; i < TIC.TicIn.TotLDesc; i++) + fprintf(fp, "LDesc %s\r\n", TIC.TicIn.LDesc[i]); + } + fprintf(fp, "Created by MBSE BBS %s %s\r\n", VERSION, ShortRight); + if (TIC.TicIn.TotPath) + for (i = 0; i < TIC.TicIn.TotPath; i++) + fprintf(fp, "Path %s\r\n", TIC.TicIn.Path[i]); + /* + * Add our system to the path + */ + now = time(NULL); + subject = ctime(&now); + Striplf(subject); + fprintf(fp, "Path %s %lu %s %s\r\n", ascfnode(bestaka_s(dest), 0x1f), + mktime(localtime(&now)), subject, tzname[0]); + + if (nodes.AdvTic) { + /* + * In advanced TIC mode we send multiple seenby + * addresses on one line in stead of one line + * per system. + */ + z = 0; + n = 0; + subject = xstrcpy((char *)"Seenby"); + for (tmp = sbl; tmp; tmp = tmp->next) { + if (strlen(subject) > 70) { + fprintf(fp, "%s\r\n", subject); + z = 0; + n = 0; + free(subject); + subject = xstrcpy((char *)"Seenby "); + } else { + subject = xstrcat(subject, (char *)" "); + } + + if (z != tmp->addr->zone) { + subject = xstrcat(subject, ascfnode(tmp->addr, 0x0e)); + z = tmp->addr->zone; + } else { + if (n != tmp->addr->net) { + subject = xstrcat(subject, ascfnode(tmp->addr, 0x06)); + n = tmp->addr->net; + } else { + subject = xstrcat(subject, ascfnode(tmp->addr, 0x02)); + } + } + } + if (strlen(subject) > 7) { + fprintf(fp, "%s\r\n", subject); + free(subject); + } + } else { + /* + * Old style seenby lines + */ + for (tmp = sbl; tmp; tmp = tmp->next) { + fprintf(fp, "Seenby %s\r\n", ascfnode(tmp->addr, 0x0f)); + } + } + + /* + * Now append all passthru ticlines + */ + if (TIC.TicIn.Unknowns) + for (i = 0; i < TIC.TicIn.Unknowns; i++) + fprintf(fp, "%s\r\n", TIC.TicIn.Unknown[i]); + + fprintf(fp, "Pw %s\r\n", nodes.Fpasswd); + fclose(fp); + attach(*route, ticfile, KFS, flavor); + } else { + WriteError("$Can't create %s", ticfile); + } + } + + if (TIC.Charge) { + nodes.Credit -= TIC.FileCost; + Syslog('-', "Cost: %d Left: %d", TIC.FileCost, nodes.Credit); + + /* + * Add an entry to the billing file, each node has his own + * billing file. + */ + sprintf(fname, "%s/tmp/%d.%d.%d.%d.bill", getenv("MBSE_ROOT"), + nodes.Aka[0].zone, nodes.Aka[0].net, nodes.Aka[0].node, nodes.Aka[0].point); + if ((fp = fopen(fname, "a+")) != NULL) { + memset(&bill, 0, sizeof(bill)); + bill.Node = nodes.Aka[0]; + strcpy(bill.FileName, TIC.NewName); + strcpy(bill.FileEcho, TIC.TicIn.Area); + bill.Size = TIC.FileSize; + bill.Cost = TIC.FileCost; + fwrite(&bill, sizeof(bill), 1, fp); + fclose(fp); + } else { + WriteError("$Can't create %s", fname); + } + } + + /* + * Update the nodes statistic counters + */ + StatAdd(&nodes.FilesSent, 1L); + StatAdd(&nodes.F_KbSent, T_File.SizeKb); + UpdateNode(); + SearchNode(Node); + free(ticfile); + free(fwdfile); +} + + diff --git a/mbfido/forward.h b/mbfido/forward.h new file mode 100644 index 00000000..c8f5fed9 --- /dev/null +++ b/mbfido/forward.h @@ -0,0 +1,9 @@ +#ifndef _FORWARD_H +#define _FORWARD_H + + +void ForwardFile(fidoaddr, fa_list *); + + +#endif + diff --git a/mbfido/fsort.c b/mbfido/fsort.c new file mode 100644 index 00000000..d130b773 --- /dev/null +++ b/mbfido/fsort.c @@ -0,0 +1,145 @@ +/***************************************************************************** + * + * File ..................: mbfido/fsort.c + * Purpose ...............: File sort + * Last modification date : 27-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "fsort.h" + + + +/* + * Tidy the filearray + */ +void tidy_fdlist(fd_list **fdp) +{ + fd_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a file on the array. + */ +void fill_fdlist(fd_list **fdp, char *filename, time_t filedate) +{ + fd_list *tmp; + + tmp = (fd_list *)malloc(sizeof(fd_list)); + tmp->next = *fdp; + sprintf(tmp->fname, "%s", filename); + tmp->fdate = filedate; + *fdp = tmp; +} + + + +int compfdate(fd_list **, fd_list **); + + +/* + * Sort the array of files by filedate + */ +void sort_fdlist(fd_list **fdp) +{ + fd_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) { + return; + } + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (fd_list **)malloc(n * sizeof(fd_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) { + vector[i++] = ta; + } + + qsort(vector, n, sizeof(fd_list*), (int(*)(const void*, const void*))compfdate); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compfdate(fd_list **fdp1, fd_list **fdp2) +{ + return ((*fdp1)->fdate - (*fdp2)->fdate); +} + + + +/* + * Return the name of the oldest file in the array + */ +char *pull_fdlist(fd_list **fdp) +{ + static char buf[65]; + fd_list *ta; + + if (*fdp == NULL) + return NULL; + + ta = *fdp; + memset(&buf, 0, sizeof(buf)); + sprintf(buf, "%s", ta->fname); + + if (ta->next != NULL) + *fdp = ta->next; + else + *fdp = NULL; + + free(ta); + return buf; +} + + diff --git a/mbfido/fsort.h b/mbfido/fsort.h new file mode 100644 index 00000000..ea401f36 --- /dev/null +++ b/mbfido/fsort.h @@ -0,0 +1,20 @@ +#ifndef _FSORT_H +#define _FSORT_H + + + +typedef struct _fd_list { + struct _fd_list *next; + char fname[65]; + time_t fdate; +} fd_list; + + +void tidy_fdlist(fd_list **); +void fill_fdlist(fd_list **, char *, time_t); +void sort_fdlist(fd_list **); +char *pull_fdlist(fd_list **); + + +#endif + diff --git a/mbfido/grlist.c b/mbfido/grlist.c new file mode 100644 index 00000000..56886bf6 --- /dev/null +++ b/mbfido/grlist.c @@ -0,0 +1,141 @@ +/***************************************************************************** + * + * File ..................: mbaff/grlist.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 27-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "grlist.h" + + + + +/* + * Tidy the groupnames array + */ +void tidy_grlist(gr_list ** fdp) +{ + gr_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a group to the array + */ +void fill_grlist(gr_list **fdp, char *groupname, char *echoname) +{ + gr_list *tmp; + + /* + * Count files in group if the group already exists. + */ + if (*fdp != NULL) { + for (tmp = *fdp; tmp; tmp = tmp->next) + if ((strcmp(groupname, tmp->group) == 0) && + (strcmp(echoname, tmp->echo) == 0)) { + tmp->count++; + return; + } + } + + /* + * Add a new group + */ + tmp = (gr_list *)malloc(sizeof(gr_list)); + tmp->next = *fdp; + sprintf(tmp->group, "%s", groupname); + sprintf(tmp->echo, "%s", echoname); + tmp->count = 1; + *fdp = tmp; +} + + + +int compgroup(gr_list **, gr_list **); + +/* + * Sort the array of groups + */ +void sort_grlist(gr_list **fdp) +{ + gr_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) + return; + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (gr_list **)malloc(n * sizeof(gr_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) { + vector[i++] = ta; + } + + qsort(vector, n, sizeof(gr_list*), (int(*)(const void*, const void*))compgroup); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compgroup(gr_list **fdp1, gr_list **fdp2) +{ + int rc; + + rc = strcmp((*fdp1)->group, (*fdp2)->group); + if (rc != 0) + return rc; + return strcmp((*fdp1)->echo, (*fdp2)->echo); +} + + + diff --git a/mbfido/grlist.h b/mbfido/grlist.h new file mode 100644 index 00000000..d575c3ed --- /dev/null +++ b/mbfido/grlist.h @@ -0,0 +1,19 @@ +#ifndef _GRLIST_H_ +#define _GRLIST_H + + +typedef struct _gr_list { /* Announce array */ + struct _gr_list *next; + char group[13]; /* Group name */ + char echo[21]; /* Fileecho name */ + int count; /* Number of new files */ +} gr_list; + + +void tidy_grlist(gr_list **); +void fill_grlist(gr_list **, char *, char *); +void sort_grlist(gr_list **); + + +#endif + diff --git a/mbfido/hash.c b/mbfido/hash.c new file mode 100644 index 00000000..6e32f048 --- /dev/null +++ b/mbfido/hash.c @@ -0,0 +1,52 @@ +/***************************************************************************** + * + * File ..................: mbmail/hash.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "hash.h" +#include "lhash.h" + + +void hash_update_s(unsigned long *id, char *mod) +{ + *id ^= lh_strhash(mod); +} + + + +void hash_update_n(unsigned long *id, unsigned long mod) +{ + char buf[32]; + + sprintf(buf,"%030lu",mod); + *id ^= lh_strhash(buf); +} + + diff --git a/mbfido/hash.h b/mbfido/hash.h new file mode 100644 index 00000000..511bcdd9 --- /dev/null +++ b/mbfido/hash.h @@ -0,0 +1,8 @@ +#ifndef HASH_H +#define HASH_H + +void hash_update_s(unsigned long *, char *); +void hash_update_n(unsigned long *, unsigned long); + + +#endif diff --git a/mbfido/hatch.c b/mbfido/hatch.c new file mode 100644 index 00000000..3e121136 --- /dev/null +++ b/mbfido/hatch.c @@ -0,0 +1,201 @@ +/***************************************************************************** + * + * File ..................: mbfido/hatch.c + * Purpose ...............: Hatch files + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbtic.h" +#include "utic.h" +#include "rollover.h" +#include "hatch.h" + + +extern int do_quiet; + +int Days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; +int Hatched = 0; + +int CheckHatch(char *); + + +void Hatch() +{ + char *temp; + FILE *fp; + struct tm *Tm; + time_t Now; + int LastDay; + int HatchToday; + + temp = calloc(128, sizeof(char)); + Syslog('+', "Pass: hatch files"); + Now = time(NULL); + Tm = localtime(&Now); + + LastDay = Days[Tm->tm_mon]; + if (Tm->tm_mon == 1) { + /* + * Note that with this method each century change is a leapyear, + * but take in mind that fidonet will no longer exist in 2100. + */ + if (!(Tm->tm_year % 4)) + LastDay++; + } + + sprintf(temp, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return; + } + + fread(&hatchhdr, sizeof(hatchhdr), 1, fp); + + while (fread(&hatch, hatchhdr.recsize, 1, fp) == 1) { + if (hatch.Active) { + HatchToday = FALSE; + if (hatch.Days[Diw]) + HatchToday = TRUE; + if ((hatch.Month[Tm->tm_mday -1]) || + (hatch.Month[31] && (LastDay == Tm->tm_mday))) + HatchToday = TRUE; + sprintf(temp, "%s", hatch.Spec); + + if (HatchToday) + CheckHatch(temp); + } + } + + fclose(fp); + free(temp); +} + + + +int CheckHatch(char *temp) +{ + DIR *dp; + struct dirent *de; + char *fn, tf[81], tmp[4]; + int i, Match, hatched = FALSE; + FILE *Tf; + + fn = xstrcpy(strrchr(temp, '/') + 1); + + while (temp[strlen(temp) -1] != '/') + temp[strlen(temp) -1] = '\0'; + temp[strlen(temp) -1] = '\0'; + + if (chdir(temp)) { + WriteError("$Can't chdir(%s)", temp); + return FALSE; + } + + if ((dp = opendir(temp)) == NULL) { + WriteError("$Can't opendir(%s)", temp); + return FALSE; + } + + while ((de = readdir(dp))) { + Match = FALSE; + if (strlen(fn) == strlen(de->d_name)) { + Match = TRUE; + for (i = 0; i < strlen(fn); i++) { + switch(fn[i]) { + case '?' : break; + case '#' : if (!isdigit(de->d_name[i])) + Match = FALSE; + break; + case '@' : if (!isalpha(de->d_name[i])) + Match = FALSE; + break; + default : if (fn[i] != de->d_name[i]) + Match = FALSE; + } + } + } + if (Match) { + hatched = TRUE; + Syslog('+', "Hatch %s in area %s", de->d_name, hatch.Name); + sprintf(tf, "%s/%s", CFG.pinbound, MakeTicName()); + if ((Tf = fopen(tf, "a+")) == NULL) + WriteError("Can't create %s", tf); + else { + fprintf(Tf, "Hatch\r\n"); + fprintf(Tf, "Created MBSE BBS v%s, %s\r\n", VERSION, ShortRight); + fprintf(Tf, "Area %s\r\n", hatch.Name); + if (SearchTic(hatch.Name)) { + fprintf(Tf, "Origin %s\r\n", aka2str(tic.Aka)); + fprintf(Tf, "From %s\r\n", aka2str(tic.Aka)); + } else { + fprintf(Tf, "Origin %s\r\n", aka2str(CFG.aka[0])); + fprintf(Tf, "From %s\r\n", aka2str(CFG.aka[0])); + Syslog('?', "Warning: TIC group not found"); + } + if (strlen(hatch.Replace)) + fprintf(Tf, "Replaces %s\r\n", hatch.Replace); + if (strlen(hatch.Magic)) + fprintf(Tf, "Magic %s\r\n", hatch.Magic); + fprintf(Tf, "File %s\r\n", de->d_name); + fprintf(Tf, "Pth %s\r\n", temp); + fprintf(Tf, "Desc "); + for (i = 0; i < strlen(hatch.Desc); i++) { + if (hatch.Desc[i] != '%') { + fprintf(Tf, "%c", hatch.Desc[i]); + } else { + i++; + memset(&tmp, 0, sizeof(tmp)); + if (isdigit(hatch.Desc[i])) + tmp[0] = hatch.Desc[i]; + if (isdigit(hatch.Desc[i+1])) { + tmp[1] = hatch.Desc[i+1]; + i++; + } + fprintf(Tf, "%c", de->d_name[atoi(tmp) -1]); + } + } + fprintf(Tf, "\r\n"); + fprintf(Tf, "Crc %08lx\r\n", file_crc(de->d_name, CFG.slow_util && do_quiet)); + fprintf(Tf, "Pw %s\r\n", CFG.hatchpasswd); + fclose(Tf); + Hatched++; + StatAdd(&hatch.Hatched , 1); + } + } + } + closedir(dp); + free(fn); + return hatched; +} + + diff --git a/mbfido/hatch.h b/mbfido/hatch.h new file mode 100644 index 00000000..f7ec4748 --- /dev/null +++ b/mbfido/hatch.h @@ -0,0 +1,9 @@ +#ifndef _HATCH_H +#define _HATCH_H + + +void Hatch(void); + + +#endif + diff --git a/mbfido/importmsg.c b/mbfido/importmsg.c new file mode 100644 index 00000000..46bb3159 --- /dev/null +++ b/mbfido/importmsg.c @@ -0,0 +1,908 @@ +/***************************************************************************** + * + * File ..................: tosser/importmsg.c + * Purpose ...............: Import a message + * Last modification date : 05-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "echoout.h" +#include "mkrfcmsg.h" +#include "importmsg.h" +#include "postnetmail.h" +#include "rollover.h" + + + +/* + * External declarations + */ +extern int do_quiet; +extern int do_unsec; +extern int check_dupe; +extern int autocrea; +extern time_t t_start; +extern int most_debug; + + +/* + * Global variables + */ +extern int echo_in; /* Echomail received */ +extern int echo_imp; /* Echomail imported */ +extern int echo_out; /* Echomail forwarded */ +extern int echo_bad; /* Bad echomail */ +extern int echo_dupe; /* Dupe echomail */ +extern char *subj; /* Message subject */ +char *msgid = NULL; /* Message id string */ + +#define MAXPATH 73 +#define MAXSEEN 70 + + +void tidy_qualify(qualify **); +void fill_qualify(qualify **, fidoaddr, int, int); +void dlog_qualify(qualify **, char *); + + +void tidy_qualify(qualify **qal) +{ + qualify *tmp, *old; + + for (tmp = *qal; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *qal = NULL; +} + + + +void fill_qualify(qualify **qal, fidoaddr aka, int orig, int insb) +{ + qualify *tmp; + + tmp = (qualify *)malloc(sizeof(qualify)); + tmp->next = *qal; + tmp->aka = aka; + tmp->inseenby = insb; + tmp->send = ((!insb) && (!orig)); + tmp->orig = orig; + *qal = tmp; +} + + + +void dlog_qualify(qualify **qal, char *msg) +{ + qualify *tmpl; + + for (tmpl = *qal; tmpl; tmpl = tmpl->next) { + Syslog('m', "%s InSB=%s Snd=%s Org=%s", + aka2str(tmpl->aka), tmpl->inseenby ? "True":"False", + tmpl->send ? "True":"False", + tmpl->orig ? "True":"False"); + } +} + + + +/* + * Import 1 message, forward if needed. + * pkt_from, from, to, subj, orig, mdate, flags, cost, file + * + * 1 - Cannot open message base. + * 2 - Cannot open mareas.data + * 3 - Echomail without Origin line. + * 4 - Echomail from unknown node, disconnected node. + * 5 - Locking error. + * + * For echomail, the crc32 is calculated over the ^AREA kludge, subject, + * message date, origin line, message id. + */ +int importmsg(faddr *p_from, faddr *f, faddr *t, char *orig, time_t mdate, int flags, int cost, FILE *fp, off_t orig_off) +{ + char *buf, *marea = NULL, *reply = NULL; + char *p, *q, *l, *r; + int echomail = FALSE, First = FALSE, email = FALSE; + int rc = 0, i, topt = 0, fmpt = 0, kludges = TRUE; + faddr *ta, *Faddr; + int result, dupe = FALSE, bad = FALSE; + unsigned long crc, crc2; + char sbe[16]; + sysconnect Link; + fa_list *sbl = NULL, *ptl = NULL, *tmpl; + qualify *qal = NULL, *tmpq; + FILE *nfp, *qp; + int Known = FALSE, seenlen, oldnet; + int FirstLine; + + if (CFG.slow_util && do_quiet) + usleep(1); + + memset(&Link, 0, sizeof(Link)); + msgid = NULL; + + /* + * Increase uplink's statistic counter. + */ + Link.aka.zone = p_from->zone; + Link.aka.net = p_from->net; + Link.aka.node = p_from->node; + Link.aka.point = p_from->point; + if (SearchNode(Link.aka)) { + StatAdd(&nodes.MailRcvd, 1); + UpdateNode(); + SearchNode(Link.aka); + Known = TRUE; + } + + crc = 0xffffffff; + buf = calloc(2048, sizeof(char)); + marea = NULL; + + /* + * First read the message for kludges we need. + */ + rewind(fp); + + FirstLine = TRUE; + while ((fgets(buf, 2048, fp)) != NULL) { + + Striplf(buf); + + /* + * Check all sort of relevant kludges. + */ + if (FirstLine && (!strncmp(buf, "AREA:", 5))) { + + echo_in++; + marea = xstrcpy(tu(buf + 5)); + + if (orig == NULL) { + Syslog('!', "Echomail without Origin line"); + echo_bad++; + bad = TRUE; + free(buf); + free(marea); + return 3; + } + + if (!SearchMsgs(marea)) { + WriteError("Unknown echo area %s", marea); + if (autocrea) { + autocreate(marea, p_from); + if (!SearchMsgs(marea)) { + WriteError("Autocreate of area %s failed.", area); + echo_bad++; + bad = TRUE; + free(marea); + free(buf); + return 4; + } + } else { + echo_bad++; + bad = TRUE; + free(buf); + free(marea); + return 4; + } + } + crc = upd_crc32(buf, crc, strlen(buf)); + echomail = TRUE; + free(marea); + + /* + * Check if node is allowed to enter echomail in this area. + */ + if (!bad) { + bad = TRUE; + First = TRUE; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((p_from->zone == Link.aka.zone) && + (p_from->net == Link.aka.net) && + (p_from->node == Link.aka.node)) { + bad = FALSE; + break; + } + } + if (bad && (msgs.UnSecure || do_unsec)) { + bad = FALSE; + memset(&Link, 0, sizeof(Link)); + } + if (bad) { + Syslog('+', "Node %s not connected to area %s", ascfnode(p_from, 0x1f), msgs.Tag); + free(buf); + echo_bad++; + return 4; + } + + if (Link.cutoff && !bad) { + Syslog('+', "Echomail from %s in %s refused, cutoff", ascfnode(p_from, 0x1f), msgs.Tag); + free(buf); + bad = TRUE; + echo_bad++; + return 4; + } + if (!Link.receivefrom && !bad) { + Syslog('+', "Echomail from %s in %s refused, read only", ascfnode(p_from, 0x1f), msgs.Tag); + bad = TRUE; + free(buf); + echo_bad++; + return 4; + } + + if (CFG.toss_old) { + if (((t_start - mdate) / 86400) > CFG.toss_old) { + Syslog('+', "Rejecting msg: too old, %s", rfcdate(mdate)); + bad = TRUE; + free(buf); + echo_bad++; + return 4; + } + } + } + + StatAdd(&msgs.Received, 1); + time(&msgs.LastRcvd); + StatAdd(&mgroup.MsgsRcvd, 1); + time(&mgroup.LastDate); + UpdateMsgs(); + } + + if (*buf != '\001') + FirstLine = FALSE; + + if (!echomail) { + + /* + * Check for X-FTN- kludges, this could be gated email. + * This should be impossible. + */ + if (!strncmp(buf, "\001X-FTN-", 7)) { + email = TRUE; + Syslog('?', "Warning: detected ^aX-FTN- kludge in netmail"); + } + + /* + * Check DOMAIN and INTL kludges + */ + if (!strncmp(buf, "\001DOMAIN", 7)) { + l = strtok(buf," \n"); + l = strtok(NULL," \n"); + p = strtok(NULL," \n"); + r = strtok(NULL," \n"); + q = strtok(NULL," \n"); + if ((ta = parsefnode(p))) { + t->point = ta->point; + t->node = ta->node; + t->net = ta->net; + t->zone = ta->zone; + tidy_faddr(ta); + } + t->domain = xstrcpy(l); + if ((ta = parsefnode(q))) { + f->point = ta->point; + f->node = ta->node; + f->net = ta->net; + f->zone = ta->zone; + tidy_faddr(ta); + } + f->domain = xstrcpy(r); + } else { + if (!strncmp(buf, "\001INTL", 5)) { + l = strtok(buf," \n"); + l = strtok(NULL," \n"); + r = strtok(NULL," \n"); + if ((ta = parsefnode(l))) { + t->point = ta->point; + t->node = ta->node; + t->net = ta->net; + t->zone = ta->zone; + if (ta->domain) { + if (t->domain) + free(t->domain); + t->domain = ta->domain; + ta->domain = NULL; + } + tidy_faddr(ta); + } + if ((ta = parsefnode(r))) { + f->point = ta->point; + f->node = ta->node; + f->net = ta->net; + f->zone = ta->zone; + if (ta->domain) { + if (f->domain) + free(f->domain); + f->domain = ta->domain; + ta->domain = NULL; + } + tidy_faddr(ta); + } + } + } + /* + * Now check FMPT and TOPT kludges + */ + if (!strncmp(buf, "\001FMPT", 5)) { + p = strtok(buf, " \n"); + p = strtok(NULL, " \n"); + fmpt = atoi(p); + } + if (!strncmp(buf, "\001TOPT", 5)) { + p = strtok(buf, " \n"); + p = strtok(NULL, " \n"); + topt = atoi(p); + } + + if (!strncmp(buf, "\001MSGID: ", 8)) { + msgid = xstrcpy(buf + 8); + /* + * Extra test to see if the mail comes from a pointaddress. + */ + l = strtok(buf," \n"); + l = strtok(NULL," \n"); + if ((ta = parsefnode(l))) { + if (ta->zone == f->zone && ta->net == f->net && ta->node == f->node && !fmpt && ta->point) { + Syslog('m', "Setting pointinfo (%d) from MSGID", ta->point); + fmpt = f->point = ta->point; + } + tidy_faddr(ta); + } + } + } /* if netmail */ + + if (!strncmp(buf, "\001REPLYTO: ", 10)) + reply = xstrcpy(buf + 10); + if (!strncmp(buf, "SEEN-BY:", 8)) { + if (Link.aka.zone == msgs.Aka.zone) { + p = xstrcpy(buf + 9); + fill_list(&sbl, p, NULL, FALSE); + free(p); + } else + Syslog('m', "Strip zone SB lines"); + } + if (!strncmp(buf, "\001PATH:", 6)) { + p = xstrcpy(buf + 7); + fill_path(&ptl, p); + free(p); + } + + } /* end of checking kludges */ + + /* + * Handle netmail + */ + if (!echomail) { + /* + * Only set point info if there was any info. + * GoldED doesn't set FMPT and TOPT kludges. + */ + if (fmpt) + f->point = fmpt; + if (topt) + t->point = topt; + rc = postnetmail(fp, f, t, orig, subj, mdate, flags, TRUE); + free(buf); + return rc; + } /* if !echomail */ + + /* + * Handle echomail + */ + if (echomail && (!bad)) { + /* + * First, further dupe checking. + */ + crc = upd_crc32(subj, crc, strlen(subj)); + + if (orig == NULL) + Syslog('!', "No origin line found"); + else + crc = upd_crc32(orig, crc, strlen(orig)); + + crc = upd_crc32((char *)&mdate, crc, sizeof(mdate)); + + if (msgid != NULL) { + crc = upd_crc32(msgid, crc, strlen(msgid)); + } else { + if (check_dupe) { + /* + * If a MSGID is missing it is possible that dupes from some offline + * readers slip through because these readers use the same date for + * each message. In this case the message text is included in the + * dupecheck. Redy Rodriguez. + */ + rewind(fp); + while ((fgets(buf, 2048, fp)) != NULL) { + Striplf(buf); + if (strncmp(buf, "---", 3) == 0) + break; + if ((strncmp(buf, "\001", 1) != 0 ) && (strncmp(buf,"AREA:",5) != 0 )) + crc = upd_crc32(buf, crc , strlen(buf)); + } + } + } + + if (check_dupe) + dupe = CheckDupe(crc, D_ECHOMAIL, CFG.toss_dupes); + else + dupe = FALSE; + if (dupe) + echo_dupe++; + } + + if ((echomail) && (!bad) && (!dupe) && (!msgs.UnSecure) && (!do_unsec)) { + + /* + * Check if the message is for us. Don't check point address, + * echomail messages don't have point destination set. + */ + if ((msgs.Aka.zone != t->zone) || (msgs.Aka.net != t->net) || (msgs.Aka.node != t->node)) { + bad = TRUE; + /* + * If we are a hub or host and have all our echomail + * connected to the hub/host aka, echomail from points + * under a nodenumber aka isn't accepted. The match + * must be further tested. + */ + if ((msgs.Aka.zone == t->zone) && (msgs.Aka.net == t->net)) { + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && + (CFG.aka[i].zone == t->zone) && + (CFG.aka[i].net == t->net) && + (CFG.aka[i].node == t->node)) + bad = FALSE; /* Undo the result */ + } + } + } + if (bad) { + echo_bad++; + WriteError("Msg in %s not for us (%s) but for %s", msgs.Tag, aka2str(msgs.Aka), ascfnode(t,0x1f)); + } + } + + if ((echomail) && (!bad) && (!dupe)) { + + if (msgs.Aka.zone != Link.aka.zone) { + /* + * If it is a zonegated echomailmessage the SEEN-BY lines + * are stripped off including that of the other zone's + * gate. Add the gate's aka to the SEEN-BY + */ + Syslog('m', "Gated echomail, clean SB"); + tidy_falist(&sbl); + sprintf(sbe, "%u/%u", Link.aka.net, Link.aka.node); + Syslog('m', "Add gate SB %s", sbe); + fill_list(&sbl, sbe, NULL, FALSE); + } + + /* + * Add more aka's to SEENBY if in the same zone as our system. + * When ready filter dupe's, there is at least one. + */ + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (msgs.Aka.zone == CFG.aka[i].zone) && + !((msgs.Aka.net == CFG.aka[i].net) && (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + uniq_list(&sbl); + } + + /* + * Add our system to the path for later export. + */ + sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node); + fill_path(&ptl, sbe); + + if (echomail) { + /* + * Build a list of qualified systems to receive this message. + * Complete the SEEN-BY lines. + */ + First = TRUE; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) { + Faddr = fido2faddr(Link.aka); + fill_qualify(&qal, Link.aka, ((p_from->zone == Link.aka.zone) && + (p_from->net == Link.aka.net) && (p_from->node == Link.aka.node) && + (p_from->point == Link.aka.point)), in_list(Faddr, &sbl, FALSE)); + tidy_faddr(Faddr); + } + } + + /* + * Add SEEN-BY for nodes qualified to receive this message. + * When ready, filter the dupes and sort the SEEN-BY entries. + */ + for (tmpq = qal; tmpq; tmpq = tmpq->next) { + if (tmpq->send) { + sprintf(sbe, "%u/%u", tmpq->aka.net, tmpq->aka.node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + uniq_list(&sbl); + sort_list(&sbl); + + /* + * Create a new tmpfile with a copy of the message + * without original PATH and SEENBY lines, add the + * new PATH and SEENBY lines. + */ + rewind(fp); + if ((nfp = tmpfile()) == NULL) { + WriteError("$Unable to open tmpfile"); + } + while ((fgets(buf, 2048, fp)) != NULL) { + Striplf(buf); + fprintf(nfp, "%s", buf); + /* + * Don't write SEEN-BY and PATH lines + */ + if (strncmp(buf, " * Origin:", 10) == 0) + break; + fprintf(nfp, "\n"); + } + + /* + * Now add new SEEN-BY and PATH lines + */ + seenlen = MAXSEEN + 1; + /* + * Ensure that it will not match for + * the first entry. + */ + oldnet = sbl->addr->net - 1; + for (tmpl = sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(nfp, "\nSEEN-BY:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(nfp, "%s", sbe); + } + + seenlen = MAXPATH + 1; + /* + * Ensure it will not match for the first entry + */ + oldnet = ptl->addr->net - 1; + for (tmpl = ptl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXPATH) { + seenlen = 0; + fprintf(nfp, "\n\001PATH:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(nfp, "%s", sbe); + } + fprintf(nfp, "\n"); + fflush(nfp); + rewind(nfp); + + /* + * Import this message. + */ + if (bad) { + if (strlen(CFG.badboard) == 0) { + Syslog('+', "Killing bad message"); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + free(buf); + return 0; + } else { + if ((result = Msg_Open(CFG.badboard))) + Syslog('+', "Tossing in bad board"); + } + } else if (dupe) { + if (strlen(CFG.dupboard) == 0) { + Syslog('+', "Killing dupe message"); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + free(buf); + return 0; + } else { + if ((result = Msg_Open(CFG.dupboard))) + Syslog('+', "Tossing in dupe board"); + } + } else { + result = Msg_Open(msgs.Base); + } + if (!result) { + WriteError("Can't open JAMmb %s", msgs.Base); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + free(buf); + return 1; + } + + if (Msg_Lock(30L)) { + if ((!dupe) && (!bad)) + echo_imp++; + + if (!do_quiet) { + colour(3, 0); + printf("\r%6u => %-40s\r", echo_in, msgs.Name); + fflush(stdout); + } + + Msg_New(); + + /* + * Fill subfields + */ + strcpy(Msg.From, f->name); + strcpy(Msg.To, t->name); + strcpy(Msg.FromAddress, ascfnode(f,0x1f)); + strcpy(Msg.Subject, subj); + Msg.Written = mdate; + Msg.Arrived = time(NULL); + Msg.Echomail = TRUE; + + /* + * These are the only usefull flags in echomail + */ + if ((flags & M_PVT) && ((msgs.MsgKinds == BOTH) || (msgs.MsgKinds == PRIVATE))) + Msg.Private = TRUE; + if (flags & M_FILE) + Msg.FileAttach = TRUE; + + /* + * Set MSGID and REPLYID crc. + */ + if (msgid != NULL) { + crc2 = -1; + Msg.MsgIdCRC = upd_crc32(msgid, crc2, strlen(msgid)); + } + if (reply != NULL) { + crc2 = -1; + Msg.ReplyCRC = upd_crc32(reply, crc2, strlen(reply)); + } + + /* + * Start write the message + * If not a bad or dupe message, eat the first + * line (AREA:tag). + */ + rewind(nfp); + if (!dupe && !bad) + fgets(buf , 256, nfp); + Msg_Write(nfp); + Msg_AddMsg(); + Msg_UnLock(); + Msg_Close(); + } else { + Syslog('+', "Can't lock msgbase %s", msgs.Base); + Msg_UnLock(); + Msg_Close(); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + free(buf); + return 5; + } + + /* + * Forward to other links + */ + if ((!dupe) && (!bad)) { + /* + * Now start exporting this echomail. + */ + for (tmpq = qal; tmpq; tmpq = tmpq->next) { + if (tmpq->send) { + if (SearchNode(tmpq->aka)) { + StatAdd(&nodes.MailSent, 1L); + UpdateNode(); + SearchNode(tmpq->aka); + } + echo_out++; + EchoOut(p_from, tmpq->aka, nfp, flags, cost, mdate); + } + } + + /* + * Gate to newsserver + */ + if (strlen(msgs.Newsgroup)) { + rewind(nfp); + qp = tmpfile(); + while ((fgets(buf, 2048, nfp)) != NULL) { + Striplf(buf); + if (kludges && (buf[0] != '\001') && strncmp(buf, "AREA:", 5)) { + kludges = FALSE; + q = xstrcpy(Msg.From); + for (i = 0; i < strlen(q); i++) + if (q[i] == ' ') + q[i] = '_'; + fprintf(qp, "From: %s@%s\n", q, ascinode(f, 0x1f)); + fprintf(qp, "Subject: %s\n", Msg.Subject); + fprintf(qp, "To: %s\n", Msg.To); + fprintf(qp, "\n"); + } + fprintf(qp, "%s\n", buf); + } + rewind(qp); + most_debug = TRUE; + mkrfcmsg(f, t, subj, orig, mdate, flags, qp, orig_off, FALSE); + most_debug = FALSE; + fclose(qp); + } + } + fclose(nfp); + } + + /* + * Free memory used by SEEN-BY, ^APATH and Qualified lines. + */ + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + + if (rc < 0) + rc =-rc; + free(buf); + if (reply) + free(reply); + return rc; +} + + + +void autocreate(char *marea, faddr *p_from) +{ + FILE *pMsgs; + char temp[250]; + int i; + struct _sysconnect syscon; + + if (!SearchMsgs((char *)"DEFAULT")){ + WriteError("Can't find DEFAULT area, can't autocreate:"); + autocrea = FALSE; + return; + } + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((pMsgs = fopen(temp, "r+")) == NULL) { + WriteError("$Database error: Can't create %s", temp); + return; + } + strncat(msgs.Name,marea,40-strlen(msgs.Name)); + strncpy(msgs.Tag,marea,50); + strncpy(msgs.QWKname,marea,20); + strncat(msgs.Base,marea,64-strlen(msgs.Base)); + fseek(pMsgs, 0, SEEK_END); + Syslog('+', "Autocreate area %s", marea); + + memset(&syscon, 0, sizeof(syscon)); + syscon.aka.zone = p_from->zone; + syscon.aka.node = p_from->node; + syscon.aka.net = p_from->net; + if (SearchFidonet(p_from->zone)) + strcpy(syscon.aka.domain,fidonet.domain); + else { + WriteError("New area %s from node of unknown zone %d not created.", marea,p_from->zone); + fclose(pMsgs); + return; + } + syscon.sendto = TRUE; + syscon.receivefrom = TRUE; + if (msgs.Aka.zone == 0) { + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i]) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (strcmp(CFG.aka[i].domain,msgs.Aka.domain)==0)) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && (CFG.aka[i].zone == p_from->zone)) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && (CFG.aka[i].zone == p_from->zone) && (CFG.aka[i].net == p_from->net)) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && (CFG.aka[i].zone == p_from->zone) && + (CFG.aka[i].net == p_from->net) && (CFG.aka[i].node == p_from->node)) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + } + fwrite(&msgs, msgshdr.recsize, 1, pMsgs); + fwrite(&syscon, sizeof(syscon), 1, pMsgs); + memset(&syscon, 0, sizeof(syscon)); + for (i = 1 ; i < CFG.toss_systems; i++ ) + fwrite(&syscon, sizeof(syscon), 1, pMsgs); + fclose(pMsgs); + return; +} + + diff --git a/mbfido/importmsg.h b/mbfido/importmsg.h new file mode 100644 index 00000000..71fb6399 --- /dev/null +++ b/mbfido/importmsg.h @@ -0,0 +1,22 @@ +#ifndef _IMPORTMSG_H +#define _IMPORTMSG_H + + +/* + * Structure for qualified systems to receive a echomail message + */ +typedef struct _qualify { + struct _qualify *next; /* Linked list */ + fidoaddr aka; /* AKA of the linked system */ + unsigned inseenby : 1; /* System is in SEEN-BY */ + unsigned send : 1; /* Send message to link */ + unsigned orig : 1; /* Is originator of message */ +} qualify; + + +int importmsg(faddr *, faddr *, faddr *, char *, time_t, int, int, FILE *, off_t); +void autocreate(char *, faddr *); + + +#endif + diff --git a/mbfido/importnet.c b/mbfido/importnet.c new file mode 100644 index 00000000..21bf780e --- /dev/null +++ b/mbfido/importnet.c @@ -0,0 +1,173 @@ +/***************************************************************************** + * + * File ..................: tosser/importnet.c + * Purpose ...............: Import a netmail message + * Last modification date : 20-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbuser.h" +#include "rollover.h" +#include "importnet.h" + + + +/* + * Global variables + */ +extern int net_imp; /* Netmails imported */ +extern int net_bad; /* Bad netmails (tracking errors */ +extern char *subj; /* Message subject */ + + + +/* + * Import netmail into the BBS. + * + * 0 - All seems well. + * 1 - Something went wrong. + * + */ +int importnet(faddr *f, faddr *t, time_t mdate, int flags, FILE *fp) +{ + char *msgid = NULL, *reply = NULL; + int result, i, empty = TRUE; + unsigned long crc2; + char *Buf; + + if (SearchNetBoard(t->zone, t->net)) { + StatAdd(&msgs.Received, 1L); + time(&msgs.LastRcvd); + UpdateMsgs(); + + result = Msg_Open(msgs.Base); + if (!result) { + WriteError("Can't open msgbase %s", msgs.Base); + net_bad++; + return 1; + } + + if (Msg_Lock(30L)) { + Msg_New(); + + Syslog('m', "Flagfield 0x%04x", flags); + strcpy(Msg.From, f->name); + strcpy(Msg.To, usr.sUserName); + strcpy(Msg.FromAddress, ascfnode(f,0x1f)); + strcpy(Msg.ToAddress, ascfnode(t,0x1f)); + strcpy(Msg.Subject, subj); + Msg.Written = mdate; + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Netmail = TRUE; + + /* + * These are the only usefull flags in netmail + */ + if ((msgs.MsgKinds == BOTH) || (msgs.MsgKinds == PRIVATE)) { + if (flags & M_PVT) + Msg.Private = TRUE; + else + Msg.Private = FALSE; + } else + Msg.Private = TRUE; /* Allways */ + if (flags & M_CRASH) + Msg.Crash = TRUE; + if (flags & M_FILE) + Msg.FileAttach = TRUE; + if (flags & M_REQ) + Msg.FileRequest = TRUE; + if (flags & M_RRQ) + Msg.ReceiptRequest = TRUE; + + /* + * Set MSGID and REPLYID crc. + */ + if (msgid != NULL) { + crc2 = -1; + Msg.MsgIdCRC = upd_crc32(msgid, crc2, strlen(msgid)); + } + if (reply != NULL) { + crc2 = -1; + Msg.ReplyCRC = upd_crc32(reply, crc2, strlen(reply)); + } + + /* + * Check if this is an empty netmail + */ + rewind(fp); + Buf = calloc(2049, sizeof(char)); + while ((fgets(Buf, 2048, fp)) != NULL) { + + for (i = 0; i < strlen(Buf); i++) { + if (*(Buf + i) == '\0') + break; + if (*(Buf + i) == '\n') + *(Buf + i) = '\0'; + if (*(Buf + i) == '\r') + *(Buf + i) = '\0'; + } + if (*(Buf) != '\0') { + if ((*(Buf) != '\001') && + (strcmp(Buf, (char *)"--- "))) + empty = FALSE; + } + } + free(Buf); + + if (!empty) { + Syslog('+', "Import netmail to %s", usr.sUserName); + rewind(fp); + Msg_Write(fp); + Msg_AddMsg(); + net_imp++; + } else { + Syslog('+', "Empty netmail for %s dropped", usr.sUserName); + } + Msg_UnLock(); + Msg_Close(); + + return 0; + } else { + WriteError("Can't lock msgbase %s", msgs.Base); + Msg_Close(); + return 1; + } + } else { + WriteError("Can't find a netmail board"); + net_bad++; + return 1; + } /* if SearchNetBoard() */ +} + + diff --git a/mbfido/importnet.h b/mbfido/importnet.h new file mode 100644 index 00000000..a01f9d66 --- /dev/null +++ b/mbfido/importnet.h @@ -0,0 +1,8 @@ +#ifndef _IMPORTNET_H +#define _IMPORTNET_H + + +int importnet(faddr *, faddr *, time_t, int, FILE *); + +#endif + diff --git a/mbfido/lhash.c b/mbfido/lhash.c new file mode 100644 index 00000000..0b020f9a --- /dev/null +++ b/mbfido/lhash.c @@ -0,0 +1,515 @@ +/***************************************************************************** + * + * File ..................: mbmail/lhash.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 28-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "lhash.h" + +/* crypto/lhash/lhash.c */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +char *lh_version=(char *)"lhash part of SSLeay 0.6.4 30-Aug-1996"; + +/* Code for dynamic hash table routines + * Author - Eric Young v 2.0 + * + * 2.0 eay - Fixed a bug that occured when using lh_delete + * from inside lh_doall(). As entries were deleted, + * the 'table' was 'contract()ed', making some entries + * jump from the end of the table to the start, there by + * skiping the lh_doall() processing. eay - 4/12/95 + * + * 1.9 eay - Fixed a memory leak in lh_free, the LHASH_NODEs + * were not being free()ed. 21/11/95 + * + * 1.8 eay - Put the stats routines into a seperate file, lh_stats.c + * 19/09/95 + * + * 1.7 eay - Removed the fputs() for realloc failures - the code + * should silently tolerate them. I have also fixed things + * lint complained about 04/05/95 + * + * 1.6 eay - Fixed an invalid pointers in contract/expand 27/07/92 + * + * 1.5 eay - Fixed a misuse of realloc in expand 02/03/1992 + * + * 1.4 eay - Fixed lh_doall so the function can call lh_delete 28/05/91 + * + * 1.3 eay - Fixed a few lint problems 19/3/1991 + * + * 1.2 eay - Fixed lh_doall problem 13/3/1991 + * + * 1.1 eay - Added lh_doall + * + * 1.0 eay - First version + */ + + +#undef MIN_NODES +#define MIN_NODES 16 +#define UP_LOAD (2*LH_LOAD_MULT) /* load times 256 (default 2) */ +#define DOWN_LOAD (LH_LOAD_MULT) /* load times 256 (default 1) */ + +#ifndef NOPROTO + +#define P_CP char * +#define P_CPP char *,char * +static void expand(LHASH *lh); +static void contract(LHASH *lh); +static LHASH_NODE **getrn(LHASH *lh, char *data, unsigned long *rhash); + +#else + +#define P_CP +#define P_CPP +static void expand(); +static void contract(); +static LHASH_NODE **getrn(); + +#endif + +LHASH *lh_new(unsigned long (*h)(char *), int (*c)(char *, char *)) +{ + LHASH *ret; + int i; + + if ((ret=(LHASH *)malloc(sizeof(LHASH))) == NULL) + goto err0; + if ((ret->b=(LHASH_NODE **)malloc(sizeof(LHASH_NODE *)*MIN_NODES)) == NULL) + goto err1; + for (i=0; ib[i]=NULL; + ret->comp=((c == NULL)?(int (*)(char *, char *))strcmp:c); + ret->hash=((h == NULL)?(unsigned long (*)(char *))lh_strhash:h); + ret->num_nodes=MIN_NODES/2; + ret->num_alloc_nodes=MIN_NODES; + ret->p=0; + ret->pmax=MIN_NODES/2; + ret->up_load=UP_LOAD; + ret->down_load=DOWN_LOAD; + ret->num_items=0; + + ret->num_expands=0; + ret->num_expand_reallocs=0; + ret->num_contracts=0; + ret->num_contract_reallocs=0; + ret->num_hash_calls=0; + ret->num_comp_calls=0; + ret->num_insert=0; + ret->num_replace=0; + ret->num_delete=0; + ret->num_no_delete=0; + ret->num_retreve=0; + ret->num_retreve_miss=0; + ret->num_hash_comps=0; + + return(ret); +err1: + free((char *)ret); +err0: + return(NULL); +} + + + +void lh_free(LHASH *lh) +{ + unsigned int i; + LHASH_NODE *n,*nn; + + for (i=0; inum_nodes; i++) + { + n=lh->b[i]; + while (n != NULL) + { + nn=n->next; + free(n); + n=nn; + } + } + free((char *)lh->b); + free((char *)lh); +} + + + +char *lh_insert(LHASH *lh, char *data) +{ + unsigned long hash; + LHASH_NODE *nn,**rn; + char *ret; + + if (lh->up_load <= (lh->num_items*LH_LOAD_MULT/lh->num_nodes)) + expand(lh); + + rn=getrn(lh,data,&hash); + + if (*rn == NULL) + { + if ((nn=(LHASH_NODE *)malloc(sizeof(LHASH_NODE))) == NULL) + return(NULL); + nn->data=data; + nn->next=NULL; +#ifndef NO_HASH_COMP + nn->hash=hash; +#endif + *rn=nn; + ret=NULL; + lh->num_insert++; + lh->num_items++; + } + else /* replace same key */ + { + ret= (*rn)->data; + (*rn)->data=data; + lh->num_replace++; + } + return(ret); +} + + + +char *lh_delete(LHASH *lh, char *data) +{ + unsigned long hash; + LHASH_NODE *nn,**rn; + char *ret; + + rn=getrn(lh,data,&hash); + + if (*rn == NULL) + { + lh->num_no_delete++; + return(NULL); + } + else + { + nn= *rn; + *rn=nn->next; + ret=nn->data; + free((char *)nn); + lh->num_delete++; + } + + lh->num_items--; + if ((lh->num_nodes > MIN_NODES) && + (lh->down_load >= (lh->num_items*LH_LOAD_MULT/lh->num_nodes))) + contract(lh); + + return(ret); +} + + + +char *lh_retrieve(LHASH *lh, char *data) +{ + unsigned long hash; + LHASH_NODE **rn; + char *ret; + + rn=getrn(lh,data,&hash); + + if (*rn == NULL) + { + lh->num_retreve_miss++; + return(NULL); + } + else + { + ret= (*rn)->data; + lh->num_retreve++; + } + return(ret); +} + + + +void lh_doall(LHASH *lh, void (*func)(char *, char *)) +//LHASH *lh; +//void (*func)(); +{ + lh_doall_arg(lh,func,NULL); +} + + + +void lh_doall_arg(LHASH *lh, void(*func)(char *, char *), char *arg) +// LHASH *lh; +//void (*func)(); +//char *arg; +{ + int i; + LHASH_NODE *a,*n; + + /* reverse the order so we search from 'top to bottom' + * We were having memory leaks otherwise */ + for (i=lh->num_nodes-1; i>=0; i--) + { + a=lh->b[i]; + while (a != NULL) + { + /* 28/05/91 - eay - n added so items can be deleted + * via lh_doall */ + n=a->next; + func(a->data,arg); + a=n; + } + } +} + + + +static void expand(LHASH *lh) +{ + LHASH_NODE **n,**n1,**n2,*np; + unsigned int p,i,j; + unsigned long hash,nni; + + lh->num_nodes++; + lh->num_expands++; + p=(int)lh->p++; + n1= &(lh->b[p]); + n2= &(lh->b[p+(int)lh->pmax]); + *n2=NULL; /* 27/07/92 - eay - undefined pointer bug */ + nni=lh->num_alloc_nodes; + + for (np= *n1; np != NULL; ) + { +#ifndef NO_HASH_COMP + hash=np->hash; +#else + hash=(*(lh->hash))(np->data); + lh->num_hash_calls++; +#endif + if ((hash%nni) != p) + { /* move it */ + *n1= (*n1)->next; + np->next= *n2; + *n2=np; + } + else + n1= &((*n1)->next); + np= *n1; + } + + if ((lh->p) >= lh->pmax) + { + j=(int)lh->num_alloc_nodes*2; + n=(LHASH_NODE **)realloc((char *)lh->b, + (unsigned int)sizeof(LHASH_NODE *)*j); + if (n == NULL) + { + WriteError("lhash: realloc error in expand()"); + lh->p=0; + return; + } + /* else */ + for (i=(int)lh->num_alloc_nodes; ipmax=lh->num_alloc_nodes; + lh->num_alloc_nodes=j; + lh->num_expand_reallocs++; + lh->p=0; + lh->b=n; + } +} + + + +static void contract(LHASH *lh) +{ + LHASH_NODE **n,*n1,*np; + + np=lh->b[lh->p+lh->pmax-1]; + lh->b[lh->p+lh->pmax-1]=NULL; /* 24/07-92 - eay - weird but :-( */ + if (lh->p == 0) + { + n=(LHASH_NODE **)realloc((char *)lh->b, + (unsigned int)(sizeof(LHASH_NODE *)*lh->pmax)); + if (n == NULL) + { + WriteError("lhash: realloc error in contract()"); + return; + } + lh->num_contract_reallocs++; + lh->num_alloc_nodes/=2; + lh->pmax/=2; + lh->p=lh->pmax-1; + lh->b=n; + } + else + lh->p--; + + lh->num_nodes--; + lh->num_contracts++; + + n1=lh->b[(int)lh->p]; + if (n1 == NULL) + lh->b[(int)lh->p]=np; + else + { + while (n1->next != NULL) + n1=n1->next; + n1->next=np; + } +} + + + +static LHASH_NODE **getrn(LHASH *lh, char *data, unsigned long *rhash) +{ + LHASH_NODE **ret,*n1; + unsigned long hash,nn; + int (*cf)(char *, char *); + + hash=(*(lh->hash))(data); + lh->num_hash_calls++; + *rhash=hash; + + nn=hash%lh->pmax; + if (nn < lh->p) + nn=hash%lh->num_alloc_nodes; + + cf=lh->comp; + ret= &(lh->b[(int)nn]); + for (n1= *ret; n1 != NULL; n1=n1->next) + { +#ifndef NO_HASH_COMP + lh->num_hash_comps++; + if (n1->hash != hash) + { + ret= &(n1->next); + continue; + } +#endif + lh->num_comp_calls++; + if ((*cf)(n1->data,data) == 0) + break; + ret= &(n1->next); + } + return(ret); +} + +/* +static unsigned long lh_strhash(str) +char *str; + { + int i,l; + unsigned long ret=0; + unsigned short *s; + + if (str == NULL) return(0); + l=(strlen(str)+1)/2; + s=(unsigned short *)str; + for (i=0; i>2)^v)&0x0f; + ret=(ret<>(32-r)); + ret&=0xFFFFFFFFL; + ret^=v*v; + c++; + } + return((ret>>16)^ret); +} + diff --git a/mbfido/lhash.h b/mbfido/lhash.h new file mode 100644 index 00000000..d7071c47 --- /dev/null +++ b/mbfido/lhash.h @@ -0,0 +1,147 @@ +/* crypto/lhash/lhash.h */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* Header for dynamic hash table routines + * Author - Eric Young + */ + +#ifndef HEADER_LHASH_H +#define HEADER_LHASH_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct lhash_node_st + { + char *data; + struct lhash_node_st *next; +#ifndef NO_HASH_COMP + unsigned long hash; +#endif + } LHASH_NODE; + +typedef struct lhash_st + { + LHASH_NODE **b; + int (*comp)(char *, char *); + unsigned long (*hash)(char *); + unsigned int num_nodes; + unsigned int num_alloc_nodes; + unsigned int p; + unsigned int pmax; + unsigned long up_load; /* load times 256 */ + unsigned long down_load; /* load times 256 */ + unsigned long num_items; + + unsigned long num_expands; + unsigned long num_expand_reallocs; + unsigned long num_contracts; + unsigned long num_contract_reallocs; + unsigned long num_hash_calls; + unsigned long num_comp_calls; + unsigned long num_insert; + unsigned long num_replace; + unsigned long num_delete; + unsigned long num_no_delete; + unsigned long num_retreve; + unsigned long num_retreve_miss; + unsigned long num_hash_comps; + } LHASH; + +#define LH_LOAD_MULT 256 + +#ifndef NOPROTO +LHASH *lh_new(unsigned long (*h)(char *), int (*c)(char *, char *)); +void lh_free(LHASH *lh); +char *lh_insert(LHASH *lh, char *data); +char *lh_delete(LHASH *lh, char *data); +char *lh_retrieve(LHASH *lh, char *data); +void lh_doall(LHASH *lh, void (*func)(char *, char *)); +void lh_doall_arg(LHASH *lh, void (*func)(char *, char *),char *arg); +unsigned long lh_strhash(char *c); + +#ifndef WIN16 +void lh_stats(LHASH *lh, FILE *out); +void lh_node_stats(LHASH *lh, FILE *out); +void lh_node_usage_stats(LHASH *lh, FILE *out); +#endif + +#ifdef HEADER_BUFFER_H +void lh_stats_bio(LHASH *lh, BIO *out); +void lh_node_stats_bio(LHASH *lh, BIO *out); +void lh_node_usage_stats_bio(LHASH *lh, BIO *out); +#else +void lh_stats_bio(LHASH *lh, char *out); +void lh_node_stats_bio(LHASH *lh, char *out); +void lh_node_usage_stats_bio(LHASH *lh, char *out); +#endif +#else +LHASH *lh_new(); +void lh_free(); +char *lh_insert(); +char *lh_delete(); +char *lh_retrieve(); +void lh_doall(); +void lh_doall_arg(); +unsigned long lh_strhash(); + +#ifndef WIN16 +void lh_stats(); +void lh_node_stats(); +void lh_node_usage_stats(); +#endif +void lh_stats_bio(); +void lh_node_stats_bio(); +void lh_node_usage_stats_bio(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mbfido/magic.c b/mbfido/magic.c new file mode 100644 index 00000000..2bbe0519 --- /dev/null +++ b/mbfido/magic.c @@ -0,0 +1,427 @@ +/***************************************************************************** + * + * File ..................: mbfido/magic.c + * Purpose ...............: .TIC files magic processing. + * Last modification date : 16-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbtic.h" +#include "tic.h" +#include "utic.h" +#include "magic.h" + + +long MagicNr; /* Current magic record number */ +int Magics = 0; /* Processed magics */ + + + +char *Magic_Macro(int); +char *Magic_Macro(int C) +{ + static char buf[81]; + + buf[0] = '\0'; + switch(toupper(C)) { + case 'F': + sprintf(buf, "%s/%s", TIC.BBSpath, TIC.NewName); + break; + + case 'P': + sprintf(buf, "%s", TIC.BBSpath); + break; + + case 'N': + sprintf(buf, "%s", strtok(strdup(TIC.NewName), ".")); + break; + + case 'E': + sprintf(buf, "%s", strrchr(TIC.NewName, '.')); + break; + + case 'L': + sprintf(buf, "%s", strrchr(TIC.NewName, '.')); + buf[0] = buf[1]; + buf[1] = buf[2]; + buf[2] = '\0'; + break; + + case 'D': + sprintf(buf, "%03d", Day_Of_Year()); + break; + + case 'C': + sprintf(buf, "%03d", Day_Of_Year()); + buf[0] = buf[1]; + buf[1] = buf[2]; + buf[2] = '\0'; + break; + + case 'A': + sprintf(buf, "%s", TIC.TicIn.Area); + break; + } + + Syslog('f', "Mgc Macro(%c): \"%s\"", C, buf); + return buf; +} + + + + +int GetMagicRec(int Typ, int First) +{ + int Eof = FALSE, DoMagic = TRUE; + int i; + char *temp; + FILE *FeM; + + if (First) + MagicNr = 0; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/magic.data", getenv("MBSE_ROOT")); + if ((FeM = fopen(temp, "r")) == NULL) { + Syslog('+', "Huh? No magic file? (%s)", temp); + free(temp); + return FALSE; + } + + fread(&magichdr, sizeof(magichdr), 1, FeM); + + do { + if (fseek(FeM, magichdr.hdrsize + (MagicNr * magichdr.recsize), SEEK_SET) != 0) { + WriteError("$Can't seek record %ld in %s", MagicNr, temp); + free(temp); + fclose(FeM); + return FALSE; + } + + MagicNr++; + + if (fread(&magic, magichdr.recsize, 1, FeM) == 1) { + + if ((magic.Active) && (magic.Attrib == Typ) && + (strcmp(magic.From, TIC.TicIn.Area) == 0)) { + + /* + * Comparing of the filename must be done in + * two parts, before and after the dot. + */ + if (strlen(magic.Mask) == strlen(TIC.NewName)) { + for (i = 0; i < strlen(magic.Mask); i++) { + switch (magic.Mask[i]) { + case '?': + break; + + case '@': + if ((TIC.NewName[i] < 'a') || (TIC.NewName[i] > 'z')) + DoMagic = FALSE; + break; + + case '#': + if ((TIC.NewName[i] < '0') || (TIC.NewName[i] > '9')) + DoMagic = FALSE; + break; + + default: + if (TIC.NewName[i] != magic.Mask[i]) + DoMagic = FALSE; + } + } + } + + if (DoMagic) { + fclose(FeM); + free(temp); + return TRUE; + } + } + + } else { + Eof = TRUE; + } + + } while (!Eof); + + free(temp); + fclose(FeM); + return FALSE; +} + + + +void MagicResult(char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(1024, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + Syslog('+', "Magic: %s", outputstr); + free(outputstr); + Magics++; +} + + +void Magic_CheckCompile(void); +void Magic_CheckCompile(void) +{ + if (magic.Compile) { + CompileNL = TRUE; + Syslog('+', "Magic: Trigger Compile Nodelists"); + } +} + + + +int Magic_MoveFile(void) +{ + if (GetMagicRec(MG_MOVE, TRUE)) { + strcpy(TIC.TicIn.Area, magic.ToArea); + MagicResult((char *)"Move %s to Area %s", TIC.TicIn.OrgName, TIC.TicIn.Area); + return TRUE; + } else + return FALSE; +} + + + +void Magic_ExecCommand(void) +{ + int i, j, k, Err, First = TRUE; + char Line[256]; + char Temp[81]; + char *cmd, *opts; + + while (GetMagicRec(MG_EXEC, First)) { + First = FALSE; + j = 0; + memset(&Line, 0, sizeof(Line)); + for (i = 0; i < strlen(magic.Cmd); i++) { + if (magic.Cmd[i] != '%') { + Line[j] = magic.Cmd[i]; + j++; + } else { + i++; + if (magic.Cmd[i] == '%') { + Line[j] = '%'; + j++; + } else { + Temp[0] = '\0'; + sprintf(Temp, "%s", Magic_Macro(magic.Cmd[i])); + for (k = 0; k < strlen(Temp); k++) { + Line[j] = Temp[k]; + j++; + } + } + } + } + + cmd = xstrcpy(getenv("MBSE_ROOT")); + cmd = xstrcat(cmd, (char *)"/bin/"); + cmd = xstrcat(cmd, strtok(Line, " ")); + opts = strtok(NULL, "\0"); + MagicResult((char *)"Exec: \"%s %s\"", cmd, opts); + + if ((Err = execute(cmd, opts, NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")) == 0) { + Magics++; + } else + Syslog('!', "Mgc Exec: (%s %s) returns %d", cmd, opts, Err); + + Magic_CheckCompile(); + } +} + + + +void Magic_CopyFile(void) +{ + int First = TRUE; + char *From, *To; + + From = calloc(256, sizeof(char)); + To = calloc(256, sizeof(char)); + + while (GetMagicRec(MG_COPY, First)) { + First = FALSE; + sprintf(From, "%s/%s", TIC.BBSpath, TIC.NewName); + sprintf(To, "%s/%s", magic.Path, TIC.NewName); + + if (file_cp(From, To) == 0) { + MagicResult((char *)"%s copied to %s", From, To); + Magic_CheckCompile(); + } else + WriteError("Magic: copy: %s to %s failed"); + } + + free(From); + free(To); +} + + + +void Magic_OtherPath(void) +{ + if (GetMagicRec(MG_OTHER, TRUE)) { + if (access(magic.Path, W_OK) == 0) { + strcpy(TIC.BBSpath, magic.Path); + MagicResult((char *)"Otherpath %s", TIC.BBSpath); + TIC.OtherPath = TRUE; + } else { + WriteError("$Magic: otherpath \"%s\" no access", magic.Path); + } + } +} + + + +void Magic_UnpackFile(void) +{ + int rc, First = TRUE; + char *buf = NULL, *unarc = NULL, *cmd = NULL; + char Fn[128]; + + while (GetMagicRec(MG_UNPACK, First)) { + First = FALSE; + buf = calloc(PATH_MAX, sizeof(char)); /* 06-01-2001 MB. Test if NULL pointer free'd message goes away */ + getcwd(buf, 128); + + if (chdir(magic.Path) == 0) { + sprintf(Fn, "%s/%s", TIC.BBSpath, TIC.NewName); + if ((unarc = unpacker(Fn)) != NULL) { + if (getarchiver(unarc)) { + cmd = xstrcpy(archiver.funarc); + if (strlen(cmd)) { + rc = execute(cmd, Fn, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); + if (rc) + WriteError("$Magic: unpack in %s, error %d", magic.Path, rc); + else + MagicResult((char *)"unpacked in %s", magic.Path); + } + free(cmd); + } + } + + chdir(buf); + Magic_CheckCompile(); + } else + WriteError("$Magic: unpack: can't chdir \"%s\"", magic.Path); + + free(buf); + } +} + + + +void Magic_Keepnum(void) +{ + if (GetMagicRec(MG_KEEPNUM, TRUE)) { + TIC.KeepNum = magic.KeepNum; + MagicResult((char *)"Keep %d files", TIC.KeepNum); + } +} + + + +void Magic_UpDateAlias(void) +{ + if (GetMagicRec(MG_UPDALIAS, TRUE)) { + UpDateAlias(TIC.TicIn.Area); + MagicResult((char *)"Update Alias"); + } +} + + + +void Magic_AdoptFile(void) +{ + int First = TRUE; + char *temp; + FILE *Tf; + + temp = calloc(256, sizeof(char)); + + while (GetMagicRec(MG_ADOPT, First)) { + First = FALSE; + + if (SearchTic(magic.ToArea)) { + MagicResult((char *)"Adoptfile in %s", magic.ToArea); + + sprintf(temp, "%s/%s", TIC.Inbound, MakeTicName()); + if ((Tf = fopen(temp, "a+")) == NULL) + WriteError("$Can't create %s", temp); + else { + fprintf(Tf, "Hatch\r\n"); + fprintf(Tf, "NoMove\r\n"); + fprintf(Tf, "Created MBSE BBS v%s, %s\r\n", VERSION, ShortRight); + fprintf(Tf, "Area %s\r\n", magic.ToArea); + fprintf(Tf, "Origin %s\r\n", aka2str(tic.Aka)); + fprintf(Tf, "From %s\r\n", aka2str(tic.Aka)); + if (strlen(TIC.TicIn.Replace)) + fprintf(Tf, "Replaces %s\r\n", TIC.TicIn.Replace); + if (strlen(TIC.TicIn.Magic)) + fprintf(Tf, "Magic %s\r\n", TIC.TicIn.Magic); + fprintf(Tf, "File %s\r\n", TIC.NewName); + fprintf(Tf, "Pth %s\r\n", TIC.BBSpath); + fprintf(Tf, "Desc %s\r\n", TIC.TicIn.Desc); + fprintf(Tf, "Crc %s\r\n", TIC.TicIn.Crc); + fprintf(Tf, "Pw %s\r\n", CFG.hatchpasswd); + fclose(Tf); + } + + SearchTic(TIC.TicIn.Area); + } else + WriteError("Mgc Adopt: Area \"%s\" not found"); + } + + free(temp); +} + + + +int Magic_DeleteFile(void) +{ + int Result; + + if ((Result = GetMagicRec(MG_DELETE, TRUE))) + MagicResult((char *)"Delete file"); + + return Result; +} + + + diff --git a/mbfido/magic.h b/mbfido/magic.h new file mode 100644 index 00000000..9ae4a4b2 --- /dev/null +++ b/mbfido/magic.h @@ -0,0 +1,19 @@ +#ifndef _MAGIC_H +#define _MAGIC_H + + +int GetMagicRec(int, int); +void MagicResult(char *, ...); +int Magic_MoveFile(void); +void Magic_ExecCommand(void); +void Magic_CopyFile(void); +void Magic_OtherPath(void); +void Magic_UnpackFile(void); +void Magic_Keepnum(void); +void Magic_UpDateAlias(void); +void Magic_AdoptFile(void); +int Magic_DeleteFile(void); + + +#endif + diff --git a/mbfido/makestat.c b/mbfido/makestat.c new file mode 100644 index 00000000..325a9d56 --- /dev/null +++ b/mbfido/makestat.c @@ -0,0 +1,434 @@ +/***************************************************************************** + * + * File ..................: mbfido/makestat.c + * Purpose ...............: Make Web statistics + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "makestat.h" + + + +/* + * Translate ISO 8859-1 characters to named character entities + */ +void html_massage(char *, char *); +void html_massage(char *inbuf, char *outbuf) +{ + char *inptr = inbuf; + char *outptr = outbuf; + + memset(outbuf, 0, sizeof(outbuf)); + + while (*inptr) { + + switch ((unsigned char)*inptr) { + case '"': sprintf(outptr, """); break; + case '&': sprintf(outptr, "&"); break; + case '<': sprintf(outptr, "<"); break; + case '>': sprintf(outptr, ">"); break; + case 160: sprintf(outptr, " "); break; + case 161: sprintf(outptr, "¡"); break; + case 162: sprintf(outptr, "¢"); break; + case 163: sprintf(outptr, "£"); break; + case 164: sprintf(outptr, "¤"); break; + case 165: sprintf(outptr, "¥"); break; + case 166: sprintf(outptr, "¦"); break; + case 167: sprintf(outptr, "§"); break; + case 168: sprintf(outptr, "¨"); break; + case 169: sprintf(outptr, "©"); break; + case 170: sprintf(outptr, "ª"); break; + case 171: sprintf(outptr, "«"); break; + case 172: sprintf(outptr, "¬"); break; + case 173: sprintf(outptr, "­"); break; + case 174: sprintf(outptr, "®"); break; + case 175: sprintf(outptr, "¯"); break; + case 176: sprintf(outptr, "°"); break; + case 177: sprintf(outptr, "&plumn;"); break; + case 178: sprintf(outptr, "²"); break; + case 179: sprintf(outptr, "³"); break; + case 180: sprintf(outptr, "´"); break; + case 181: sprintf(outptr, "µ"); break; + case 182: sprintf(outptr, "¶"); break; + case 183: sprintf(outptr, "·"); break; + case 184: sprintf(outptr, "¸"); break; + case 185: sprintf(outptr, "&supl;"); break; + case 186: sprintf(outptr, "º"); break; + case 187: sprintf(outptr, "»"); break; + case 188: sprintf(outptr, "¼"); break; + case 189: sprintf(outptr, "½"); break; + case 190: sprintf(outptr, "¾"); break; + case 191: sprintf(outptr, "¿"); break; + case 192: sprintf(outptr, "À"); break; + case 193: sprintf(outptr, "Á"); break; + case 194: sprintf(outptr, "Â"); break; + case 195: sprintf(outptr, "Ã"); break; + case 196: sprintf(outptr, "Ä"); break; + case 197: sprintf(outptr, "Å"); break; + case 198: sprintf(outptr, "Æ"); break; + case 199: sprintf(outptr, "Ç"); break; + case 200: sprintf(outptr, "È"); break; + case 201: sprintf(outptr, "É"); break; + case 202: sprintf(outptr, "Ê"); break; + case 203: sprintf(outptr, "Ë"); break; + case 204: sprintf(outptr, "Ì"); break; + case 205: sprintf(outptr, "Í"); break; + case 206: sprintf(outptr, "Î"); break; + case 207: sprintf(outptr, "Ï"); break; + case 208: sprintf(outptr, "Ð"); break; + case 209: sprintf(outptr, "Ñ"); break; + case 210: sprintf(outptr, "Ò"); break; + case 211: sprintf(outptr, "Ó"); break; + case 212: sprintf(outptr, "Ô"); break; + case 213: sprintf(outptr, "Õ"); break; + case 214: sprintf(outptr, "Ö"); break; + case 215: sprintf(outptr, "×"); break; + case 216: sprintf(outptr, "Ø"); break; + case 217: sprintf(outptr, "Ù"); break; + case 218: sprintf(outptr, "Ú"); break; + case 219: sprintf(outptr, "Û"); break; + case 220: sprintf(outptr, "Ü"); break; + case 221: sprintf(outptr, "Ý"); break; + case 222: sprintf(outptr, "Þ"); break; + case 223: sprintf(outptr, "ß"); break; + case 224: sprintf(outptr, "à"); break; + case 225: sprintf(outptr, "á"); break; + case 226: sprintf(outptr, "â"); break; + case 227: sprintf(outptr, "ã"); break; + case 228: sprintf(outptr, "ä"); break; + case 229: sprintf(outptr, "å"); break; + case 230: sprintf(outptr, "æ"); break; + case 231: sprintf(outptr, "ç"); break; + case 232: sprintf(outptr, "è"); break; + case 233: sprintf(outptr, "é"); break; + case 234: sprintf(outptr, "ê"); break; + case 235: sprintf(outptr, "ë"); break; + case 236: sprintf(outptr, "ì"); break; + case 237: sprintf(outptr, "í"); break; + case 238: sprintf(outptr, "î"); break; + case 239: sprintf(outptr, "ï"); break; + case 240: sprintf(outptr, "ð"); break; + case 241: sprintf(outptr, "ñ"); break; + case 242: sprintf(outptr, "ò"); break; + case 243: sprintf(outptr, "ó"); break; + case 244: sprintf(outptr, "ô"); break; + case 245: sprintf(outptr, "õ"); break; + case 246: sprintf(outptr, "ö"); break; + case 247: sprintf(outptr, "÷"); break; + case 248: sprintf(outptr, "ø"); break; + case 249: sprintf(outptr, "ù"); break; + case 250: sprintf(outptr, "ú"); break; + case 251: sprintf(outptr, "û"); break; + case 252: sprintf(outptr, "ü"); break; + case 253: sprintf(outptr, "ý"); break; + case 254: sprintf(outptr, "þ"); break; + case 255: sprintf(outptr, "ÿ"); break; + default: *outptr++ = *inptr; *outptr = '\0'; break; + } + while (*outptr) + outptr++; + + inptr++; + } + *outptr = '\0'; +} + + + +FILE *newpage(char *, char *); +FILE *newpage(char *Name, char *Title) +{ + char linebuf[1024], outbuf[1024]; + static FILE* fa; + time_t later; + + later = time(NULL) + 86400; + sprintf(linebuf, "%s/stat/%s.temp", CFG.www_root, Name); + mkdirs(linebuf); + + if ((fa = fopen(linebuf, "w")) == NULL) { + WriteError("$Can't create %s", linebuf); + } else { + sprintf(linebuf, "%s", Title); + html_massage(linebuf, outbuf); + fprintf(fa, "\n"); + fprintf(fa, "\n", rfcdate(later)); + fprintf(fa, "\n"); + fprintf(fa, "\n", CFG.www_charset); + fprintf(fa, "\n", CFG.www_author, outbuf); + fprintf(fa, "\n%s\n", outbuf); + fprintf(fa, "\n", CFG.www_url); + fprintf(fa, "\n\n\n\n"); + fprintf(fa, "

%s

\n", Title); + fprintf(fa, "\n"); + return fa; + } + return NULL; +} + + + +void closepage(FILE *, char *); +void closepage(FILE *fa, char *Name) +{ + char temp1[81], temp2[81]; + + if (fa == NULL) + return; + + fprintf(fa, "

\n"); + fprintf(fa, "

\n"); + fprintf(fa, "Top of page   Statistic index\n"); + fprintf(fa, "
\n\n\n"); + fclose(fa); + sprintf(temp1, "%s/stat/%s.html", CFG.www_root, Name); + sprintf(temp2, "%s/stat/%s.temp", CFG.www_root, Name); + rename(temp2, temp1); + fa = NULL; +} + + + +char *adate(time_t); +char *adate(time_t now) +{ + static char buf[40]; + struct tm ptm; + + if (now == 0L) { + sprintf(buf, "N/A"); + } else { + ptm = *localtime(&now); + sprintf(buf, "%02d-%02d-%04d %02d:%02d", ptm.tm_mday, ptm.tm_mon +1, ptm.tm_year + 1900, + ptm.tm_hour, ptm.tm_min); + } + return buf; +} + + + +void MakeStat(void) +{ + FILE *fg, *fw; + char *name, *p; + int i, Total, Lm, Area; + struct _history hist; + + if (!strlen(CFG.www_root)) + return; + + Syslog('+', "Start making statistic HTML pages"); + name = calloc(128, sizeof(char)); + if (Miy == 0) + Lm = 11; + else + Lm = Miy -1; + + sprintf(name, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("Can't open %s", name); + } else { + if ((fw = newpage((char *)"mgroups", (char *)"Message groups statistics")) != NULL) { + fprintf(fw, "Message group statisticsReceived lastSent last\n"); + fprintf(fw, "GroupCommentAkaLast dateweekmonthweekmonth\n"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fg); + while ((fread(&mgroup, mgrouphdr.recsize, 1, fg)) == 1) { + if (mgroup.Active) { + fprintf(fw, "%s%s%s%s%ld%ld%ld%ld\n", + mgroup.Name, mgroup.Comment, aka2str(mgroup.UseAka), adate(mgroup.LastDate), + mgroup.MsgsRcvd.lweek, mgroup.MsgsRcvd.month[Lm], + mgroup.MsgsSent.lweek, mgroup.MsgsSent.month[Lm]); + } + } + fprintf(fw, "\n"); + closepage(fw, (char *)"mgroups"); + } else { + WriteError("Can't create mgroups.html"); + } + fclose(fg); + } + + + sprintf(name, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"mareas", (char *)"Message areas statistics")) != NULL) { + fprintf(fw, "Message areas statisticsReceived lastPosts last\n"); + fprintf(fw, "NrAreaTagGroupLast dateweekmonthweekmonth\n"); + fread(&msgshdr, sizeof(msgshdr), 1, fg); + Area = 0; + while ((fread(&msgs, msgshdr.recsize, 1, fg)) == 1) { + Area++; + if (msgs.Active) { + fprintf(fw, "%d%s%s %s %s%ld%ld%ld%ld\n", + Area, msgs.Name, msgs.Tag, msgs.Group, adate(msgs.LastRcvd), + msgs.Received.lweek, msgs.Received.month[Lm], + msgs.Posted.lweek, msgs.Posted.month[Lm]); + } + fseek(fg, msgshdr.syssize, SEEK_CUR); + } + fprintf(fw, "\n"); + closepage(fw, (char *)"mareas"); + } else { + WriteError("Can't create mareas.html"); + } + fclose(fg); + } + + sprintf(name, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"fgroups", (char *)"TIC file groups statistics")) != NULL) { + fprintf(fw, "TIC file group statisticsLast weekLast month\n"); + fprintf(fw, "GroupCommentAkaLast datefilesKBytesfilesKBytes\n"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fg); + while ((fread(&fgroup, fgrouphdr.recsize, 1, fg)) == 1) { + if (fgroup.Active) { + fprintf(fw, "%s%s%s%s%ld%ld%ld%ld\n", + fgroup.Name, fgroup.Comment, aka2str(fgroup.UseAka), adate(fgroup.LastDate), + fgroup.Files.lweek, fgroup.KBytes.lweek, + fgroup.Files.month[Lm], fgroup.KBytes.month[Lm]); + } + } + fprintf(fw, "\n"); + closepage(fw, (char *)"fgroups"); + } else { + WriteError("Can't create fgroups.html"); + } + fclose(fg); + } + + sprintf(name, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"tic", (char *)"TIC file areas statistics")) != NULL) { + fprintf(fw, "TIC file areas statisticsLast weekLast month\n"); + fprintf(fw, "AreaTagGroupLast datefilesKBytesfilesKBytes\n"); + fread(&tichdr, sizeof(tichdr), 1, fg); + while ((fread(&tic, tichdr.recsize, 1, fg)) == 1) { + if (tic.Active) { + fprintf(fw, "%s%s %s %s%ld%ld%ld%ld\n", + tic.Comment, tic.Name, tic.Group, adate(tic.LastAction), + tic.Files.lweek, tic.KBytes.lweek, + tic.Files.month[Lm], tic.KBytes.month[Lm]); + } + fseek(fg, tichdr.syssize, SEEK_CUR); + } + fprintf(fw, "\n"); + closepage(fw, (char *)"tic"); + } else { + WriteError("Can't create tic.html"); + } + fclose(fg); + } + + sprintf(name, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"nodes", (char *)"Nodes statistics")) != NULL) { + fprintf(fw, "Nodes statistics\n"); + fprintf(fw, "NodeSysopStatusStart DateLast dateCreditDebet\n"); + fread(&nodeshdr, sizeof(nodeshdr), 1, fg); + while ((fread(&nodes, nodeshdr.recsize, 1, fg)) == 1) { + fseek(fg, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + p = xstrcpy(adate(nodes.StartDate)); + fprintf(fw, "%s%s%s %s%s%s%ld%ld\n", + aka2str(nodes.Aka[0]), nodes.Sysop, nodes.Crash?"Crash":"", nodes.Hold?"Hold":"", + p, adate(nodes.LastDate), nodes.Credit, nodes.Debet); + free(p); + } + fprintf(fw, "\n"); + closepage(fw, (char *)"nodes"); + } else { + WriteError("Can't create nodes.html"); + } + fclose(fg); + } + + sprintf(name, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"mailhistory", (char *)"Mailer history")) != NULL) { + fseek(fg, 0, SEEK_END); + Total = (ftell(fg) / sizeof(hist)) -1; + fseek(fg, 0, SEEK_SET); + fread(&hist, sizeof(hist), 1, fg); + fprintf(fw, "Mailer history since %s\n", adate(hist.online)); + fprintf(fw, "AkaSystemLocationTimeElapsedSentReceivedMode\n"); + + for (i = Total; i > 0; i--) { + fseek(fg, i * sizeof(hist), SEEK_SET); + fread(&hist, sizeof(hist), 1, fg); + fprintf(fw, "%s%s%s%s%s%lu%lu%s", + aka2str(hist.aka), hist.system_name, hist.location, + adate(hist.online), t_elapsed(hist.online, hist.offline), hist.sent_bytes, + hist.rcvd_bytes, hist.inbound ? "In":"Out"); + } + + fprintf(fw, "\n"); + closepage(fw, (char *)"mailhistory"); + } else { + WriteError("Can't create tic.html"); + } + fclose(fg); + } + + sprintf(name, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) != NULL ) { + fread(&SYSINFO, sizeof(SYSINFO), 1, fg); + if ((fw = newpage((char *)"sysinfo", (char *)"BBS system information")) != NULL) { + fprintf(fw, "BBS system info\n"); + fprintf(fw, "Total calls%lu\n", SYSINFO.SystemCalls); + fprintf(fw, "Pots calls%lu\n", SYSINFO.Pots); + fprintf(fw, "ISDN calls%lu\n", SYSINFO.ISDN); + fprintf(fw, "Network calls%lu\n", SYSINFO.Network); + fprintf(fw, "Local calls%lu\n", SYSINFO.Local); + fprintf(fw, "ADSL calls%lu\n", SYSINFO.ADSL); + fprintf(fw, "Start date%s\n", adate(SYSINFO.StartDate)); + fprintf(fw, "Last caller%s\n", SYSINFO.LastCaller); + fprintf(fw, "\n"); + closepage(fw, (char *)"sysinfo"); + } + fclose(fg); + } + + free(name); + Syslog('+', "Finished making statistic HTML pages"); +} + + diff --git a/mbfido/makestat.h b/mbfido/makestat.h new file mode 100644 index 00000000..22132b1a --- /dev/null +++ b/mbfido/makestat.h @@ -0,0 +1,9 @@ +#ifndef _MAKESTAT_H +#define _MAKESTAT_H + + +void MakeStat(void); + + +#endif + diff --git a/mbfido/maketags.c b/mbfido/maketags.c new file mode 100644 index 00000000..e8306373 --- /dev/null +++ b/mbfido/maketags.c @@ -0,0 +1,132 @@ +/***************************************************************************** + * + * File ..................: mbfido/maketags.c + * Purpose ...............: Make tag files + * Last modification date : 20-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "maketags.h" + + + +void MakeTags(void) +{ + FILE *fg, *fd, *td, *ad; + char *gname, *dname, *tname, *aname; + + Syslog('+', "Start making tagfiles"); + gname = calloc(128, sizeof(char)); + dname = calloc(128, sizeof(char)); + tname = calloc(128, sizeof(char)); + aname = calloc(128, sizeof(char)); + + sprintf(gname, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + sprintf(dname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + + if (((fg = fopen(gname, "r")) == NULL) || + ((fd = fopen(dname, "r")) == NULL)) { + WriteError("$Can't open data"); + } else { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fg); + fread(&msgshdr, sizeof(msgshdr), 1, fd); + + while ((fread(&mgroup, mgrouphdr.recsize, 1, fg)) == 1) { + if (mgroup.Active) { + sprintf(tname, "%s/doc/%s.msgs.tag", getenv("MBSE_ROOT"), mgroup.Name); + td = fopen(tname, "w"); + sprintf(aname, "%s/doc/%s.msgs.are", getenv("MBSE_ROOT"), mgroup.Name); + ad = fopen(aname, "w"); + fprintf(ad, "; Mail areas in group %s\n", mgroup.Name); + fprintf(ad, ";\n"); + + fseek(fd, msgshdr.hdrsize, SEEK_SET); + while ((fread(&msgs, msgshdr.recsize, 1, fd)) == 1) { + if (msgs.Active && strlen(msgs.Tag) && + strcmp(mgroup.Name, msgs.Group) == 0) { + fprintf(ad, "%-35s %s\n", msgs.Tag, msgs.Name); + fprintf(td, "%s\n", msgs.Tag); + } + + fseek(fd, msgshdr.syssize, SEEK_CUR); + } + fclose(ad); + fclose(td); + } + } + fclose(fg); + fclose(fd); + } + + sprintf(gname, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + sprintf(dname, "%s/etc/tic.data", getenv("MBSE_ROOT")); + + if (((fg = fopen(gname, "r")) == NULL) || + ((fd = fopen(dname, "r")) == NULL)) { + WriteError("$Can't open data"); + } else { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fg); + fread(&tichdr, sizeof(tichdr), 1, fd); + + while ((fread(&fgroup, fgrouphdr.recsize, 1, fg)) == 1) { + if (fgroup.Active) { + sprintf(tname, "%s/doc/%s.file.tag", getenv("MBSE_ROOT"), fgroup.Name); + td = fopen(tname, "w"); + sprintf(aname, "%s/doc/%s.file.are", getenv("MBSE_ROOT"), fgroup.Name); + ad = fopen(aname, "w"); + fprintf(ad, "; TIC file areas in group %s\n", fgroup.Name); + fprintf(ad, ";\n"); + + fseek(fd, tichdr.hdrsize, SEEK_SET); + while ((fread(&tic, tichdr.recsize, 1, fd)) == 1) { + if (tic.Active && strlen(tic.Name) && + strcmp(fgroup.Name, tic.Group) == 0) { + fprintf(ad, "%-21s %s\n", tic.Name, tic.Comment); + fprintf(td, "%s\n", tic.Name); + } + + fseek(fd, tichdr.syssize, SEEK_CUR); + } + fclose(ad); + fclose(td); + } + } + fclose(fg); + fclose(fd); + } + + free(aname); + free(tname); + free(dname); + free(gname); +} + + diff --git a/mbfido/maketags.h b/mbfido/maketags.h new file mode 100644 index 00000000..33dbdb24 --- /dev/null +++ b/mbfido/maketags.h @@ -0,0 +1,9 @@ +#ifndef _MAKETAGS_H +#define _MAKETAGS_H + + +void MakeTags(void); + + +#endif + diff --git a/mbfido/maptabs.tgz b/mbfido/maptabs.tgz new file mode 100644 index 00000000..9270b3e6 Binary files /dev/null and b/mbfido/maptabs.tgz differ diff --git a/mbfido/mbaff.c b/mbfido/mbaff.c new file mode 100644 index 00000000..2a6792b7 --- /dev/null +++ b/mbfido/mbaff.c @@ -0,0 +1,196 @@ +/***************************************************************************** + * + * File ..................: mbaff/mbaff.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "announce.h" +#include "filefind.h" +#include "mbaff.h" + + + +int do_announce = FALSE; /* Announce flag */ +int do_filefind = FALSE; /* FileFind flag */ +extern int do_quiet; /* Supress screen output */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ + + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBAFF: MBSE BBS %s Announce new files and FileFind\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBAFF finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i, Mail = FALSE; + char *cmd; + struct passwd *pw; + struct tm *t; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + time(&t_start); + t = localtime(&t_start); + Diw = t->tm_wday; + Miy = t->tm_mon; + umask(002); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM) || + (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line: mbaff"); + + for (i = 1; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (!strncmp(argv[i], "a", 1)) + do_announce = TRUE; + if (!strncmp(argv[i], "f", 1)) + do_filefind = TRUE; + if (!strncmp(argv[i], "-q", 2)) + do_quiet = TRUE; + + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbaff", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBAFF v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) + printf("\n"); + + if (!diskfree(CFG.freespace)) + die(101); + + memset(&MsgBase, 0, sizeof(MsgBase)); + + if (do_announce) + if (Announce()) + Mail = TRUE; + + if (do_filefind) + if (Filefind()) + Mail = TRUE; + + if (Mail) { + CreateSema((char *)"mailout"); + CreateSema((char *)"msglink"); + } + + die(0); + return 0; +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbaff [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" a announce Announce new files\n"); + printf(" f filefind FileFind service\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -q -quiet Quiet mode\n"); + colour(7, 0); + printf("\n"); + die(0); +} + + diff --git a/mbfido/mbaff.h b/mbfido/mbaff.h new file mode 100644 index 00000000..1969a11e --- /dev/null +++ b/mbfido/mbaff.h @@ -0,0 +1,9 @@ +#ifndef _MBAFF_H_ +#define _MBAFF_H + + +void Help(void); /* Show help screen */ + + +#endif + diff --git a/mbfido/mbdiff.c b/mbfido/mbdiff.c new file mode 100644 index 00000000..665651ca --- /dev/null +++ b/mbfido/mbdiff.c @@ -0,0 +1,576 @@ +/***************************************************************************** + * + * File ..................: mbdiff/mbdiff.c + * Purpose ...............: Nodelist diff processor + * Last modification date : 25-May-2001 + * Original ideas ........: Eugene G. Crosser. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbdiff.h" + + + +#ifndef BLKSIZ +#define BLKSIZ 512 +#endif + +extern unsigned short crc16xmodemtab[]; +#define updcrc(cp, crc) ( crc16xmodemtab[((crc >> 8) & 255) ^ cp] ^ (crc << 8)) + +extern int show_log; +extern int e_pid; +extern int do_quiet; /* Supress screen output */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ + + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBDIFF: MBSE BBS %s Nodelist diff processor\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + /* + * First check if a child is running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeded", e_pid); + else + WriteError("$Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode... + */ + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBDIFF finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i, Match; + char *cmd, *nl = NULL, *nd = NULL, *nn; + int rc; + char *p, *q, *arc; + struct passwd *pw; + char *wrk, *onl, *ond; + DIR *dp; + struct dirent *de; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + time(&t_start); + umask(002); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 3) + Help(); + + cmd = xstrcpy((char *)"Cmd: mbdiff"); + + for (i = 1; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + + if (i == 1) + if ((nl = argv[i]) == NULL) + Help(); + if (i == 2) + if ((nd = argv[i]) == NULL) + Help(); + if (!strncasecmp(argv[i], "-q", 2)) + do_quiet = TRUE; + + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbdiff", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBDIFF v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + colour(12, 0); + printf("\n"); + } + + if (!diskfree(CFG.freespace)) + die(101); + + /* + * Extract work directory from the first commandline parameter + * and set that directory as default. + */ + show_log = TRUE; + wrk = xstrcpy(nl); + if (strrchr(wrk, '/') == NULL) { + WriteError("No path in nodelist name"); + free(wrk); + die(100); + } + if (strrchr(wrk, '.') != NULL) { + WriteError("Filename extension given for nodelist"); + free(wrk); + die(100); + } + if (strrchr(nd, '/') == NULL) { + WriteError("No path in nodediff name"); + free(wrk); + die(100); + } + show_log = FALSE; + + while (wrk[strlen(wrk) -1] != '/') + wrk[strlen(wrk) -1] = '\0'; + wrk[strlen(wrk) -1] = '\0'; + + show_log = TRUE; + if (access(wrk, R_OK|W_OK)) { + WriteError("$No R/W access in %s", wrk); + free(wrk); + die(100); + } + + if (chdir(wrk)) { + WriteError("$Can't chdir to %s", wrk); + free(wrk); + die(100); + } + show_log = FALSE; + + onl = xstrcpy(strrchr(nl, '/') + 1); + onl = xstrcat(onl, (char *)".???"); + + if ((dp = opendir(wrk)) == 0) { + show_log = TRUE; + free(wrk); + WriteError("$Error opening directory %s", wrk); + die(100); + } + + Match = FALSE; + while ((de = readdir(dp))) { + if (strlen(de->d_name) == strlen(onl)) { + Match = TRUE; + for (i = 0; i < strlen(onl); i++) { + if ((onl[i] != '?') && (onl[i] != de->d_name[i])) + Match = FALSE; + } + if (Match) { + free(onl); + onl = xstrcpy(de->d_name); + break; + } + } + } + closedir(dp); + if (!Match) { + show_log = TRUE; + free(wrk); + free(onl); + WriteError("Old nodelist not found"); + die(100); + } + + /* + * Now try to get the diff file into the workdir. + */ + if ((arc = unpacker(nd)) == NULL) { + show_log = TRUE; + free(onl); + free(wrk); + WriteError("Can't get filetype for %s", nd); + die(100); + } + + ond = xstrcpy(strrchr(nd, '/') + 1); + + if (strncmp(arc, "ASC", 3)) { + if (!getarchiver(arc)) { + show_log = TRUE; + free(onl); + free(wrk); + free(ond); + WriteError("Can't find unarchiver %s", arc); + die(100); + } + + /* + * We may both use the unarchive command for files and mail, + * unarchiving isn't recursive anyway. + */ + if (strlen(archiver.funarc)) + cmd = xstrcpy(archiver.funarc); + else + cmd = xstrcpy(archiver.munarc); + + if ((cmd == NULL) || (cmd == "")) { + show_log = TRUE; + free(cmd); + free(onl); + free(wrk); + free(ond); + WriteError("No unarc command available for %s", arc); + die(100); + } + + if (execute(cmd, nd, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")) { + show_log = TRUE; + free(cmd); + free(onl); + free(wrk); + free(ond); + WriteError("Unpack error"); + die(100); + } + free(cmd); + + Match = FALSE; + if ((dp = opendir(wrk)) != NULL) { + while ((de = readdir(dp))) { + if (strlen(ond) == strlen(de->d_name)) { + Match = TRUE; + for (i = 0; i < (strlen(ond) -3); i++) + if (toupper(ond[i]) != toupper(de->d_name[i])) + Match = FALSE; + if (Match) { + free(ond); + ond = xstrcpy(de->d_name); + break; + } + } + } + closedir(dp); + } + if (!Match) { + show_log = TRUE; + free(ond); + free(onl); + free(wrk); + WriteError("Could not find extracted file"); + die(100); + } + } else { + if (file_cp(nd, ond)) { + show_log = TRUE; + free(ond); + free(onl); + free(wrk); + WriteError("$Copy %s failed", nd); + die(100); + } + Syslog('s', "Copied %s", nd); + } + + if (((p = strrchr(onl, '.'))) && ((q = strrchr(ond, '.'))) && + (strlen(p) == strlen(q))) { + nn = xstrcpy(onl); + p = strrchr(nn, '.') + 1; + q++; + strcpy(p, q); + } else + nn = xstrcpy((char *)"newnodelist"); + + if (strcmp(onl, nn) == 0) { + show_log = TRUE; + WriteError("Attempt to update nodelist to the same version"); + unlink(ond); + free(ond); + free(onl); + free(wrk); + free(nn); + die(100); + } + + Syslog('+', "Apply %s with %s to %s", onl, ond, nn); + if (!do_quiet) { + colour(3, 0); + printf("Apply %s with %s to %s\n", onl, ond, nn); + } + rc = apply(onl, ond, nn); + + unlink(ond); + if (rc) { + unlink(nn); + free(nn); + free(ond); + free(onl); + free(wrk); + die(rc + 100); + } else { + unlink(onl); + cmd = xstrcpy(archiver.farc); + + if ((cmd == NULL) || (!strlen(cmd))) { + free(cmd); + Syslog('+', "No archive command for %s, fallback to ZIP", arc); + if (!getarchiver((char *)"ZIP")) { + WriteError("No ZIP command available"); + free(ond); + free(onl); + free(wrk); + free(nn); + die(100); + } else { + cmd = xstrcpy(archiver.farc); + } + } else { + free(cmd); + cmd = xstrcpy(archiver.farc); + } + + if ((cmd == NULL) || (!strlen(cmd))) { + WriteError("No archiver command available"); + } else { + free(onl); + onl = xstrcpy(nn); + onl[strlen(onl) -3] = tolower(archiver.name[0]); + tl(onl); + p = xstrcpy(onl); + p = xstrcat(p, (char *)" "); + p = xstrcat(p, nn); + if (execute(cmd, p, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")) + WriteError("Create %s failed", onl); + else { + CreateSema((char *)"mailin"); + } + free(p); + free(cmd); + } + + free(onl); + free(ond); + free(wrk); + free(nn); + die(0); + } + return 0; +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbdiff [nodelist] [nodediff] \n\n"); + colour(3, 0); + printf(" The nodelist must be the full path and filename\n"); + printf(" without the dot and daynumber digits to the working\n"); + printf(" directory of that nodelist.\n"); + printf(" The nodediff must be the full path and filename\n"); + printf(" to the (compressed) nodediff file in the download\n"); + printf(" directory.\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -quiet Quiet mode\n"); + colour(7, 0); + printf("\n"); + die(99); +} + + + +int apply(char *nl, char *nd, char *nn) +{ + FILE *fo, *fd, *fn; + unsigned char cmdbuf[BLKSIZ]; + unsigned char lnbuf[BLKSIZ]; + int i, count; + int ac = 0, cc = 0, dc = 0; + int rc = 0; + int firstline = 1; + unsigned short theircrc = 0, mycrc = 0; + unsigned char *p; + + if ((fo = fopen(nl, "r")) == NULL) { + WriteError("$Can't open %s", nl); + return 2; + } + + if ((fd = fopen(nd, "r")) == NULL) { + WriteError("$Can't open %s", nd); + fclose(fo); + return 2; + } + + if ((fn = fopen(nn, "w")) == NULL) { + WriteError("$Can't open %s", nn); + fclose(fo); + fclose(fd); + return 2; + } + + if ((fgets(cmdbuf, sizeof(cmdbuf)-1, fd) == NULL) || + (fgets(lnbuf, sizeof(cmdbuf)-1, fo) == NULL) || + (strcmp(cmdbuf, lnbuf) != 0)) { + rc = 6; + } else { + rewind(fo); + rewind(fd); + + while ((rc == 0) && fgets(cmdbuf, sizeof(cmdbuf)-1, fd)) + switch (cmdbuf[0]) { + case ';': + Striplf(cmdbuf); + break; + case 'A': + count = atoi(cmdbuf+1); + ac += count; + Striplf(cmdbuf); + for (i = 0;(i < count) && (rc == 0); i++) + if (fgets(lnbuf, sizeof(lnbuf)-1, fd)) { + if (firstline) { + firstline = 0; + if ((p = strrchr(lnbuf, ':'))) { + theircrc = atoi(p+1); + } + } else { + for (p = lnbuf; *p; p++) + mycrc = updcrc(*p, mycrc); + } + fputs(lnbuf, fn); + } else + rc = 3; + break; + case 'D': + count = atoi(cmdbuf + 1); + dc += count; + Striplf(cmdbuf); + for (i = 0;(i < count) && (rc == 0); i++) + if (fgets(lnbuf, sizeof(lnbuf)-1, fo) == NULL) + rc = 3; + break; + case 'C': + count = atoi(cmdbuf+1); + cc += count; + Striplf(cmdbuf); + for (i = 0; (i < count) && (rc == 0); i++) + if (fgets(lnbuf, sizeof(lnbuf) - 1, fo)) { + for (p = lnbuf; *p; p++) + mycrc = updcrc(*p, mycrc); + fputs(lnbuf, fn); + } else + rc = 3; + break; + default: + rc = 5; + break; + } + } + + fclose(fo); + fclose(fd); + fclose(fn); + + if ((rc != 0) && !do_quiet) { + show_log = TRUE; + colour(12, 0); + } + + if ((rc == 0) && (mycrc != theircrc)) + rc = 4; + + if (rc == 3) + WriteError("Could not read some of the files"); + else if (rc == 4) + WriteError("CRC is %hu, should be %hu", mycrc, theircrc); + else if (rc == 5) + WriteError("Unknown input line: \"%s\"", cmdbuf); + else if (rc == 6) + WriteError("Diff does not match old list"); + else { + Syslog('+', "Copied %d, added %d, deleted %d, difference %d", cc, ac, dc, ac-dc); + if (!do_quiet) + printf("Created new nodelist\n"); + } + + return rc; +} + + diff --git a/mbfido/mbdiff.h b/mbfido/mbdiff.h new file mode 100644 index 00000000..4ebf13ad --- /dev/null +++ b/mbfido/mbdiff.h @@ -0,0 +1,12 @@ +#ifndef _MBFIFF_H +#define _MBDIFF_H + + +void Help(void); +int apply(char *, char *, char *); +char *unpacker(char *); +int getarchiver(char *); + + +#endif + diff --git a/mbfido/mbfido.c b/mbfido/mbfido.c new file mode 100644 index 00000000..9806abc6 --- /dev/null +++ b/mbfido/mbfido.c @@ -0,0 +1,663 @@ +/***************************************************************************** + * + * File ..................: mbfido/mbfido.c + * Purpose ...............: Process Fidonet style mail and files. + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbdupe.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "../lib/dbtic.h" +#include "../lib/msg.h" +#include "flock.h" +#include "tosspkt.h" +#include "pack.h" +#include "ulock.h" +#include "tic.h" +#include "fsort.h" +#include "scan.h" +#include "mbfido.h" +#include "tracker.h" +#include "notify.h" +#include "rollover.h" +#include "hatch.h" +#include "scannews.h" +#include "maketags.h" +#include "makestat.h" +#include "newspost.h" +#include "rnews.h" +#include "backalias.h" + + +#define UNPACK_FACTOR 300 + + +int do_toss = FALSE; /* Toss flag */ +int do_scan = FALSE; /* Scan flag */ +int do_tic = FALSE; /* Process .tic files */ +int do_notify = FALSE; /* Create notify messages */ +int do_roll = FALSE; /* Rollover only */ +int do_full = FALSE; /* Full mailscan */ +int do_tags = FALSE; /* Create taglists */ +int do_stat = FALSE; /* Create statistic HTML pages */ +int do_test = FALSE; /* Test routing */ +int do_news = FALSE; /* Process NNTP news */ +int do_uucp = FALSE; /* Process UUCP newsbatch */ +int do_unsec = FALSE; /* Unsecure tossing */ +int do_learn = FALSE; /* News articles learnmode */ +int check_crc = TRUE; /* Check .tic crc values */ +int check_dupe = TRUE; /* Check duplicates */ +int autocrea = FALSE; /* Autocreate new msg areas */ +extern int do_quiet; /* Quiet flag */ +extern int e_pid; /* Pid of child process */ +extern int show_log; /* Show logging on screen */ +int do_unprot = FALSE; /* Unprotected inbound flag */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +int packets = 0; /* Tossed packets */ +int packets_ok = 0; /* Tossed packets Ok. */ +char *envptr = NULL; + +extern int net_in, net_imp, net_out, net_bad; +extern int echo_in, echo_imp, echo_out, echo_bad, echo_dupe; +extern int email_in, email_imp, email_out, email_bad; +extern int news_in, news_imp, news_out, news_bad, news_dupe; +extern int tic_in, tic_imp, tic_out, tic_bad, tic_dup; +extern int Magics, Hatched; +extern int notify, filemgr, areamgr; + + + +/* + * If we don't know what to type + */ +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbfido [command(s)] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" ne news Scan for new news\n"); + printf(" no notify Send notify messages\n"); + printf(" r roll Rollover statistic counters\n"); + printf(" s scan Scan outgoing Fido mail\n"); + printf(" ta tag Create taglists\n"); + printf(" te test Do some testing\n"); + printf(" ti tic Process .tic files\n"); + printf(" to toss Toss incoming Fido mail\n"); + printf(" u uucp Process UUCP batchfile\n"); + printf(" w web Create WWW statistics\n\n"); + colour(9, 0); + printf(" Options are:\n\n"); + colour(3, 0); + printf(" -a -auto Autocreate new msg areas\n"); + printf(" -f -full Full Mailscan\n"); + printf(" -l -learn Learn News dupes\n"); + printf(" -noc -nocrc Skip CRC checking\n"); + printf(" -nod -nodupe Skip dupe checking\n"); + printf(" -q -quiet Quiet mode\n"); + printf(" -uns -unsecure Toss unsecure\n"); + printf(" -unp -unprotect Toss unprotected inbound\n"); + colour(7, 0); + ExitClient(0); +} + + + +/* + * Header, only if not quiet. + */ +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBFIDO: MBSE BBS %s - Fidonet File and Mail processor\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + /* + * First check if there is a child running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeeded", e_pid); + else + WriteError("Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode, reset the tty. + */ + system("stty sane"); + } + + CloseDupes(); + + /* + * Check for locked and open message base. + */ + if (MsgBase.Locked) + Msg_UnLock(); + if (MsgBase.Open) + Msg_Close(); + + signal(onsig, SIG_IGN); + + if (!do_quiet) { + show_log = TRUE; + colour(3, 0); + } + + if (onsig) { + if (onsig <= NSIG) + WriteError("Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + if (echo_imp + net_imp + net_out + echo_out) + CreateSema((char *)"msglink"); + + if (echo_out + net_out + tic_out) + CreateSema((char *)"scanout"); + + if (tic_imp) + CreateSema((char *)"reqindex"); + + if (net_in + net_imp + net_out + net_bad) + Syslog('+', "Netmail [%4d] import [%4d] out [%4d] bad [%4d]", + net_in, net_imp, net_out, net_bad); + if (email_in + email_imp + email_out + email_bad) + Syslog('+', "Email [%4d] import [%4d] out [%4d] bad [%4d]", + email_in, email_imp, email_out, email_bad); + if (echo_in + echo_imp + echo_out + echo_bad + echo_dupe) + Syslog('+', "Echomail [%4d] import [%4d] out [%4d] bad [%4d] dupe [%4d]", + echo_in, echo_imp, echo_out, echo_bad, echo_dupe); + if (news_in + news_imp + news_out + news_bad + news_dupe) + Syslog('+', "News [%4d] import [%4d] out [%4d] bad [%4d] dupe [%4d]", + news_in, news_imp, news_out, news_bad, news_dupe); + if (tic_in + tic_imp + tic_out + tic_bad + tic_dup) + Syslog('+', "TICfiles [%4d] import [%4d] out [%4d] bad [%4d] dupe [%4d]", + tic_in, tic_imp, tic_out, tic_bad, tic_dup); + if (Magics + Hatched) + Syslog('+', " Magics [%4d] hatch [%4d]", Magics, Hatched); + if (notify + areamgr + filemgr) + Syslog('+', "Notify msgs [%4d] AreaMgr [%4d] FileMgr [%4d]", notify, areamgr, filemgr); + + time(&t_end); + Syslog(' ', "MBFIDO finished in %s", t_elapsed(t_start, t_end)); + ulockunpack(); + + if (!do_quiet) + colour(7, 0); + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i, Loop; + char *p, *cmd, Options[81]; + struct passwd *pw; + struct tm *t; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * The next trick is to supply a fake environment variable + * MBSE_ROOT in case we are started from UUCP. + * this will setup the variable so InitConfig() will work. + * The /etc/passwd must point to the correct homedirectory. + */ + if (getenv("MBSE_ROOT") == NULL) { + pw = getpwuid(getuid()); + if (strcmp(pw->pw_name, "mbse")) { + /* + * We are not running as user mbse. + */ + pw = getpwnam("mbse"); + if (setuid(pw->pw_uid)) { + printf("Fatal error: can't set uid to user mbse\n"); + } + } + envptr = xstrcpy((char *)"MBSE_ROOT="); + envptr = xstrcat(envptr, pw->pw_dir); + putenv(envptr); + } + + InitConfig(); + memset(&Options, 0, sizeof(Options)); + + /* + * Initialize global variables, data records. + */ + InitNode(); + InitMsgs(); + InitTic(); + InitUser(); + InitFidonet(); + TermInit(1); + time(&t_start); + t = localtime(&t_start); + Diw = t->tm_wday; + Miy = t->tm_mon; + umask(002); + + /* + * Catch all the signals we can, and ignore the rest. + */ + for(i = 0; i < NSIG; i++) { + + if ((i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || + (i == SIGSEGV) || (i == SIGTERM) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if ((p = strrchr(argv[0], '/'))) + p++; + else + p = argv[0]; + if (!strcmp(p, "mbnews")) { + do_quiet = TRUE; + do_uucp = TRUE; + cmd = xstrcpy((char *)"Cmd: mbnews"); + } else { + if (argc < 2) + Help(); + cmd = xstrcpy((char *)"Cmd: mbfido"); + } + + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (strncmp(tl(argv[i]), "ne", 2) == 0) + do_news = TRUE; + if (strncmp(tl(argv[i]), "no", 2) == 0) { + do_notify = TRUE; + if (((i + 1) < argc) && + ((strchr(argv[i + 1], ':') != NULL) || + (atoi(argv[i + 1])) || + (strncmp(argv[i + 1], "*", 1) == 0))) { + sprintf(Options, "%s", argv[i + 1]); + i++; + } + } + if (strncmp(tl(argv[i]), "r", 1) == 0) + do_roll = TRUE; + if (strncmp(tl(argv[i]), "s", 1) == 0) + do_scan = TRUE; + if (strncmp(tl(argv[i]), "ta", 2) == 0) + do_tags = TRUE; + if (strncmp(tl(argv[i]), "ti", 2) == 0) + do_tic = TRUE; + if (strncmp(tl(argv[i]), "te", 2) == 0) + do_test = TRUE; + if (strncmp(tl(argv[i]), "to", 2) == 0) + do_toss = TRUE; + if (strncmp(tl(argv[i]), "u", 1) == 0) + do_uucp = TRUE; + if (strncmp(tl(argv[i]), "w", 1) == 0) + do_stat = TRUE; + if (strncmp(tl(argv[i]), "-a", 2) == 0) + autocrea = TRUE; + if (strncmp(tl(argv[i]), "-f", 2) == 0) + do_full = TRUE; + if (strncmp(tl(argv[i]), "-l", 2) == 0) + do_learn = TRUE; + if (strncmp(tl(argv[i]), "-noc", 4) == 0) + check_crc = FALSE; + if (strncmp(tl(argv[i]), "-nod", 4) == 0) + check_dupe = FALSE; + if (strncmp(tl(argv[i]), "-q", 2) == 0) + do_quiet = TRUE; + if (strncmp(tl(argv[i]), "-unp", 4) == 0) + do_unprot = TRUE; + if (strncmp(tl(argv[i]), "-uns", 4) == 0) + do_unsec = TRUE; + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbfido", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBFIDO v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + InitDupes(); + + if (!diskfree(CFG.freespace)) + die(101); + + if (lockunpack()) + die(0); + if (initnl()) + die(101); + Rollover(); + if (!do_quiet) + printf("\n"); + + /* + * Read alias file + */ + cmd = calloc(PATH_MAX, sizeof(char)); + sprintf(cmd, "%s/etc/aliases", getenv("MBSE_ROOT")); + if ((do_news || do_scan || do_toss) && file_exist(cmd, R_OK) == 0) + readalias(cmd); + free(cmd); + + if (do_notify) + if (Notify(Options)) + packmail(); + if (do_tic) { + if (IsSema((char *)"mailin")) + RemoveSema((char *)"mailin"); + /* + * Hatch new files and process .tic files + * until nothing left to do. + */ + if (!diskfree(CFG.freespace)) + die(101); + Loop = TRUE; + do { + Hatch(); + switch (Tic()) { + case -1: die(0); + break; + case 0: Loop = FALSE; + break; + default: break; + } + } while (Loop); + } + if (do_news) { + ScanNews(); + if (IsSema((char *)"newnews")) + RemoveSema((char *)"newnews"); + } + if (do_scan) + ScanMail(do_full); + if (do_toss) { + if (IsSema((char *)"mailin")) + RemoveSema((char *)"mailin"); + if (TossMail() == FALSE) + die(0); + } + if (!do_uucp) + newspost(); + if (do_test) + TestTracker(); + if (do_tags) + MakeTags(); + if (do_stat) + MakeStat(); + if (do_uucp) + NewsUUCP(FALSE); + die(0); + return 0; +} + + + +/* + * Toss Fidonet mail + */ +int TossMail(void) +{ + char *inbound, *fname; + DIR *dp; + struct dirent *de; + struct stat sbuf; + int files = 0, files_ok = 0; + int rc = 0, maxrc = 0; + fd_list *fdl = NULL; + + if (do_unprot) + inbound = xstrcpy(CFG.inbound); + else + inbound = xstrcpy(CFG.pinbound); + + Syslog('+', "Pass: toss netmail (%s)", inbound); + + if (chdir(inbound) == -1) { + WriteError("$Can't chdir(%s)", inbound); + die(0); + } + + /* + * First toss any netmail packets. + */ + maxrc = rc = TossPkts(); + chdir(inbound); + + /* + * Scan the directory for ARCmail archives. The archive extension + * numbering doesn't matter, as long as there is something, so + * all kind of ARCmail naming schemes are recognized. + */ + if ((dp = opendir(inbound)) == NULL) { + WriteError("$Can't opendir(%s)", inbound); + die(0); + } + + Syslog('+', "Pass: toss ARCmail (%s)", inbound); + + /* + * Add all ARCmail filenames to the memory array. + */ + sync(); + while ((de=readdir(dp))) + if ((strlen(de->d_name) == 12) && + ((strncasecmp(de->d_name+8,".su",3) == 0) || + (strncasecmp(de->d_name+8,".mo",3) == 0) || + (strncasecmp(de->d_name+8,".tu",3) == 0) || + (strncasecmp(de->d_name+8,".we",3) == 0) || + (strncasecmp(de->d_name+8,".th",3) == 0) || + (strncasecmp(de->d_name+8,".fr",3) == 0) || + (strncasecmp(de->d_name+8,".sa",3) == 0))) { + stat(de->d_name, &sbuf); + fill_fdlist(&fdl, de->d_name, sbuf.st_mtime); + } + + closedir(dp); + sort_fdlist(&fdl); + + /* + * Now process the archives, the oldest first. + */ + while ((fname = pull_fdlist(&fdl)) != NULL) { + files++; + IsDoing("Unpack arcmail"); + + if (IsSema((char *)"upsalarm")) { + Syslog('+', "Detected upsalarm semafore, aborting toss"); + break; + } + if (!diskfree(CFG.freespace)) { + rc = 101; + break; + } + + if (checkspace(inbound, fname, UNPACK_FACTOR)) + if ((rc = unpack(fname)) == 0) { + files_ok++; + sync(); + rc = TossPkts(); + chdir(inbound); + } else + WriteError("Error unpacking file %s", fname); + else + Syslog('!', "Insufficient space to unpack file %s", fname); + + if (rc > maxrc) + maxrc = rc; + } + + free(inbound); + if ((files || packets) && + ((files_ok != files) || (packets_ok != packets))) + Syslog('!', "Processed %d of %d files, %d of %d packets, rc=%d", + files_ok, files, packets_ok, packets, maxrc); + + return TRUE; +} + + + +/* + * Toss all packets currently in the inbound. Tossing is sorted by + * age of the files. + */ +int TossPkts(void) +{ + char *inbound = NULL, *fname; + DIR *dp; + struct dirent *de; + struct stat sbuf; + int rc = 0, maxrc = 0; + fd_list *fdl = NULL; + + IsDoing("Tossing mail"); + + if (do_unprot) + inbound = xstrcpy(CFG.inbound); + else + inbound = xstrcpy(CFG.pinbound); + + if ((dp = opendir(inbound)) == NULL) { + WriteError("$Can't opendir(%s)", inbound); + return FALSE; + } + + /* + * Read all .pkt filenames, get the timestamp and add them + * to the memory array for later sort on filedate. + */ + while((de = readdir(dp))) + if ((strlen(de->d_name) == 12) && + (strncasecmp(de->d_name+8,".pkt",4) == 0)) { + stat(de->d_name, &sbuf); + fill_fdlist(&fdl, de->d_name, sbuf.st_mtime); + } + + closedir(dp); + sort_fdlist(&fdl); + + /* + * Get the filenames, the oldest first until nothing left. + */ + while ((fname = pull_fdlist(&fdl)) != NULL) { + + if (!diskfree(CFG.freespace)) + return FALSE; + packets++; + + /* + * See if "pktdate" from Tobias Ernst (or another + * preprocessor) is installed. + */ + if (strlen(CFG.pktdate)) { + rc = execute(CFG.pktdate, fname, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); + if (rc) + Syslog('+', "%s preprocessing rc=%d", fname, rc); + } + + if ((rc = toss(fname)) == 0) + packets_ok++; + else + WriteError("Error tossing packet %s", fname); + if (rc > maxrc) + maxrc = rc; + } + + free(inbound); + if (diskfree(CFG.freespace)) + packmail(); + return maxrc; +} + + + +/* + * Toss one packet + */ +int toss(char *fn) +{ + int rc, ld; + char newname[16]; + + rc = 0; + /* + * Lock the packet + */ + if ((ld = f_lock(fn)) == -1) + return 1; + + rc = TossPkt(fn); + if (rc == 0) { + unlink(fn); + } else { + strncpy(newname,fn,sizeof(newname)-1); + strcpy(newname+8,".bad"); + rename(fn,newname); + } + + funlock(ld); + return rc; +} + + diff --git a/mbfido/mbfido.h b/mbfido/mbfido.h new file mode 100644 index 00000000..67facb0f --- /dev/null +++ b/mbfido/mbfido.h @@ -0,0 +1,15 @@ +/* mbfido.h */ + +#ifndef _MBFIDO_H +#define _MBFIDO_H + +void Help(void); +void ProgName(void); +void die(int); +int TossPkts(void); +int TossMail(void); +int toss(char *); + +#endif + + diff --git a/mbfido/mbfile.c b/mbfido/mbfile.c new file mode 100644 index 00000000..02edd1a9 --- /dev/null +++ b/mbfido/mbfile.c @@ -0,0 +1,1002 @@ +/***************************************************************************** + * + * File ..................: mbfile/mbfile.c + * Purpose ...............: File Database Maintenance + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbfile.h" + + + +extern int do_quiet; /* Supress screen output */ +int do_pack = FALSE; /* Pack filebase */ +int do_check = FALSE; /* Check filebase */ +int do_kill = FALSE; /* Kill/move old files */ +int do_index = FALSE; /* Create request index */ +extern int e_pid; /* Pid of external process */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +int marker = 0; /* Marker counter */ + + +typedef struct _Index { + struct _Index *next; + struct FILEIndex idx; +} Findex; + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBFILE: MBSE BBS %s File maintenance utility\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + /* + * First check if a child is running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeded", e_pid); + else + WriteError("$Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode... + */ + if (!do_quiet) + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBFILE finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i; + char *cmd; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + time(&t_start); + umask(002); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGBUS) || (i == SIGKILL) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line: mbfile"); + + for (i = 1; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (!strncmp(argv[i], "i", 1)) + do_index = TRUE; + if (!strncmp(argv[i], "p", 1)) + do_pack = TRUE; + if (!strncmp(argv[i], "c", 1)) + do_check = TRUE; + if (!strncmp(argv[i], "k", 1)) + do_kill = TRUE; + if (!strncmp(argv[i], "-q", 2)) + do_quiet = TRUE; + } + + if (!(do_pack || do_check || do_kill || do_index)) + Help(); + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbfile", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBFILE v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) + printf("\n"); + + if (!diskfree(CFG.freespace)) + die(101); + + if (do_kill) + Kill(); + + if (do_check) + Check(); + + if (do_pack) + PackFileBase(); + + if (do_index) + Index(); + + die(0); + return 0; +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbfile [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" c check Check filebase\n"); + printf(" i index Create filerequest index\n"); + printf(" k kill Kill/move old files\n"); + printf(" p pack Pack filebase\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -q -quiet Quiet mode\n"); + colour(7, 0); + printf("\n"); + die(0); +} + + + +void Marker(void) +{ + /* + * Keep the connection with the server alive + */ + Nopper(); + + /* + * Release system resources when running in the background + */ + if (CFG.slow_util && do_quiet) + usleep(1); + + if (do_quiet) + return; + + switch (marker) { + case 0: printf(">---"); + break; + + case 1: printf(">>--"); + break; + + case 2: printf(">>>-"); + break; + + case 3: printf(">>>>"); + break; + + case 4: printf("<>>>"); + break; + + case 5: printf("<<>>"); + break; + + case 6: printf("<<<>"); + break; + + case 7: printf("<<<<"); + break; + + case 8: printf("-<<<"); + break; + + case 9: printf("--<<"); + break; + + case 10:printf("---<"); + break; + + case 11:printf("----"); + break; + } + printf("\b\b\b\b"); + fflush(stdout); + + if (marker < 11) + marker++; + else + marker = 0; +} + + + +/* + * Check files for age, and not downloaded for x days. If they match + * one of these criteria (setable in areas setup), the file will be + * move to some retire area or deleted, depending on the setup. + * If they are moved, the upload date is reset to the current date, + * so you can set new removal criteria again. + */ +void Kill(void) +{ + FILE *pAreas, *pFile, *pDest, *pTemp; + int i, iAreas, iAreasNew = 0; + int iTotal = 0, iKilled = 0, iMoved = 0; + char *sAreas, *fAreas, *newdir = NULL, *sTemp; + time_t Now; + int rc, Killit, FilesLeft; + struct fileareas darea; + char from[128], to[128]; + + sAreas = calloc(81, sizeof(char)); + fAreas = calloc(81, sizeof(char)); + sTemp = calloc(81, sizeof(char)); + + IsDoing("Kill files"); + if (!do_quiet) { + colour(3, 0); + printf("Kill/move files...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + die(0); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreas = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + Now = time(NULL); + + for (i = 1; i <= iAreas; i++) { + + fseek(pAreas, ((i-1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + + if ((area.Available) && (area.DLdays || area.FDdays) && (!area.CDrom)) { + + if (!diskfree(CFG.freespace)) + die(101); + + if (!do_quiet) { + printf("\r%4d => %-44s \b\b\b\b", i, area.Name); + fflush(stdout); + } + + /* + * Check if download directory exists, + * if not, create the directory. + */ + if (access(area.Path, R_OK) == -1) { + Syslog('!', "Create dir: %s", area.Path); + newdir = xstrcpy(area.Path); + newdir = xstrcat(newdir, (char *)"/"); + mkdirs(newdir); + free(newdir); + newdir = NULL; + } + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), i); + + /* + * Open the file database, if it doesn't exist, + * create an empty one. + */ + if ((pFile = fopen(fAreas, "r+")) == NULL) { + Syslog('!', "Creating new %s", fAreas); + if ((pFile = fopen(fAreas, "a+")) == NULL) { + WriteError("$Can't create %s", fAreas); + die(0); + } + } + + /* + * Now start checking the files in the filedatabase + * against the contents of the directory. + */ + while (fread(&file, sizeof(file), 1, pFile) == 1) { + iTotal++; + Marker(); + + Killit = FALSE; + if (area.DLdays) { + /* + * Test last download date or never downloaded and the + * file is more then n days available for download. + */ + if ((file.LastDL) && + (((Now - file.LastDL) / 84400) > area.DLdays)) { + Killit = TRUE; + } + if ((!file.LastDL) && + (((Now - file.UploadDate) / 84400) > area.DLdays)) { + Killit = TRUE; + } + } + + if (area.FDdays) { + /* + * Check filedate + */ + if (((Now - file.UploadDate) / 84400) > area.FDdays) { + Killit = TRUE; + } + } + + if (Killit) { + do_pack = TRUE; + if (area.MoveArea) { + fseek(pAreas, ((area.MoveArea -1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&darea, areahdr.recsize, 1, pAreas); + sprintf(from, "%s/%s", area.Path, file.Name); + sprintf(to, "%s/%s", darea.Path, file.Name); + if ((rc = file_mv(from, to)) == 0) { + Syslog('+', "Move %s, area %d => %d", file.Name, i, area.MoveArea); + sprintf(to, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), area.MoveArea); + if ((pDest = fopen(to, "a+")) != NULL) { + file.UploadDate = time(NULL); + file.LastDL = time(NULL); + fwrite(&file, sizeof(file), 1, pDest); + fclose(pDest); + } + /* + * Now again if there is a dotted version (thumbnail) of this file. + */ + sprintf(from, "%s/.%s", area.Path, file.Name); + sprintf(to, "%s/.%s", darea.Path, file.Name); + if (file_exist(from, R_OK) == 0) + file_mv(from, to); + file.Deleted = TRUE; + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + iMoved++; + } else { + WriteError("Move %s failed rc = %d", file.Name, rc); + } + } else { + Syslog('+', "Delete %s, area %d", file.Name, i); + file.Deleted = TRUE; + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + iKilled++; + sprintf(from, "%s/%s", area.Path, file.Name); + unlink(from); + } + } + } + + /* + * Now we must pack this area database otherwise + * we run into trouble later on. + */ + fseek(pFile, 0, SEEK_SET); + sprintf(sTemp, "%s/fdb/fdbtmp.data", getenv("MBSE_ROOT")); + + if ((pTemp = fopen(sTemp, "a+")) != NULL) { + FilesLeft = FALSE; + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if ((!file.Deleted) && strcmp(file.Name, "") != 0) { + fwrite(&file, sizeof(file), 1, pTemp); + FilesLeft = TRUE; + } + } + + fclose(pFile); + fclose(pTemp); + if ((rename(sTemp, fAreas)) == 0) { + unlink(sTemp); + chmod(fAreas, 006600); + } + if (!FilesLeft) { + Syslog('+', "Warning: area %d (%s) is empty", i, area.Name); + } + } else + fclose(pFile); + + iAreasNew++; + + } /* if area.Available */ + } + + fclose(pAreas); + + Syslog('+', "Kill Areas [%5d] Files [%5d] Deleted [%5d] Moved [%5d]", iAreasNew, iTotal, iKilled, iMoved); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + free(sTemp); + free(sAreas); + free(fAreas); +} + + + +void tidy_index(Findex **); +void tidy_index(Findex **fap) +{ + Findex *tmp, *old; + + for (tmp = *fap; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fap = NULL; +} + + + +void fill_index(struct FILEIndex, Findex **); +void fill_index(struct FILEIndex idx, Findex **fap) +{ + Findex *tmp; + + tmp = (Findex *)malloc(sizeof(Findex)); + tmp->next = *fap; + tmp->idx = idx; + *fap = tmp; +} + + +int comp_index(Findex **, Findex **); + +void sort_index(Findex **); +void sort_index(Findex **fap) +{ + Findex *ta, **vector; + size_t n = 0, i; + + if (*fap == NULL) + return; + + for (ta = *fap; ta; ta = ta->next) + n++; + + vector = (Findex **)malloc(n * sizeof(Findex *)); + + i = 0; + for (ta = *fap; ta; ta = ta->next) + vector[i++] = ta; + + qsort(vector, n, sizeof(Findex *), + (int(*)(const void*, const void *))comp_index); + + (*fap) = vector[0]; + i = 1; + + for (ta = *fap; ta; ta = ta->next) { + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int comp_index(Findex **fap1, Findex **fap2) +{ + return strcasecmp((*fap1)->idx.LName, (*fap2)->idx.LName); +} + + + +/* + * Build a sorted index for the file request processor. + */ +void Index(void) +{ + FILE *pAreas, *pFile, *pIndex; + long i, iAreas, iAreasNew = 0, record; + int iTotal = 0; + char *sAreas, *fAreas, *newdir = NULL, *sIndex; + Findex *fdx = NULL; + Findex *tmp; + struct FILEIndex idx; + + sAreas = calloc(81, sizeof(char)); + fAreas = calloc(81, sizeof(char)); + sIndex = calloc(81, sizeof(char)); + + IsDoing("Kill files"); + if (!do_quiet) { + colour(3, 0); + printf("Create filerequest index...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open %s", sAreas); + die(0); + } + + sprintf(sIndex, "%s/etc/request.index", getenv("MBSE_ROOT")); + if ((pIndex = fopen(sIndex, "w")) == NULL) { + WriteError("$Can't create %s", sIndex); + die(0); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreas = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + + for (i = 1; i <= iAreas; i++) { + + fseek(pAreas, ((i-1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + + if ((area.Available) && (area.FileReq)) { + + if (!diskfree(CFG.freespace)) + die(101); + + if (!do_quiet) { + printf("\r%4ld => %-44s \b\b\b\b", i, area.Name); + fflush(stdout); + } + + /* + * Check if download directory exists, + * if not, create the directory. + */ + if (access(area.Path, R_OK) == -1) { + Syslog('!', "Create dir: %s", area.Path); + newdir = xstrcpy(area.Path); + newdir = xstrcat(newdir, (char *)"/"); + mkdirs(newdir); + free(newdir); + newdir = NULL; + } + + sprintf(fAreas, "%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), i); + + /* + * Open the file database, if it doesn't exist, + * create an empty one. + */ + if ((pFile = fopen(fAreas, "r+")) == NULL) { + Syslog('!', "Creating new %s", fAreas); + if ((pFile = fopen(fAreas, "a+")) == NULL) { + WriteError("$Can't create %s", fAreas); + die(0); + } + } + + /* + * Now start creating the unsorted index. + */ + record = 0; + while (fread(&file, sizeof(file), 1, pFile) == 1) { + iTotal++; + if ((iTotal % 10) == 0) + Marker(); + memset(&idx, 0, sizeof(idx)); + sprintf(idx.Name, "%s", tu(file.Name)); + sprintf(idx.LName, "%s", tu(file.LName)); + idx.AreaNum = i; + idx.Record = record; + fill_index(idx, &fdx); + record++; + } + + fclose(pFile); + iAreasNew++; + + } /* if area.Available */ + } + + fclose(pAreas); + + sort_index(&fdx); + for (tmp = fdx; tmp; tmp = tmp->next) + fwrite(&tmp->idx, sizeof(struct FILEIndex), 1, pIndex); + fclose(pIndex); + tidy_index(&fdx); + + Syslog('+', "Index Areas [%5d] Files [%5d]", iAreasNew, iTotal); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + free(sIndex); + free(sAreas); + free(fAreas); + RemoveSema((char *)"reqindex"); +} + + + +/* + * Check file database integrity, all files in the file database must + * exist in real, the size and date/time must match, the files crc is + * checked, and if anything is wrong, the file database is updated. + * If the file is missing the entry is marked as deleted. With the + * pack option that record will be removed. + * After these checks, de database is checked for missing records, if + * there are files on disk but not in the directory these files are + * deleted. System files (beginning with a dot) are left alone and + * the files 'files.bbs', 'files.bak', '00index', 'header' 'readme' + * and 'index.html' too. + * + * Remarks: Maybe if the crc check fails, and the date and time are + * ok, the file is damaged and must be made unavailable. + */ +void Check(void) +{ + FILE *pAreas, *pFile; + int i, iAreas, iAreasNew = 0; + int iTotal = 0, iErrors = 0; + char *sAreas, *fAreas, *newdir; + DIR *dp; + struct dirent *de; + int Found, Update; + char fn[128]; + struct stat stb; + + sAreas = calloc(81, sizeof(char)); + fAreas = calloc(81, sizeof(char)); + newdir = calloc(81, sizeof(char)); + + if (!do_quiet) { + colour(3, 0); + printf("Checking file database...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + die(0); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreas = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + + for (i = 1; i <= iAreas; i++) { + + fseek(pAreas, ((i-1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + + if (area.Available) { + + IsDoing("Check area %d", i); + + if (!do_quiet) { + printf("\r%4d => %-44s \b\b\b\b", i, area.Name); + fflush(stdout); + } + + /* + * Check if download directory exists, + * if not, create the directory. + */ + if (access(area.Path, R_OK) == -1) { + Syslog('!', "No dir: %s", area.Path); + sprintf(newdir, "%s/foobar", area.Path); + mkdirs(newdir); + } + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), i); + + /* + * Open the file database, if it doesn't exist, + * create an empty one. + */ + if ((pFile = fopen(fAreas, "r+")) == NULL) { + Syslog('!', "Creating new %s", fAreas); + if ((pFile = fopen(fAreas, "a+")) == NULL) { + WriteError("$Can't create %s", fAreas); + die(0); + } + } + + /* + * Now start checking the files in the filedatabase + * against the contents of the directory. + */ + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + iTotal++; + sprintf(newdir, "%s/%s", area.Path, file.Name); + + if (file_exist(newdir, R_OK)) { + Syslog('+', "File %s area %d not on disk.", newdir, i); + if (!file.NoKill) { + file.Deleted = TRUE; + do_pack = TRUE; + } + iErrors++; + file.Missing = TRUE; + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + } else { + /* + * File exists, now check the file. + */ + Marker(); + Update = FALSE; + if (file_time(newdir) != file.FileDate) { + Syslog('!', "Date mismatch area %d file %s", i, file.Name); + file.FileDate = file_time(newdir); + iErrors++; + Update = TRUE; + } + if (file_size(newdir) != file.Size) { + Syslog('!', "Size mismatch area %d file %s", i, file.Name); + file.Size = file_size(newdir); + iErrors++; + Update = TRUE; + } + if (file_crc(newdir, CFG.slow_util && do_quiet) != file.Crc32) { + Syslog('!', "CRC error area %d, file %s", i, file.Name); + file.Crc32 = file_crc(newdir, CFG.slow_util && do_quiet); + iErrors++; + Update = TRUE; + } + Marker(); + if (Update) { + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + } + } + } + + /* + * Check files in the directory against the database. + * This test is skipped for CD-rom. + */ + if (!area.CDrom) { + if ((dp = opendir(area.Path)) != NULL) { + while ((de = readdir(dp)) != NULL) { + if (de->d_name[0] != '.') { + Marker(); + Found = FALSE; + rewind(pFile); + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if (strcmp(file.Name, de->d_name) == 0) { + Found = TRUE; + break; + } + } + if ((!Found) && + (strncmp(de->d_name, "files.bbs", 9)) && + (strncmp(de->d_name, "files.bak", 9)) && + (strncmp(de->d_name, "00index", 7)) && + (strncmp(de->d_name, "header", 6)) && + (strncmp(de->d_name, "index", 5)) && + (strncmp(de->d_name, "readme", 6))) { + sprintf(fn, "%s/%s", area.Path, de->d_name); + if (stat(fn, &stb) == 0) + if (S_ISREG(stb.st_mode)) { + if (unlink(fn) == 0) { + Syslog('!', "%s not in fdb, deleted from disk", fn); + iErrors++; + } else { + WriteError("$%s not in fdb, cannot delete", fn); + } + } + } + } + } + closedir(dp); + } else { + WriteError("Can't open %s", area.Path); + } + } + + fclose(pFile); + iAreasNew++; + + } /* if area.Available */ + } + + fclose(pAreas); + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + free(newdir); + free(sAreas); + free(fAreas); + + Syslog('+', "Check Areas [%5d] Files [%5d] Errors [%5d]", iAreasNew, iTotal, iErrors); +} + + + +/* + * Removes records who are marked for deletion. If there is still a file + * on disk, it will be removed too. + */ +void PackFileBase(void) +{ + FILE *fp, *pAreas, *pFile; + int i, iAreas, iAreasNew = 0; + int iTotal = 0, iRemoved = 0; + char *sAreas, *fAreas, *fTmp, fn[128]; + + sAreas = calloc(81, sizeof(char)); + fAreas = calloc(81, sizeof(char)); + fTmp = calloc(81, sizeof(char)); + + IsDoing("Pack filebase"); + if (!do_quiet) { + colour(3, 0); + printf("Packing file database...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + die(0); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreas = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + + for (i = 1; i <= iAreas; i++) { + + fseek(pAreas, ((i-1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + + if (area.Available && !area.CDrom) { + + if (!diskfree(CFG.freespace)) + die(101); + + if (!do_quiet) { + printf("\r%4d => %-44s", i, area.Name); + fflush(stdout); + } + Marker(); + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), i); + sprintf(fTmp, "%s/fdb/fdbtmp.data", getenv("MBSE_ROOT")); + + if ((pFile = fopen(fAreas, "r")) == NULL) { + Syslog('!', "Creating new %s", fAreas); + if ((pFile = fopen(fAreas, "a+")) == NULL) { + WriteError("$Can't create %s", fAreas); + die(0); + } + } + + if ((fp = fopen(fTmp, "a+")) == NULL) { + WriteError("$Can't create %s", fTmp); + die(0); + } + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + iTotal++; + + if ((!file.Deleted) && (strcmp(file.Name, "") != 0)) { + fwrite(&file, sizeof(file), 1, fp); + } else { + iRemoved++; + Syslog('+', "Removed file \"%s\" from area %d", file.Name, i); + sprintf(fn, "%s/%s", area.Path, file.Name); + Syslog('+', "Unlink %s result %d", fn, unlink(fn)); + /* + * If a dotted version (thumbnail) exists, remove it silently + */ + sprintf(fn, "%s/.%s", area.Path, file.Name); + unlink(fn); + } + } + + fclose(fp); + fclose(pFile); + + if ((rename(fTmp, fAreas)) == 0) { + unlink(fTmp); + chmod(fAreas, 00660); + } + iAreasNew++; + + } /* if area.Available */ + } + + fclose(pAreas); + Syslog('+', "Pack Areas [%5d] Files [%5d] Removed [%5d]", iAreasNew, iTotal, iRemoved); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + free(fTmp); + free(sAreas); + free(fAreas); +} + + diff --git a/mbfido/mbfile.h b/mbfido/mbfile.h new file mode 100644 index 00000000..e6c8e841 --- /dev/null +++ b/mbfido/mbfile.h @@ -0,0 +1,12 @@ +#ifndef _MBFILE_H_ +#define _MBFILE_H + +void Help(void); /* Show help screen */ +void Check(void); /* Check file database */ +void Index(void); /* Index filerquest */ +void Req(void); /* Check symlinks */ +void Kill(void); /* Kill/move old files */ +void PackFileBase(void); /* Pack / Compress File Base */ +void CreateWeb(void); /* Create WWW pages */ +#endif + diff --git a/mbfido/mbindex.c b/mbfido/mbindex.c new file mode 100644 index 00000000..0c4569ac --- /dev/null +++ b/mbfido/mbindex.c @@ -0,0 +1,985 @@ +/***************************************************************************** + * + * File ..................: mbindex.c + * Purpose ...............: Nodelist Compiler + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbftn.h" + + +#define TMPNAME "TMP." +#define LCKNAME "LOCKFILE" + + +typedef struct _nl_list { + struct _nl_list *next; + struct _nlidx idx; +} nl_list; + + +#include "mbindex.h" + + +FILE *ifp, *ufp, *ffp; +long total = 0, entries = 0; +int filenr = 0; +unsigned short regio; +nl_list *nll = NULL; +static char lockfile[81]; + + +extern int do_quiet; /* Quiet flag */ +extern int show_log; /* Show logging on screen */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ + + +/* + * Put a lock on this program. + */ +int lockindex(void) +{ + char Tmpfile[81]; + FILE *fp; + pid_t oldpid; + + sprintf(Tmpfile, "%s/", CFG.nodelists); + strcpy(lockfile, Tmpfile); + sprintf(Tmpfile + strlen(Tmpfile), "%s%u", TMPNAME, getpid()); + sprintf(lockfile + strlen(lockfile), "%s", LCKNAME); + + if ((fp = fopen(Tmpfile, "w")) == NULL) { + WriteError("$Can't create lockfile \"%s\"", Tmpfile); + return 1; + } + fprintf(fp, "%10u\n", getpid()); + fclose(fp); + + while (TRUE) { + if (link(Tmpfile, lockfile) == 0) { + unlink(Tmpfile); + return 0; + } + if ((fp = fopen(lockfile, "r")) == NULL) { + WriteError("$Can't open lockfile \"%s\"", Tmpfile); + unlink(Tmpfile); + return 1; + } + if (fscanf(fp, "%u", &oldpid) != 1) { + WriteError("$Can't read old pid from \"%s\"", Tmpfile); + fclose(fp); + unlink(Tmpfile); + return 1; + } + fclose(fp); + if (kill(oldpid,0) == -1) { + if (errno == ESRCH) { + Syslog('+', "Stale lock found for pid %u", oldpid); + unlink(lockfile); + /* no return, try lock again */ + } else { + WriteError("$Kill for %u failed",oldpid); + unlink(Tmpfile); + return 1; + } + } else { + Syslog('+', "mbindex already running, pid=%u", oldpid); + if (!do_quiet) + printf("Another mbindex is already running.\n"); + unlink(Tmpfile); + return 1; + } + } +} + + + +void ulockindex(void) +{ + if (lockfile) + (void)unlink(lockfile); +} + + + +/* + * If we don't know what to type + */ +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbindex \n\n"); + colour(9, 0); + printf(" Options are:\n\n"); + colour(3, 0); + printf(" -quiet Quiet mode\n"); + colour(7, 0); + printf("\n"); + die(0); +} + + + +/* + * Header, only if not quiet. + */ +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBINDEX: MBSE BBS %s Nodelist Index Compiler\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); + colour(3, 0); +} + + + +void die(int onsig) +{ + if (onsig && (onsig < NSIG)) + signal(onsig, SIG_IGN); + + ulockindex(); + + if (!do_quiet) { + colour(3, 0); + show_log = TRUE; + } + + if (IsSema((char *)"mbindex")) + RemoveSema((char *)"mbindex"); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBINDEX finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) + colour(7, 0); + + ExitClient(onsig); +} + + + +int main(int argc,char *argv[]) +{ + int i, rc; + char *cmd; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + InitFidonet(); + TermInit(1); + t_start = time(NULL); + umask(002); + + /* + * Catch all the signals we can, and ignore the rest. + * Don't listen to SIGTERM. + */ + for(i = 0; i < NSIG; i++) { + + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + cmd = xstrcpy((char *)"Command line: mbindex"); + + if (argc > 2) + Help(); + + if (argc == 2) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[1]); + + if (strncasecmp(argv[1], "-q", 2) == 0) + do_quiet = TRUE; + else + Help(); + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbindex", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBINDEX v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!diskfree(CFG.freespace)) + die(101); + + if (lockindex()) { + if (!do_quiet) + printf("Can't lock mbindex, abort.\n"); + die(104); + } + + rc = nodebld(); + die(rc); + return 0; +} + + + +void tidy_nllist(nl_list **fap) +{ + nl_list *tmp, *old; + + Syslog('S', "tidy_nllist"); + for (tmp = *fap; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fap = NULL; +} + + + +int in_nllist(struct _nlidx idx, nl_list **fap, int replace) +{ + nl_list *tmp; + + Syslog('S', "Seeking nlidx match for %u:%u/%u.%u", idx.zone, idx.net, idx.node, idx.point); + + for (tmp = *fap; tmp; tmp = tmp->next) + if ((tmp->idx.zone == idx.zone) && (tmp->idx.net == idx.net) && + (tmp->idx.node == idx.node) && (tmp->idx.point == idx.point)) { + Syslog('S', "Match found"); + if (replace) { + tmp->idx = idx; + entries++; + } + regio = tmp->idx.region; + return TRUE; + } + return FALSE; +} + + + +void fill_nllist(struct _nlidx idx, nl_list **fap) +{ + nl_list *tmp; + + Syslog('S', "fill_nllist %u:%u/%u.%u", idx.zone, idx.net, idx.node, idx.point); + tmp = (nl_list *)malloc(sizeof(nl_list)); + tmp->next = *fap; + tmp->idx = idx; + *fap = tmp; + total++; + entries++; +} + + + +char *fullpath(char *fname) +{ + static char path[128]; + + sprintf(path, "%s/%s", CFG.nodelists, fname); + return path; +} + + + +void sort_nllist(nl_list **fap) +{ + nl_list *ta, **vector; + size_t n = 0, i; + + if (*fap == NULL) + return; + + for (ta = *fap; ta; ta = ta->next) + n++; + + vector = (nl_list **)malloc(n * sizeof(nl_list *)); + Syslog('s', "Sorting %d nodelist entries", n); + + i = 0; + for (ta = *fap; ta; ta = ta->next) { + vector[i++] = ta; + Syslog('S', "Before %u:%u/%u.%u", ta->idx.zone, ta->idx.net, ta->idx.node, ta->idx.point); + } + + qsort(vector, n, sizeof(nl_list *), + (int(*)(const void*, const void *))comp_node); + + (*fap) = vector[0]; + i = 1; + + for (ta = *fap; ta; ta = ta->next) { + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + Syslog('S', "After %u:%u/%u.%u", ta->idx.zone, ta->idx.net, ta->idx.node, ta->idx.point); + } + + free(vector); + return; +} + + + +int comp_node(nl_list **fap1, nl_list **fap2) +{ + if ((*fap1)->idx.zone != (*fap2)->idx.zone) + return ((*fap1)->idx.zone - (*fap2)->idx.zone); + else if ((*fap1)->idx.net != (*fap2)->idx.net) + return ((*fap1)->idx.net - (*fap2)->idx.net); + else if ((*fap1)->idx.node != (*fap2)->idx.node) + return ((*fap1)->idx.node - (*fap2)->idx.node); + else + return ((*fap1)->idx.point - (*fap2)->idx.point); +} + + + +int compile(char *nlname, unsigned short zo, unsigned short ne, unsigned short no) +{ + int num, i, rc = 0; + int lineno, boss = FALSE, bossvalid = FALSE; + unsigned short upnet, upnode; + char buf[256], *p, *q; + faddr *tmpa; + FILE *nl; + struct _nlidx ndx; + struct _nlusr udx; + + rc = 0; + if ((nl = fopen(fullpath(nlname), "r")) == NULL) { + WriteError("$Can't open %s", fullpath(nlname)); + return 102; + } + + Syslog('+', "Compiling \"%s\" (%d)", nlname, filenr); + IsDoing("Compile NL %d", filenr +1); + + memset(&ndx, 0, sizeof(ndx)); + ndx.type = NL_NODE; + ndx.fileno = filenr; + upnet = 0; + upnode = 0; + + /* + * If zone is set, it is a overlay segment + */ + if (zo) { + ndx.zone = zo; + ndx.net = ne; + ndx.node = no; + ndx.point = 0; + } + entries = 0; + lineno = 0; + + while (!feof(nl)) { + + ndx.offset = ftell(nl); + lineno++; + if (fgets(buf, sizeof(buf)-1, nl) == NULL) + continue; + + /* + * Next check at and characters + */ + if ((*(buf+strlen(buf) -1) != '\n') && (*(buf + strlen(buf) -1) != '\012')) { + while (fgets(buf, sizeof(buf) -1, nl) && + (*(buf + strlen(buf) -1) != '\n')) /*void*/; + if (strlen(buf) > 1) /* Suppress EOF character */ + Syslog('s', "Nodelist: too long line junked (%d)", lineno); + continue; + } + + if (*(p=buf+strlen(buf) -1) == '\n') + *p-- = '\0'; + if (*p == '\r') + *p = '\0'; + if ((buf[0] == ';') || (buf[0] == '\032') || (buf[0] == '\0')) + continue; + + if (CFG.slow_util && do_quiet) { + if (zo) { + usleep(1); + } else { + if ((lineno % 40) == 0) + usleep(1); + } + } + + if ((p = strchr(buf, ','))) + *p++ = '\0'; + if ((q = strchr(p, ','))) + *q++ = '\0'; + + ndx.type = NL_NONE; + ndx.pflag = 0; + + if (buf[0] == '\0') { + if (boss) + ndx.type = NL_POINT; + else + ndx.type = NL_NODE; + } else + if (strcasecmp(buf,"Boss") == 0) { + ndx.type = NL_POINT; + bossvalid = FALSE; + if ((tmpa=parsefnode(p)) == NULL) { + WriteError("%s(%u): unparsable Boss addr \"%s\"", + nlname,lineno,p); + continue; + } + boss = TRUE; + if (tmpa->zone) + ndx.zone = tmpa->zone; + ndx.net = tmpa->net; + ndx.node = tmpa->node; + ndx.point = 0; + tidy_faddr(tmpa); + Syslog('S', "Boss %u:%u/%u", ndx.zone, ndx.net, ndx.node); + ndx.type = NL_NONE; + + if (in_nllist(ndx, &nll, FALSE)) { + Syslog('S', "Boss exists"); + bossvalid = TRUE; + } + else + Syslog('S', "Boss not found"); + continue; /* no further processing */ + } else { + boss = FALSE; + ndx.type = NL_NONE; + if (!strcasecmp(buf, "Down")) { + ndx.pflag |= NL_DOWN; + ndx.type = NL_NODE; + } + if (!strcasecmp(buf, "Hold")) { + ndx.pflag |= NL_HOLD; + ndx.type = NL_NODE; + } + if (!strcasecmp(buf, "Pvt")) { + ndx.pflag |= NL_PVT; + ndx.type = NL_NODE; + } + + if (!strcasecmp(buf, "Zone")) + ndx.type = NL_ZONE; + if (!strcasecmp(buf, "Region")) + ndx.type = NL_REGION; + if (!strcasecmp(buf, "Host")) + ndx.type = NL_HOST; + if (!strcasecmp(buf, "Hub")) + ndx.type = NL_HUB; + if (!strcasecmp(buf, "Point")) { + ndx.type = NL_POINT; + bossvalid = TRUE; + } + } + + if (ndx.type == NL_NONE) { + for (q = buf; *q; q++) + if (*q < ' ') + *q='.'; + WriteError("%s(%u): unidentified entry \"%s\"", + nlname, lineno, buf); + continue; + } + + Syslog('S',"Got \"%s\" as \"%s\" typ %d", buf, p, ndx.type); + if ((num=atoi(p)) == 0) { + WriteError("%s(%u): bad numeric \"%s\"", + nlname,lineno,p); + continue; + } + + /* + * now update the current address + */ + switch (ndx.type) { + case NL_REGION: ndx.net = num; + ndx.node = 0; + ndx.point = 0; + ndx.upnet = ndx.zone; + ndx.upnode= 0; + ndx.region= num; + upnet = num; + upnode = 0; + break; + case NL_ZONE: ndx.zone = num; + ndx.net = num; + ndx.node = 0; + ndx.point = 0; + ndx.upnet = 0; + ndx.upnode= 0; + ndx.region= 0; + upnet = num; + upnode = 0; + break; + case NL_HOST: ndx.net = num; + ndx.node = 0; + ndx.point = 0; + ndx.upnet = ndx.region; + ndx.upnode= 0; + upnet = num; + upnode = 0; + break; + case NL_HUB: ndx.node = num; + ndx.point = 0; + ndx.upnet = ndx.net; + ndx.upnode= 0; + upnet = ndx.net; + upnode = num; + break; + case NL_NODE: ndx.node = num; + ndx.point = 0; + ndx.upnet = upnet; + ndx.upnode= upnode; + break; + case NL_POINT: ndx.point = num; + ndx.upnet = ndx.net; + ndx.upnode= ndx.node; + if ((!ndx.region) && bossvalid) + ndx.region = regio; + break; + } + if (!do_quiet) { + printf("\rZone %-6uRegion %-6uNet %-6uNode %-6uPoint %-6u", + ndx.zone, ndx.region, ndx.net, ndx.node, ndx.point); + fflush(stdout); + } + + memset(&udx, 0, sizeof(udx)); + udx.record = total; + + /* + * Read nodelist line and extract username. + */ + for (i = 0; i < 3; i++) { + p = q; + if (p == NULL) + continue; + if ((q = strchr(p, ','))) + *q++ = '\0'; + } + if (strlen(p) > 35) + p[35] = '\0'; + sprintf(udx.user, "%s", p); + + /* + * Now search for the baudrate field, 300 means it's + * and ISDN or TCP/IP only node which is a special case. + */ + for (i = 0; i < 2; i++) { + p = q; + if (p == NULL) + continue; + if ((q = strchr(p, ','))) + *q++ = '\0'; + } + if ((strlen(p) == 3) && (!strcmp(p, "300"))) { + if ((strstr(q, (char *)"X75")) || + (strstr(q, (char *)"V110L")) || + (strstr(q, (char *)"V110H")) || + (strstr(q, (char *)"V120L")) || + (strstr(q, (char *)"V120H")) || + (strstr(q, (char *)"ISDN"))) + ndx.pflag |= NL_ISDN; + if ((strstr(q, (char *)"IFC")) || + (strstr(q, (char *)"IBN")) || + (strstr(q, (char *)"ITN")) || + (strstr(q, (char *)"IVM")) || + (strstr(q, (char *)"IFT")) || + (strstr(q, (char *)"IP"))) + ndx.pflag |= NL_TCPIP; + } + + Syslog('S',"put: %u:%u/%u.%u reg %u upl %u/%u typ %u flg %02X as (%u,%lu)", + ndx.zone,ndx.net,ndx.node, + ndx.point,ndx.region,ndx.upnet,ndx.upnode, + ndx.type,ndx.pflag,ndx.fileno,ndx.offset); + + + /* + * If zone, net and node given, then this list is an + * overlay so we will call in_list() to replace the + * existing records, or append them if they don't exist. + * Also, only points with a valid boss will be added. + */ + if (zo) { + if (!(in_nllist(ndx, &nll, TRUE))) { + if (ndx.point && bossvalid) { + fill_nllist(ndx, &nll); + Syslog('S', "Add point %u:%u/%u.%u", ndx.zone, ndx.net, ndx.node, ndx.point); + } + if (!ndx.point) + fill_nllist(ndx, &nll); + } + } else + fill_nllist(ndx, &nll); + } + + Syslog('+', "%d entries", entries); + + if (!do_quiet) { + printf(" %ld entries\n", entries); + fflush(stdout); + } + + return rc; +} + + + +/* + * Tidy the filearray + */ +void tidy_fdlist(fd_list **fdp) +{ + fd_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a file on the array. + */ +void fill_fdlist(fd_list **fdp, char *filename, time_t filedate) +{ + fd_list *tmp; + + tmp = (fd_list *)malloc(sizeof(fd_list)); + tmp->next = *fdp; + sprintf(tmp->fname, "%s", filename); + tmp->fdate = filedate; + *fdp = tmp; +} + + + +int compfdate(fd_list **, fd_list **); + + +/* + * Sort the array of files by filedate + */ +void sort_fdlist(fd_list **fdp) +{ + fd_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) { + return; + } + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (fd_list **)malloc(n * sizeof(fd_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) { + vector[i++] = ta; + } + + qsort(vector, n, sizeof(fd_list*), (int(*)(const void*, const void*))compfdate); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compfdate(fd_list **fdp1, fd_list **fdp2) +{ + return ((*fdp1)->fdate - (*fdp2)->fdate); +} + + + +/* + * Return the name of the oldest file in the array + */ +char *pull_fdlist(fd_list **fdp) +{ + static char buf[65]; + fd_list *ta; + + if (*fdp == NULL) + return NULL; + + ta = *fdp; + memset(&buf, 0, sizeof(buf)); + sprintf(buf, "%s", ta->fname); + + if (ta->next != NULL) + *fdp = ta->next; + else + *fdp = NULL; + + free(ta); + return buf; +} + + + +int makelist(char *base, unsigned short zo, unsigned short ne, unsigned short no) +{ + int rc = 0, files = 0; + struct dirent *de; + DIR *dp; + char *p = NULL, *q; + struct _nlfil fdx; + fd_list *fdl = NULL; + + if (!strlen(base)) { + WriteError("Error, no nodelist defined for %d:%d/%d", zo, ne, no); + return 0; + } + + if ((dp = opendir(CFG.nodelists)) == NULL) { + WriteError("$Can't open dir %s", CFG.nodelists); + rc = 103; + } else { + while ((de = readdir(dp))) + if (strncmp(de->d_name, base, strlen(base)) == 0) { + /* + * Extension must be at least 2 digits + */ + q = (de->d_name) + strlen(base); + if ((*q == '.') && (strlen(q) > 2) && + (strspn(q+1,"0123456789") == (strlen(q)-1))) { + /* + * Add matched filenames to the array + */ + fill_fdlist(&fdl, de->d_name, file_time(fullpath(de->d_name))); + files++; + } + } + closedir(dp); + + if (files == 0) { + Syslog('+', "No nodelist found for %s", base); + return 103; + } + + /* + * Sort found nodelists by age and kill all but the newest 2. + */ + sort_fdlist(&fdl); + while (files) { + p = pull_fdlist(&fdl); + if (files > 2) { + Syslog('+', "Remove old \"%s\"", p); + unlink(fullpath(p)); + } + files--; + } + tidy_fdlist(&fdl); + + memset(&fdx, 0, sizeof(fdx)); + sprintf(fdx.filename, "%s", p); + sprintf(fdx.domain, "%s", fidonet.domain); + fdx.number = filenr; + fwrite(&fdx, sizeof(fdx), 1, ffp); + + rc = compile(p, zo, ne, no); + filenr++; + } + + return rc; +} + + + +int nodebld(void) +{ + int rc = 0, i; + char *im, *fm, *um, *old, *new; + struct _nlfil fdx; + FILE *fp; + nl_list *tmp; + + memset(&fdx, 0, sizeof(fdx)); + im = xstrcpy(fullpath((char *)"temp.index")); + fm = xstrcpy(fullpath((char *)"temp.files")); + um = xstrcpy(fullpath((char *)"temp.users")); + + if ((ifp = fopen(im, "w+")) == NULL) { + WriteError("$Can't create %s",MBSE_SS(im)); + return 101; + } + if ((ufp = fopen(um, "w+")) == NULL) { + WriteError("$Can't create %s", MBSE_SS(um)); + fclose(ifp); + unlink(im); + return 101; + } + if ((ffp = fopen(fm, "w+")) == NULL) { + WriteError("$Can't create %s", MBSE_SS(fm)); + fclose(ifp); + unlink(im); + fclose(ufp); + unlink(um); + return 101; + } + + if (!do_quiet) { + colour(3, 0); + printf("\n"); + } + + if ((fp = fopen(fidonet_fil, "r")) == 0) + rc = 102; + else { + fread(&fidonethdr, sizeof(fidonethdr), 1, fp); + + while (fread(&fidonet, fidonethdr.recsize, 1, fp) == 1) { + if (fidonet.available) { + rc = makelist(fidonet.nodelist, 0, 0, 0); + if (rc) + break; + + for (i = 0; i < 6; i++) { + if (fidonet.seclist[i].zone) { + rc = makelist(fidonet.seclist[i].nodelist, + fidonet.seclist[i].zone, + fidonet.seclist[i].net, + fidonet.seclist[i].node); + if (rc) + break; + } + } + if (rc) + break; + } + } + + fclose(fp); + } + + fclose(ufp); + fclose(ffp); + + if (rc == 0) { + IsDoing("Sorting nodes"); + sort_nllist(&nll); + + IsDoing("Writing files"); + for (tmp = nll; tmp; tmp = tmp->next) + fwrite(&tmp->idx, sizeof(struct _nlidx), 1, ifp); + fclose(ifp); + + Syslog('+', "Compiled %d entries", total); + + /* + * Rename existing files to old.*, they stay on disk in + * case they are open by some program. The temp.* files + * are then renamed to node.* + */ + old = xstrcpy(fullpath((char *)"old.index")); + new = xstrcpy(fullpath((char *)"node.index")); + unlink(old); + rename(new, old); + rename(im, new); + free(old); + free(new); + old = xstrcpy(fullpath((char *)"old.users")); + new = xstrcpy(fullpath((char *)"node.users")); + unlink(old); + rename(new, old); + rename(um, new); + free(old); + free(new); + old = xstrcpy(fullpath((char *)"old.files")); + new = xstrcpy(fullpath((char *)"node.files")); + unlink(old); + rename(new, old); + rename(fm, new); + free(old); + free(new); + } else { + fclose(ifp); + Syslog('+', "Compile failed, rc=%d", rc); + unlink(im); + unlink(fm); + unlink(um); + } + + free(im); + free(fm); + free(um); + tidy_nllist(&nll); + + return rc; +} + + + diff --git a/mbfido/mbindex.h b/mbfido/mbindex.h new file mode 100644 index 00000000..917d30d8 --- /dev/null +++ b/mbfido/mbindex.h @@ -0,0 +1,31 @@ +#ifndef _MBINDEX_H +#define _MBINDEX_H + + +typedef struct _fd_list { + struct _fd_list *next; + char fname[65]; + time_t fdate; +} fd_list; + + +int lockindex(void); +void ulockindex(void); +void Help(void); +void ProgName(void); +void die(int); +char *fullpath(char *); +int compile(char *, unsigned short, unsigned short, unsigned short); +void tidy_fdlist(fd_list **); +void fill_fdlist(fd_list **, char *, time_t); +void sort_fdlist(fd_list **); +char *pull_fdlist(fd_list **); +int makelist(char *, unsigned short, unsigned short, unsigned short); +void tidy_nllist(nl_list **); +int in_nllist(struct _nlidx, nl_list **, int); +void fill_nllist(struct _nlidx, nl_list **); +int comp_node(nl_list **, nl_list **); +int nodebld(void); + +#endif + diff --git a/mbfido/mbmail.c b/mbfido/mbmail.c new file mode 100644 index 00000000..8fe56431 --- /dev/null +++ b/mbfido/mbmail.c @@ -0,0 +1,418 @@ +/***************************************************************************** + * + * File ..................: mbmail/mbmail.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 28-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbftn.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbuser.h" +#include "hash.h" +#include "mkftnhdr.h" +#include "message.h" + + +/* ### Modified by P.Saratxaga on 9 Aug 1995 ### + * - added a line so if fmsg->to->name is greater than MAXNAME (35), + * and "@" or "%" or "!" is in it; then UUCP is used instead. So we can + * send messages to old style fido->email gates (that is, using another + * soft than mbmail ;-) ) with long adresses. + */ + +extern int most_debug; +extern int addrerror; +extern int defaultrfcchar; +extern int defaultftnchar; +extern int do_quiet; /* Quiet flag */ +extern int e_pid; /* Pid of child process */ +extern int show_log; /* Show logging on screen */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +extern int usetmp; +int pgpsigned; +extern char *configname; +extern char passwd[]; +int net_in = 0, net_imp = 0, net_out = 0, net_bad = 0; +int dirtyoutcode = CHRS_NOTSET; + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBMAIL: MBSE BBS %s - Internet Fidonet mail gate\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbmail -r -g ...\n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" -r address to route packet\n"); + printf(" -g [ n | c | h ] \"flavor\" of packet\n"); + printf(" -c force the given charset\n"); + printf(" list of receipient addresses\n"); + colour(7, 0); + ExitClient(0); +} + + + +void die(int onsig) +{ + /* + * First check if there is a child running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeeded", e_pid); + else + WriteError("Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode, reset the tty. + */ + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (!do_quiet) { + show_log = TRUE; + colour(3, 0); + } + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + Syslog('+', "Msgs in [%4d] imp [%4d] out [%4d] bad [%4d]", net_in, net_imp, net_out, net_bad); + + if (net_out) + CreateSema((char *)"scanout"); + + + time(&t_end); + Syslog(' ', "MBMAIL finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) + colour(7, 0); + ExitClient(onsig); +} + + + +int main(int argc, char *argv[]) +{ + char *cmd, *envptr; + struct passwd *pw; + int i, c, rc; + char *routec = NULL; + faddr *route = NULL; + char *p; + char buf[BUFSIZ]; + FILE *fp; + fa_list **envrecip, *envrecip_start = NULL; + int envrecip_count = 0; + rfcmsg *msg=NULL; + ftnmsg *fmsg=NULL; + faddr *taddr; + char cflavor = '\0', flavor; + fa_list *sbl = NULL; + int incode, outcode; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * The next trick is to supply a fake environment variable + * MBSE_ROOT in case we are started from the MTA. + * Some MTA's can't change uid to mbse, so if that's the + * case we will try it ourself. + * This will setup the variable so InitConfig() will work. + * The /etc/passwd must point to the correct homedirectory. + */ + pw = getpwuid(getuid()); + if (getenv("MBSE_ROOT") == NULL) { + pw = getpwuid(getuid()); + if (strcmp(pw->pw_name, "mbse")) { + /* + * We are not running as user mbse. + */ + pw = getpwnam("mbse"); + if (setuid(pw->pw_uid)) { + printf("Fatal error: can't set uid to user mbse\n"); + } + } + envptr = xstrcpy((char *)"MBSE_ROOT="); + envptr = xstrcat(envptr, pw->pw_dir); + putenv(envptr); + } + + do_quiet = TRUE; + InitConfig(); + InitFidonet(); + InitNode(); + InitMsgs(); + InitUser(); + TermInit(1); + time(&t_start); + umask(002); + + /* + * Catch all the signals we can, and ignore the rest. + */ + for(i = 0; i < NSIG; i++) { + + if ((i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || + (i == SIGSEGV) || (i == SIGTERM) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if (argc < 2) + Help(); + + cmd = xstrcpy((char *)"Cmd line: mbmail"); + + while ((c = getopt(argc, argv, "g:r:c:h")) != -1) { + cmd = xstrcat(cmd, (char *)" - "); + cmd[strlen(cmd) -1] = c; + switch (c) { + case 'h': Help(); + case 'g': if (optarg && ((*optarg == 'n') || (*optarg == 'c') || (*optarg == 'h'))) { + cflavor = *optarg; + cmd = xstrcat(cmd, optarg); + } else { + Help(); + } + break; + case 'r': routec = optarg; cmd = xstrcat(cmd, optarg); break; + case 'c': dirtyoutcode = readchrs(optarg); + cmd = xstrcat(cmd, optarg); + if (dirtyoutcode == CHRS_NOTSET) + dirtyoutcode = getcode(optarg); + break; + default: Help(); + } + } + + ProgName(); + InitClient(pw->pw_name, (char *)"mbmail", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBMAIL v%s", VERSION); + most_debug = TRUE; + + if (!diskfree(CFG.freespace)) + die(101); + + + if (cflavor == 'n') + cflavor='o'; + + if ((routec) && ((route=parsefaddr(routec)) == NULL)) + WriteError("unparsable route address \"%s\" (%s)", MBSE_SS(routec),addrerrstr(addrerror)); + + if ((p=strrchr(argv[0],'/'))) + p++; + else + p=argv[0]; + + envrecip = &envrecip_start; + while (argv[optind]) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[optind]); + if ((taddr = parsefaddr(argv[optind++]))) { + (*envrecip)=(fa_list*)malloc(sizeof(fa_list)); + (*envrecip)->next=NULL; + (*envrecip)->addr=taddr; + envrecip=&((*envrecip)->next); + envrecip_count++; + } else + WriteError("unparsable recipient \"%s\" (%s), ignored", argv[optind-1], addrerrstr(addrerror)); + } + Syslog(' ', cmd); + free(cmd); + + if (!envrecip_count) { + WriteError("No valid receipients specified, aborting"); + die(105); + } + + for (envrecip = &envrecip_start; *envrecip; envrecip = &((*envrecip)->next)) + Syslog('+', "envrecip: %s",ascfnode((*envrecip)->addr,0x7f)); + Syslog('+', "route: %s",ascfnode(route,0x1f)); + + umask(066); /* packets may contain confidential information */ + + while (!feof(stdin)) { + usetmp = 0; + tidyrfc(msg); + msg = parsrfc(stdin); + + incode = outcode = CHRS_NOTSET; + pgpsigned = 0; + + p = hdr((char *)"Content-Type",msg); + if (p) + incode = readcharset(p); + if (incode == CHRS_NOTSET) { + p = hdr((char *)"X-FTN-CHRS",msg); + if (p == NULL) + p = hdr((char *)"X-FTN-CHARSET",msg); + if (p == NULL) + p = hdr((char *)"X-FTN-CODEPAGE",msg); + if (p) + incode = readchrs(p); + if ((p = hdr((char *)"Message-ID",msg)) && (chkftnmsgid(p))) + incode = defaultftnchar; + else + incode = defaultrfcchar; + } + if ((p = hdr((char *)"Content-Type",msg)) && ((strcasestr(p, (char *)"multipart/signed")) || + (strcasestr(p,(char *)"application/pgp")))) { + pgpsigned = 1; + outcode = incode; + } else if ((p=hdr((char *)"X-FTN-ORIGCHRS",msg))) + outcode = readchrs(p); + else if (dirtyoutcode != CHRS_NOTSET) + outcode = dirtyoutcode; + else + outcode = getoutcode(incode); + + flavor = cflavor; + + if ((p = hdr((char *)"X-FTN-FLAGS",msg))) { + if (!flavor) { + if (flag_on((char *)"CRS",p)) + flavor = 'c'; + else if (flag_on((char *)"HLD",p)) + flavor = 'h'; + else + flavor = 'o'; + } + if (flag_on((char *)"ATT",p)) + attach(*route, hdr((char *)"Subject",msg), 0, flavor); + if (flag_on((char *)"TFS",p)) + attach(*route, hdr((char *)"Subject",msg), 1, flavor); + if (flag_on((char *)"KFS",p)) + attach(*route, hdr((char *)"Subject",msg), 2, flavor); + } + if ((!flavor) && ((p = hdr((char *)"Priority",msg)) || + (p = hdr((char *)"Precedence",msg)) || (p = hdr((char *)"X-Class",msg)))) { + while (isspace(*p)) + p++; + if ((strncasecmp(p,"fast",4) == 0) || (strncasecmp(p,"high",4) == 0) || + (strncasecmp(p,"crash",5) == 0) || (strncasecmp(p,"airmail",5) == 0) || + (strncasecmp(p,"special-delivery",5) == 0) || (strncasecmp(p,"first-class",5) == 0)) + flavor='c'; + else if ((strncasecmp(p,"slow",4) == 0) || (strncasecmp(p,"low",3) == 0) || + (strncasecmp(p,"hold",4) == 0) || (strncasecmp(p,"news",4) == 0) || + (strncasecmp(p,"bulk",4) == 0) || (strncasecmp(p,"junk",4) == 0)) + flavor='h'; + } + if (!flavor) + flavor='o'; + + if (envrecip_count > 1) { + if ((fp = tmpfile()) == NULL) { + WriteError("$Cannot open temporary file"); + die(102); + } + while (bgets(buf, sizeof(buf)-1, stdin)) + fputs(buf, fp); + rewind(fp); + usetmp = 1; + } else { + fp = stdin; + usetmp = 0; + } + + tidy_ftnmsg(fmsg); + if ((fmsg = mkftnhdr(msg, incode, outcode, FALSE)) == NULL) { + WriteError("Unable to create FTN headers from RFC ones, aborting"); + die(103); + } + + for (envrecip = &envrecip_start; *envrecip; envrecip = &((*envrecip)->next)) { + fmsg->to = (*envrecip)->addr; + if ((!fmsg->to->name) || ((strlen(fmsg->to->name) > MAXNAME) + && ((strstr(fmsg->to->name,"@")) || (strstr(fmsg->to->name,"%")) + || (strstr(fmsg->to->name,"!"))))) + fmsg->to->name = (char *)"UUCP"; + rc = putmessage(msg, fmsg, fp, route, flavor, &sbl, incode, outcode); + if (rc == 1) { + WriteError("Unable to put netmail message into the packet, aborting"); + die(104); + } + if (rc == 2) { + WriteError("Unable to import netmail messages into the messabe base"); + die(105); + } + if (usetmp) + rewind(fp); + fmsg->to = NULL; + } + net_in++; + if (usetmp) + fclose(fp); + } + + closepkt(); + die(0); + return 0; +} + diff --git a/mbfido/mbmail.h b/mbfido/mbmail.h new file mode 100644 index 00000000..c4b0273a --- /dev/null +++ b/mbfido/mbmail.h @@ -0,0 +1,6 @@ +#ifndef _MBMAIL_H +#define _MBMAIL_H + + +#endif + diff --git a/mbfido/mbmsg.c b/mbfido/mbmsg.c new file mode 100644 index 00000000..9d6256f9 --- /dev/null +++ b/mbfido/mbmsg.c @@ -0,0 +1,702 @@ +/***************************************************************************** + * + * File ..................: mbmsg/mbmsg.c + * Purpose ...............: Message Base Maintenance + * Last modification date : 27-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/dbcfg.h" +#include "post.h" +#include "mbmsg.h" + + + +int do_pack = FALSE; /* Pack flag */ +int do_kill = FALSE; /* Kill flag (age and maxmsgs) */ +int do_index = FALSE; /* Index flag */ +int do_link = FALSE; /* Link messages */ +int do_post = FALSE; /* Post a Message */ +extern int do_quiet; /* Quiet flag */ +extern int show_log; /* Show loglines */ +long do_area = 0; /* Do only one area */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +int are_tot = 0; /* Total areas */ +int are_proc = 0; /* Areas processed */ +int msg_tot = 0; /* Total messages */ +int msg_del = 0; /* Deleted messages */ +int msg_link = 0; /* Linked messages */ +int processed = FALSE; /* Did process something */ +int oldmask; + + + + +/* + * Header, only if not quiet + */ +void ProgName() +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBMSG: MBSE BBS %s - Message Base Maintenance Utility\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); + colour(7, 0); +} + + + +int main(int argc, char **argv) +{ + int i; + char *cmd, *too = NULL, *subj = NULL, *mfile = NULL, *flavor = NULL; + struct passwd *pw; + long tarea = 0; + +#ifdef MEMWATCH + mwInit(); +#endif + + InitConfig(); + TermInit(1); + oldmask = umask(007); + time(&t_start); + + /* + * Catch all signals we can, and ignore or catch them + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGBUS) || (i == SIGILL) || + (i == SIGSEGV) || (i == SIGTERM) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if (argc < 2) + Help(); + + cmd = xstrcpy((char *)"Cmd:"); + + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + + if (strncasecmp(argv[i], "i", 1) == 0) + do_index = TRUE; + if (strncasecmp(argv[i], "l", 1) == 0) + do_link = TRUE; + if (strncasecmp(argv[i], "k", 1) == 0) + do_kill = TRUE; + if (strncasecmp(argv[i], "pa", 2) == 0) + do_pack = TRUE; + if (strncasecmp(argv[i], "po", 2) == 0) { + do_post = TRUE; + too = argv[++i]; + cmd = xstrcat(cmd, (char *)" \""); + cmd = xstrcat(cmd, too); + tarea = atoi(argv[++i]); + cmd = xstrcat(cmd, (char *)"\" "); + cmd = xstrcat(cmd, argv[i]); + subj = argv[++i]; + cmd = xstrcat(cmd, (char *)" \""); + cmd = xstrcat(cmd, subj); + mfile = argv[++i]; + cmd = xstrcat(cmd, (char *)"\" "); + cmd = xstrcat(cmd, mfile); + flavor = argv[++i]; + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, flavor); + } + if (strncasecmp(argv[i], "-a", 2) == 0) { + i++; + do_area = atoi(argv[i]); + } + if (strncasecmp(argv[i], "-q", 2) == 0) + do_quiet = TRUE; + } + + if (!(do_index || do_link || do_kill || do_pack || do_post)) + Help(); + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbmsg", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBMSG v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + printf("\n"); + colour(3, 0); + } + + if (do_index || do_link || do_kill || do_pack) { + memset(&MsgBase, 0, sizeof(MsgBase)); + DoMsgBase(); + } + + if (do_post) { + Post(too, tarea, subj, mfile, flavor); + } + + die(0); + return 0; +} + + + +void Help() +{ + do_quiet = FALSE; + ProgName(); + + colour(12, 0); + printf("\n Usage: mbmsg [command(s)] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); +// printf(" i index Create new index files\n"); + printf(" l link Link messages by subject\n"); + printf(" k kill Kill messages (age & count)\n"); + printf(" pa pack Pack deleted messages\n"); + printf(" po post <#> Post file in message area #\n\n"); + colour(9, 0); + printf(" Options are:\n\n"); + colour(3, 0); + printf(" -a -area <#> Process area <#> only\n"); + printf(" -q -quiet Quiet mode\n"); + + printf("\n"); + die(0); +} + + + +void die(int onsig) +{ + signal(onsig, SIG_IGN); + if (!do_quiet) { + printf("\r"); + colour(3, 0); + } + + if (MsgBase.Locked) + Msg_UnLock(); + if (MsgBase.Open) + Msg_Close(); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + if (onsig == SIGSEGV) + Syslog('+', "Last msg area %s", msgs.Name); + + if (are_tot || are_proc || msg_link) + Syslog('+', "Areas [%5d] Processed [%5d] Linked [%5d]", are_tot, are_proc, msg_link); + if (msg_tot || msg_del) + Syslog('+', "Msgs [%5d] Deleted [%5d]", msg_tot, msg_del); + + time(&t_end); + Syslog(' ', "MBMSG finished in %s", t_elapsed(t_start, t_end)); + + umask(oldmask); + if (!do_quiet) { + colour(7, 0); + printf("\r \n"); + } + ExitClient(onsig); +} + + + +void DoMsgBase() +{ + FILE *pAreas; + char *sAreas, *Name; + long arearec; + int Del = 0; + + sAreas = calloc(81, sizeof(char)); + Name = calloc(81, sizeof(char )); + + IsDoing("Msg Maintenance"); + + if (do_area) + Syslog('+', "Processing message area %ld", do_area); + else + Syslog('+', "Processing all message areas"); + + if (do_kill) { + Syslog('-', " Total Max. Days/Killed Max. Age/Killed Area name"); + Syslog('-', "------ ------ ------ ------ ------ ----------------------------------"); + } + + sprintf(sAreas, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if(( pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open Messages Areas File."); + die(SIGILL); + } + fread(&msgshdr, sizeof(msgshdr), 1, pAreas); + + if (do_area) { + if (fseek(pAreas, (msgshdr.recsize + msgshdr.syssize) * (do_area - 1), SEEK_CUR) == 0) { + fread(&msgs, msgshdr.recsize, 1, pAreas); + if (msgs.Active) { + + if (!diskfree(CFG.freespace)) + die(101); + + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", do_area, msgs.Name); + fflush(stdout); + } + are_tot++; + if (do_kill) + KillArea(msgs.Base, msgs.Name, msgs.DaysOld, msgs.MaxMsgs); + if (do_pack || msg_del) + PackArea(msgs.Base); + if (do_index) + IndexArea(msgs.Base); + if (do_link) + LinkArea(msgs.Base); + if (processed) + are_proc++; + } + } + } else { + arearec = 0; + while (fread(&msgs, msgshdr.recsize, 1, pAreas) == 1) { + fseek(pAreas, msgshdr.syssize, SEEK_CUR); + arearec++; + if (msgs.Active) { + + if (!diskfree(CFG.freespace)) + die(101); + + Nopper(); + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", arearec, msgs.Name); + fflush(stdout); + } + are_tot++; + processed = FALSE; + if (do_kill) + KillArea(msgs.Base, msgs.Name, msgs.DaysOld, msgs.MaxMsgs); + if (do_pack || (Del != msg_del)) { + PackArea(msgs.Base); + } + Del = msg_del; + if (do_index) + IndexArea(msgs.Base); + if (do_link) + LinkArea(msgs.Base); + if (processed) + are_proc++; + } + } + } + fclose(pAreas); + + if (!do_area) { + sprintf(sAreas, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open Messages Areas File."); + die(SIGILL); + } + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pAreas); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, pAreas) == 1) { + if (usrconfig.Email && strlen(usrconfig.Name)) { + Nopper(); + sprintf(Name, "User %s email area: mailbox", usrconfig.Name); + if (!do_quiet) { + colour(3, 0); + printf("\r .. %-40s", Name); + fflush(stdout); + } + sprintf(sAreas, "%s/%s/mailbox", CFG.bbs_usersdir, usrconfig.Name); + are_tot++; + processed = FALSE; + if (do_kill) + KillArea(sAreas, Name, 0, CFG.defmsgs); + if (do_pack || (Del != msg_del)) { + PackArea(sAreas); + } + Del = msg_del; + if (do_index) + IndexArea(sAreas); + if (do_link) + LinkArea(sAreas); + if (processed) + are_proc++; + sprintf(sAreas, "%s/%s/archive", CFG.bbs_usersdir, usrconfig.Name); + sprintf(Name, "User %s email area: archive", usrconfig.Name); + are_tot++; + processed = FALSE; + if (do_kill) + KillArea(sAreas, Name, 0, CFG.defmsgs); + if (do_pack || (Del != msg_del)) + PackArea(sAreas); + Del = msg_del; + if (do_index) + IndexArea(sAreas); + if (do_link) + LinkArea(sAreas); + if (processed) + are_proc++; + sprintf(sAreas, "%s/%s/trash", CFG.bbs_usersdir, usrconfig.Name); + sprintf(Name, "User %s email area: trash", usrconfig.Name); + are_tot++; + processed = FALSE; + if (do_kill) + KillArea(sAreas, Name, CFG.defdays, CFG.defmsgs); + if (do_pack || (Del != msg_del)) + PackArea(sAreas); + Del = msg_del; + if (do_index) + IndexArea(sAreas); + if (do_link) + LinkArea(sAreas); + if (processed) + are_proc++; + + } + } + + fclose(pAreas); + } + + if (do_link) + RemoveSema((char *)"msglink"); + + free(sAreas); + free(Name); + die(0); +} + + + +typedef struct { + unsigned long Subject; + unsigned long Number; +} MSGLINK; + + + +void LinkArea(char *Path) +{ + int i, m; + unsigned long Number, Prev, Next, Crc, Total; + char Temp[128], *p; + MSGLINK *Link; + + IsDoing("Linking"); + + if (Msg_Open(Path)) { + if (!do_quiet) { + colour(12, 0); + printf(" (linking)"); + colour(13, 0); + fflush(stdout); + } + + if ((Total = Msg_Number()) != 0L) { + if (Msg_Lock(30L)) { + if ((Link = (MSGLINK *)malloc(Total * sizeof(MSGLINK))) != NULL) { + memset(Link, 0, Total * sizeof(MSGLINK)); + Number = Msg_Lowest(); + i = 0; + do { + Msg_ReadHeader(Number); + strcpy(Temp, Msg.Subject); + p = strupr(Temp); + if (!strncmp(p, "RE:", 3)) { + p += 3; + if (*p == ' ') + p++; + } + Link[i].Subject = StringCRC32(p); + Link[i].Number = Number; + i++; + + if (CFG.slow_util && do_quiet && ((i % 5) == 0)) + usleep(1); + + if (((i % 10) == 0) && (!do_quiet)) { + printf("%6d / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total); + fflush(stdout); + } + } while(Msg_Next(&Number) == TRUE); + + if (!do_quiet) { + printf("%6d / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total); + fflush(stdout); + } + + Number = Msg_Lowest(); + i = 0; + do { + Msg_ReadHeader(Number); + Prev = Next = 0; + Crc = Link[i].Subject; + + for (m = 0; m < Total; m++) { + if (m == i) + continue; + if (Link[m].Subject == Crc) { + if (m < i) + Prev = Link[m].Number; + else if (m > i) { + Next = Link[m].Number; + break; + } + } + } + + if (CFG.slow_util && do_quiet && ((i % 5) == 0)) + usleep(1); + + if (((i % 10) == 0) && (!do_quiet)) { + printf("%6d / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total); + fflush(stdout); + } + + if (Msg.Original != Prev || Msg.Reply != Next) { + Msg.Original = Prev; + Msg.Reply = Next; + Msg_WriteHeader(Number); + processed = TRUE; + msg_link++; + } + + i++; + } while(Msg_Next(&Number) == TRUE); + + if (!do_quiet) { + printf("%6d / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total); + fflush(stdout); + } + + free(Link); + } + + if (!do_quiet) { + printf(" \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + Msg_UnLock(); + } else { + Syslog('+', "Can't lock %s", Path); + } + } + + Msg_Close(); + + if (!do_quiet) { + printf("\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + } +} + + + +/* + * Kill messages according to age and max messages. + */ +void KillArea(char *Path, char *Name, int DaysOld, int MaxMsgs) +{ + unsigned long Number, TotalMsgs = 0, Highest, *Active, Counter = 0; + int i, DelCount = 0, DelAge = 0, Done; + time_t Today, MsgDate; + + IsDoing("Killing"); + Today = time(NULL) / 86400L; + + if (Msg_Open(Path)) { + + if (!do_quiet) { + colour(12, 0); + printf(" (Killing)"); + colour(13, 0); + fflush(stdout); + } + + if (Msg_Lock(30L)) { + + TotalMsgs = Msg_Number(); + + if (TotalMsgs) { + if ((Active = (unsigned long *)malloc((size_t)((TotalMsgs + 100L) * sizeof(unsigned long)))) != NULL) { + i = 0; + Number = Msg_Lowest(); + do { + Active[i++] = Number; + } while (Msg_Next(&Number) == TRUE); + } + } else + Active = NULL; + + Number = Msg_Lowest(); + Highest = Msg_Highest(); + + do { + if (CFG.slow_util && do_quiet) + usleep(1); + + if ((!do_quiet) && ((Counter % 10L) == 0)) { + printf("%6lu / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", Counter, TotalMsgs); + fflush(stdout); + } + if ((Counter % 10L) == 0) + DoNop(); + + Counter++; + msg_tot++; + + if (Msg_ReadHeader(Number) == TRUE) { + Done = FALSE; + if (DaysOld) { + /* + * GoldED doesn't fill the Msg.Arrived field, use the + * written date instead. + */ + if (Msg.Arrived == 0L) + MsgDate = Msg.Written / 86400L; + else + MsgDate = Msg.Arrived / 86400L; + + if ((Today - MsgDate) > DaysOld) { + Msg_Delete(Number); + Done = TRUE; + DelAge++; + msg_del++; + if (Active != NULL) { + for (i = 0; i < TotalMsgs; i++) { + if (Active[i] == Number) + Active[i] = 0L; + } + } + } + } + + if (Done == FALSE && (MaxMsgs) && Msg_Number() > MaxMsgs) { + Msg_Delete(Number); + DelCount++; + msg_del++; + if (Active != NULL) { + for (i = 0; i < TotalMsgs; i++) { + if (Active[i] == Number) + Active[i] = 0L; + } + } + } + } + } while (Msg_Next(&Number) == TRUE); + + if (Active != NULL) + free(Active); + Msg_UnLock(); + } else { + Syslog('+', "Can't lock msgbase %s", Path); + } + + if (!do_quiet) { + printf(" \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + + Msg_Close(); + Syslog('-', "%6d %6d %6d %6d %6d %s", TotalMsgs, DaysOld, DelAge, MaxMsgs, DelCount, Name); + + if (!do_quiet) { + printf("\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + } else + Syslog('+', "Failed to open %s", Path); +} + + + +void IndexArea(char *Path) +{ +} + + + +/* + * Pack message area if there are deleted messages. + */ +void PackArea(char *Path) +{ + IsDoing("Packing"); + if (Msg_Open(Path)) { + + if (!do_quiet) { + colour(12, 0); + printf(" (Packing)"); + fflush(stdout); + } + + if (Msg_Lock(30L)) { + Msg_Pack(); + Msg_UnLock(); + } else + Syslog('+', "Can't lock %s", Path); + + Msg_Close(); + + if (!do_quiet) { + printf("\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + } + + if (CFG.slow_util && do_quiet) + usleep(1); +} + + diff --git a/mbfido/mbmsg.h b/mbfido/mbmsg.h new file mode 100644 index 00000000..45f12989 --- /dev/null +++ b/mbfido/mbmsg.h @@ -0,0 +1,14 @@ +#ifndef _MBMSG_H +#define _MBMSG_H + +void ProgName(void); +void Help(void); +void die(int); +void DoMsgBase(void); +void PackArea(char *); +void LinkArea(char *); +void IndexArea(char *); +void KillArea(char *, char *, int, int); + +#endif + diff --git a/mbfido/mbseq.c b/mbfido/mbseq.c new file mode 100644 index 00000000..d3cbe0ba --- /dev/null +++ b/mbfido/mbseq.c @@ -0,0 +1,72 @@ +/***************************************************************************** + * + * File ..................: mbfido/mbseq.c + * Purpose ...............: give a hexadecimal sequence to stdout + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbseq.h" + + + +int main(int argc, char **argv) +{ + struct passwd *pw; + unsigned long seq; + +#ifdef MEMWATCH + mwInit(); +#endif + + InitConfig(); + + pw = getpwuid(getuid()); + + InitClient(pw->pw_name, (char *)"mbseq", CFG.location, + CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBSEQ v%s", VERSION); + + seq = sequencer(); + Syslog('+', "Sequence string %08lx", seq); + printf("%08lx", seq); + fflush(stdout); + + Syslog(' ', "MBSEQ finished"); + ExitClient(0); + return 0; +} + + + diff --git a/mbfido/mbseq.h b/mbfido/mbseq.h new file mode 100644 index 00000000..4b1ccc43 --- /dev/null +++ b/mbfido/mbseq.h @@ -0,0 +1,6 @@ +#ifndef _MBSEQ_H +#define _MBSEQ_H + + +#endif + diff --git a/mbfido/message.c b/mbfido/message.c new file mode 100644 index 00000000..7c8e4123 --- /dev/null +++ b/mbfido/message.c @@ -0,0 +1,882 @@ +/***************************************************************************** + * + * File ..................: mbmail/message.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 02-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbuser.h" + + +/* ### Modified by P.Saratxaga on 7 Aug 1995 ### + * - Newsgroups: line is now gated if there is more than one newsgroup + * - Added support for X-FTN-To and X-FTN-From generated by other gates + * - modified removemime to kludgerise lines if charset != us-ascii + * - creation of ^aACUPDATE kludges from Supersedes: and cancel's + * - added charset support (see Changelog for details) + * - added recognition of X-Fsc- + * - added support to dequote MIME quoted printable messages. Code by T.Tanaka + * - added removemsgid and removeinreply + */ +#include "bread.h" +#include "bwrite.h" +#include "hash.h" +#include "mkftnhdr.h" +#include "tracker.h" +#include "viadate.h" +#include "importnet.h" + + +#define MAXHDRSIZE 2048 +#define MAXSEEN 70 +#define MAXPATH 73 + + +extern time_t now; +extern char *replyaddr; +extern faddr *bestaka; +extern int pgpsigned; +extern int net_bad; +extern int net_out; +extern char *ftnmsgidstyle; + + +char *subj; +char *localdomain=NULL; +static int removemime; +static int removeorg; +static int removemsgid; +static int removeref; +static int removeinreply; +static int removesupersedes; +static int removeapproved; +static int removefrom; +static int removereplyto; +static int removereturnto; +static int ftnorigin; + + +void StatAdd(statcnt *S, unsigned long V) +{ + S->total += V; + S->tweek += V; + S->tdow[Diw] += V; + S->month[Miy] += V; +} + + +int needputrfc(rfcmsg *msg) +{ + faddr *ta; + + /* 0-junk, 1-kludge, 2-pass */ + + if (!strcasecmp(msg->key,"X-UUCP-From")) + return 0; + if (!strcasecmp(msg->key,"X-Body-Start")) + return 0; + if (!strncasecmp(msg->key,".",1)) + return 0; + if (!strncasecmp(msg->key,"X-FTN-",6)) + return 0; + if (!strncasecmp(msg->key,"X-Fsc-",6)) + return 0; + if (!strncasecmp(msg->key,"X-ZC-",5)) + return 0; + if (!strcasecmp(msg->key,"X-Gateway")) + return 0; + if (!strcasecmp(msg->key,"Path")) + return 0; + if (!strcasecmp(msg->key,"Newsgroups")) { + if ((hdr((char *)"X-Origin-Newsgroups",msg))) + return 0; + else + return 1; + } + if (!strcasecmp(msg->key,"X-Origin-Newsgroups")) { + return 1; + } + if (!strcasecmp(msg->key,"Control")) { + if (CFG.allowcontrol) { + if (strstr(msg->val,"cancel")) + return 1; + else + return 0; + } else + return 0; + } + if (!strcasecmp(msg->key,"Return-Path")) + return 1; + if (!strcasecmp(msg->key,"Xref")) + return 0; + if (!strcasecmp(msg->key,"Approved")) + return removeapproved ?0:2; + if (!strcasecmp(msg->key,"X-URL")) + return 0; + if (!strcasecmp(msg->key,"Return-Receipt-To")) + return removereturnto ?0:1; + if (!strcasecmp(msg->key,"Notice-Requested-Upon-Delivery-To")) + return 0; + if (!strcasecmp(msg->key,"Received")) { + return ftnorigin ?0:1; + } + if (!strcasecmp(msg->key,"From")) { + if ((ta=parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else + return removefrom ?0:2; + } + if (!strcasecmp(msg->key,"To")) { + if ((ta=parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else + return 2; + } + if (!strcasecmp(msg->key,"Cc")) + return 2; + if (!strcasecmp(msg->key,"Bcc")) + return 0; + if (!strcasecmp(msg->key,"Reply-To")) { + if ((ta=parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else + return removereplyto ?0:2; + } + if (!strcasecmp(msg->key,"Lines")) + return 0; + if (!strcasecmp(msg->key,"Date")) + return 0; + if (!strcasecmp(msg->key,"Subject")) { + if ((msg->val) && (strlen(msg->val) > MAXSUBJ)) + return 2; + else + return 0; + } + if (!strcasecmp(msg->key,"Organization")) + return removeorg ?0:1; + if (!strcasecmp(msg->key,"Comment-To")) + return 0; + if (!strcasecmp(msg->key,"X-Comment-To")) + return 0; + if (!strcasecmp(msg->key,"X-Apparently-To")) + return 0; + if (!strcasecmp(msg->key,"Apparently-To")) + return 0; + if (!strcasecmp(msg->key,"X-Fidonet-Comment-To")) + return 0; + if (!strcasecmp(msg->key,"Keywords")) + return 2; + if (!strcasecmp(msg->key,"Summary")) + return 2; + if (!strcasecmp(msg->key,"MIME-Version")) + return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Type")) + return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Length")) + return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Transfer-Encoding")) + return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Name")) + return 2; + if (!strcasecmp(msg->key,"Content-Description")) + return 2; + if (!strcasecmp(msg->key,"Message-ID")) + return removemsgid ?0:1; + if (!strcasecmp(msg->key,"References")) + return removeref ?0:1; + if (!strcasecmp(msg->key,"In-Reply-To")) + return removeinreply ?0:1; + if (!strcasecmp(msg->key,"Supersedes")) + return removesupersedes ?0:1; + if (!strcasecmp(msg->key,"Distribution")) + return 0; + if (!strcasecmp(msg->key,"X-Newsreader")) + return 0; + if (!strcasecmp(msg->key,"X-Mailer")) + return 0; + if (!strcasecmp(msg->key,"User-Agent")) + return 0; + if (!strncasecmp(msg->key,"NNTP-",5)) + return 0; + if (!strncasecmp(msg->key,"X-Trace",7)) + return 0; + if (!strncasecmp(msg->key,"X-Complaints",12)) + return 0; + if (!strncasecmp(msg->key,"X-MSMail",9)) + return 0; + if (!strncasecmp(msg->key,"X-MimeOLE",9)) + return 0; + if (!strncasecmp(msg->key,"X-MIME-Autoconverted",20)) + return 0; + if (!strcasecmp(msg->key,"X-Origin-Date")) + return 0; + if (!strncasecmp(msg->key,"X-PGP-",6)) + return 0; + if (!strncasecmp(msg->key,"Resent-",7)) + return 0; + if (!strcasecmp(msg->key,"X-Mailing-List")) + return 0; + if (!strcasecmp(msg->key,"X-Loop")) + return 0; + if (!strcasecmp(msg->key,"Precedence")) + return 0; + /*if (!strcasecmp(msg->key,"")) return ;*/ + return 1; +} + + + +int putmessage(rfcmsg *msg, ftnmsg *fmsg, FILE *fp, faddr *route, char flavor,fa_list **sbl, int incode, int outcode) +{ + char buf[BUFSIZ],*p,*q,newsubj[4 * (MAXSUBJ+1)],*oldsubj; + rfcmsg *tmp; + int rfcheaders, postlocal; + int needsplit,hdrsize,datasize,splitpart,forbidsplit; + int sot_kludge, eot_kludge; + int qp_or_base64; /* 0=plain text, 1=quoted-printable, 2=base64 */ + int html_message; + int tinyorigin=0; + fa_list *ptl=NULL; + faddr *ta; + int i; + FILE *pkt; + fidoaddr Dest, Route, *dest; + time_t Now; + + Syslog('m', "putmessage from %s",ascfnode(fmsg->from,0x7f)); + Syslog('m', "putmessage to %s",ascfnode(fmsg->to,0x7f)); + Syslog('m', "putmessage subj %s",MBSE_SS(fmsg->subj)); + Syslog('m', "putmessage flags %04x",fmsg->flags); + Syslog('m', "putmessage msgid %s %lx",MBSE_SS(fmsg->msgid_a),fmsg->msgid_n); + Syslog('m', "putmessage reply %s %lx",MBSE_SS(fmsg->reply_a),fmsg->reply_n); + Syslog('m', "putmessage date %s",ftndate(fmsg->date)); + + removemime = FALSE; + removeorg = FALSE; + removemsgid = FALSE; + removeref = FALSE; + removeinreply = FALSE; + removesupersedes = FALSE; + removeapproved = FALSE; + removefrom = TRUE; + removereplyto = TRUE; + removereturnto = TRUE; + ftnorigin=fmsg->ftnorigin; + sot_kludge = 0; + eot_kludge = 0; + qp_or_base64 = 0; + html_message = 0; + + if ((hdr((char *)"X-PGP-Signed",msg))) + pgpsigned = TRUE; + Syslog('m', "pgpsigned = %s", pgpsigned ? "True":"False"); + + q = hdr((char *)"Content-Transfer-Encoding",msg); + if (q) + while (*q && isspace(*q)) + q++; + if (!(q)) + q = (char *)"8bit"; + if ((p = hdr((char *)"Content-Type",msg))) { + while (*p && isspace(*p)) + p++; + + /* + * turn the quoted-printable decode mode on; remember FTN is virtually 8-bit clean + */ + if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "quoted-printable", 16) == 0)) + qp_or_base64 = 1; + /* + * turn the base64 decode mode on + */ + else if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "base64", 6) == 0)) + qp_or_base64 = 2; + + /* + * text/html support from FSC-HTML 001 proposal of Odinn Sorensen (2:236/77) + */ + if (strncasecmp(p, "text/html", 9) == 0) + html_message = TRUE; + for (tmp=msg;tmp;tmp=tmp->next) + if (((strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0) && (strcasecmp(tmp->val,"FSCHTML") == 0)) || + (strcasecmp(tmp->key,"X-FTN-HTML") == 0)) + html_message = FALSE; + + if ((readcharset(p) != CHRS_NOTSET ) && ((q == NULL) || (strncasecmp(q,"7bit",4) == 0) || + ((!pgpsigned) && (qp_or_base64==1)) || ((!pgpsigned) && (qp_or_base64==2)) || (strncasecmp(q,"8bit",4) == 0))) + removemime = TRUE; /* no need in MIME headers */ + + /* + * some old MUA puts "text" instead of "text/plain; charset=..." + */ + else if ((strcasecmp(p,"text\n") == 0)) + removemime = TRUE; + + } + Syslog('m', "removemime=%s, qp_or_base64 = %d, html_message=%s", removemime ? "True":"False", qp_or_base64, + html_message ? "True":"False"); + + if ((p = hdr((char *)"Message-ID",msg))) { + if (!removemsgid) + removemsgid = chkftnmsgid(p); + } + Syslog('m', "removemsgid = %s", removemsgid ? "True":"False"); + + if ((p = hdr((char *)"In-Reply-To",msg))) { + p = xstrcpy(p); + q = strtok(p," \t\n"); + if ((q) && (strtok(NULL," \t\n") == NULL)) + removeinreply = chkftnmsgid(q); + free(p); + } + Syslog('m', "removeinreply = %s", removeinreply ? "True":"False"); + + if ((p = hdr((char *)"Reply-To",msg))) { + removereplyto = FALSE; + if ((!removereplyto) && (q = hdr((char *)"From",msg))) { + char *r; + r = xstrcpy(p); + p = r; + while(*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereplyto = TRUE; + free(r); + } + } + Syslog('m', "removereplyto = %s", removereplyto ? "True":"False"); + + if ((p = hdr((char *)"Return-Receipt-To",msg))) { + removereturnto = FALSE; + if ((!removereturnto) && (q=hdr((char *)"From",msg))) { + char *r; + r = xstrcpy(p); p = r; + while(*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereturnto = TRUE; +// free(r); + } + } + Syslog('m', "removereturnto = %s", removereturnto ? "True":"False"); + + p = ascfnode(fmsg->from,0x1f); + i = 79-11-3-strlen(p); + if (ftnorigin && fmsg->origin && (strlen(fmsg->origin) > i)) { + /* This is a kludge... I don't like it too much. But well, + if this is a message of FTN origin, the original origin (:) + line MUST have been short enough to fit in 79 chars... + So we give it a try. Probably it would be better to keep + the information about the address format from the origin + line in a special X-FTN-... header, but this seems even + less elegant. Any _good_ ideas, anyone? */ + + /* OK, I am keeping this, though if should never be used + al long as X-FTN-Origin is used now */ + + p = ascfnode(fmsg->from,0x0f); + i = 79-11-3-strlen(p); + tinyorigin = TRUE; + } + Syslog('m', "tinyorigin = %s", tinyorigin ? "True":"False"); + + if ((fmsg->origin) && (strlen(fmsg->origin) > i)) + fmsg->origin[i]='\0'; + forbidsplit=(ftnorigin || (hdr((char *)"X-FTN-Split",msg))); + needsplit = 0; + splitpart = 0; + hdrsize = 20; + hdrsize += (fmsg->subj)?strlen(fmsg->subj):0; + if (fmsg->from) + hdrsize += (fmsg->from->name)?strlen(fmsg->from->name):0; + if (fmsg->to) + hdrsize += (fmsg->to->name)?strlen(fmsg->to->name):0; + do { + Syslog('m', "split loop, splitpart = %d", splitpart); + datasize=0; + + if (splitpart) { + sprintf(newsubj,"[part %d] ",splitpart+1); + strncat(newsubj,fmsg->subj,MAXSUBJ-strlen(newsubj)); + } else { + strncpy(newsubj,fmsg->subj,MAXSUBJ); + } + strcpy(newsubj, hdrnconv(newsubj, incode, outcode, MAXSUBJ)); + newsubj[MAXSUBJ]='\0'; + + if (splitpart) { + hash_update_n(&fmsg->msgid_n,splitpart); + } + + oldsubj=fmsg->subj; + fmsg->subj=newsubj; + + /* + * We got the routing address from the mailer which was given by our Host's sendmail. + * This is probably our address so we need to get the address for the next hop. + */ + dest = faddr2fido(fmsg->to); + memcpy(&Dest, dest, sizeof(fidoaddr)); + free(dest); + if (TrackMail(Dest, &Route) == R_LOCAL) { + /* + * Mail for our local system. Instead of adding the message to a .pkt create + * a temporary file which later will be send via the importnet function. + */ + postlocal = TRUE; + pkt = tmpfile(); + } else { + /* + * New outbound route. + */ + route = fido2faddr(Route); + postlocal = FALSE; + if ((pkt = ftnmsghdr(fmsg, NULL, route, flavor, (char *)"MBSE-FIDO")) == NULL) { + return 1; + } + } + fmsg->subj=oldsubj; + + Syslog('m', "replyaddr=%s removereplyto=%s removefrom=%s", + printable(replyaddr, 0), removereplyto?"True":"False", removefrom?"True":"False"); + + /* + * Add FTN MSGID: and REPLY: if needed. + */ + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + if (postlocal) { + fprintf(pkt, "\001MSGID: %s %08lx\n", MBSE_SS(fmsg->msgid_a),fmsg->msgid_n); + if (fmsg->reply_s) + fprintf(pkt, "\1REPLY: %s\n", fmsg->reply_s); + else if (fmsg->reply_a) + fprintf(pkt, "\1REPLY: %s %08lx\n", fmsg->reply_a, fmsg->reply_n); + fprintf(pkt, "\001TZUTC: %s\n", gmtoffset(Now)); + } else { + fprintf(pkt, "\001MSGID: %s %08lx\r", MBSE_SS(fmsg->msgid_a),fmsg->msgid_n); + if (fmsg->reply_s) + fprintf(pkt, "\1REPLY: %s\r", fmsg->reply_s); + else if (fmsg->reply_a) + fprintf(pkt, "\1REPLY: %s %08lx\r", fmsg->reply_a, fmsg->reply_n); + fprintf(pkt, "\001TZUTC: %s\r", gmtoffset(Now)); + } + + if ((p=hdr((char *)"X-FTN-REPLYADDR",msg))) { + hdrsize += 10+strlen(p); + fprintf(pkt,"\1REPLYADDR:"); + kwrite(p,pkt,postlocal); + } else if ((replyaddr) && ((!removereplyto) || (!removefrom))) { + hdrsize += 10+strlen(replyaddr); + fprintf(pkt,"\1REPLYADDR: "); + kwrite(replyaddr,pkt,postlocal); + } + + if ((p=hdr((char *)"X-FTN-REPLYTO",msg))) { + hdrsize += 8+strlen(p); + fprintf(pkt,"\1REPLYTO:"); + kwrite(p,pkt,postlocal); + } else if ((replyaddr) && ((!removereplyto) || (!removefrom))) { + hdrsize += 15; + if (postlocal) + fprintf(pkt,"\1REPLYTO: %s UUCP\n", ascfnode(bestaka,0x1f)); + else + fprintf(pkt,"\1REPLYTO: %s UUCP\r", ascfnode(bestaka,0x1f)); + } else if ((p=hdr((char *)"Reply-To",msg))) { + if ((ta=parsefaddr(p))) { + if ((q=hdr((char *)"From",msg))) { + if (!strcasestr(q,p)) { + if (postlocal) + fprintf(pkt,"\1REPLYTO: %s %s\n", ascfnode(ta,0x1f), ta->name); + else + fprintf(pkt,"\1REPLYTO: %s %s\r", ascfnode(ta,0x1f), ta->name); + } + tidy_faddr(ta); + } + } + /* Added 15-Apr-2001 MB. Add UUCP reply info if there is nothing. */ + } else if ((p=hdr((char *)"X-UUCP-From",msg)) && (q=hdr((char *)"From",msg))) { + hdrsize += 15; + Striplf(q); + if (postlocal) { + fprintf(pkt,"\1REPLYADDR: %s\n", q); + fprintf(pkt,"\1REPLYTO: %s UUCP\n", ascfnode(bestaka,0x1f)); + } else { + fprintf(pkt,"\1REPLYADDR: %s\r", q); + fprintf(pkt,"\1REPLYTO: %s UUCP\r", ascfnode(bestaka,0x1f)); + } + } + + if ((p=strip_flags(hdr((char *)"X-FTN-FLAGS",msg)))) { + hdrsize += 15; + if (postlocal) + fprintf(pkt,"\1FLAGS:%s\n",p); + else + fprintf(pkt,"\1FLAGS:%s\r",p); + free(p); + } + + if (!hdr((char *)"X-FTN-PID", msg)) { + p = hdr((char *)"User-Agent", msg); + if (p == NULL) + p = hdr((char *)"X-Newsreader", msg); + if (p == NULL) + p = hdr((char *)"X-Mailer", msg); + if (p) { + hdrsize += 4 + strlen(p); + fprintf(pkt, "\1PID:"); + kwrite(p, pkt, postlocal); + } else { + if (postlocal) + fprintf(pkt, "\001PID: MBSE-MAIL %s\n", VERSION); + else + fprintf(pkt, "\001PID: MBSE-MAIL %s\r", VERSION); + } + } + + hdrsize += 15; + if (postlocal) + writechrs(outcode,pkt,3); + else + writechrs(outcode,pkt,1); + + if (html_message) { + hdrsize += 9; + if (postlocal) + fprintf(pkt, "\1HTML: 5\n"); + else + fprintf(pkt, "\1HTML: 5\r"); + } + +#ifdef FSC_0070 + /* FSC-0070 */ + if ((p = hdr((char *)"Message-ID", msg)) && !(hdr((char *)"X-FTN-RFCID", msg))) { + q = strdup(p); + fprintf(pkt,"\1RFCID:"); + if ((l = strrchr(q, '<')) && (r = strchr(q, '>')) && (l < r)) { + *l++ = ' '; + while(*l && isspace(*l)) + l++; + l--; /* leading ' ' */ + *r-- = '\0'; + while(*r && isspace(*r)) + *r-- = '\0'; + } else + l = q; + kwrite(l, pkt, postlocal); + hdrsize += 6 + strlen(l); + free(q); + } +#endif /* FSC_0070 */ + + if (!(hdr((char *)"X-FTN-Tearline", msg)) && !(hdr((char *)"X-FTN-TID", msg))) { + sprintf(buf, " mbmail %s", VERSION); + hdrsize += 4 + strlen(buf); + fprintf(pkt, "\1TID:"); + kwrite(buf, pkt, postlocal); + } + + if ((splitpart == 0) || (hdrsize < MAXHDRSIZE)) { + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,"X-Fsc-",6)) || + (!strncmp(tmp->key,"X-FTN-",6) && + strcasecmp(tmp->key,"X-FTN-Tearline") && + strcasecmp(tmp->key,"X-FTN-Origin") && + strcasecmp(tmp->key,"X-FTN-Sender") && + strcasecmp(tmp->key,"X-FTN-Split") && + strcasecmp(tmp->key,"X-FTN-FLAGS") && + strcasecmp(tmp->key,"X-FTN-AREA") && + strcasecmp(tmp->key,"X-FTN-MSGID") && + strcasecmp(tmp->key,"X-FTN-REPLY") && + strcasecmp(tmp->key,"X-FTN-SEEN-BY") && + strcasecmp(tmp->key,"X-FTN-PATH") && + strcasecmp(tmp->key,"X-FTN-REPLYADDR") && + strcasecmp(tmp->key,"X-FTN-REPLYTO") && + strcasecmp(tmp->key,"X-FTN-To") && + strcasecmp(tmp->key,"X-FTN-From") && + strcasecmp(tmp->key,"X-FTN-CHARSET") && + strcasecmp(tmp->key,"X-FTN-CHRS") && + strcasecmp(tmp->key,"X-FTN-CODEPAGE") && + strcasecmp(tmp->key,"X-FTN-ORIGCHRS") && + strcasecmp(tmp->key,"X-FTN-SOT") && + strcasecmp(tmp->key,"X-FTN-EOT") && + strcasecmp(tmp->key,"X-FTN-Via"))) { + if (strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0) { + if (!strcasecmp(tmp->val," SOT:\n")) + sot_kludge = 1; + else if (!strcasecmp(tmp->val," EOT:\n")) + eot_kludge = 1; + else { + hdrsize += strlen(tmp->val); + fprintf(pkt,"\1"); + /* we should have restored the original string here... */ + kwrite((tmp->val)+1, pkt, postlocal); + } + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"\1%s:",tmp->key+6); + kwrite(tmp->val, pkt, postlocal); + } + } + /* ZConnect are X-ZC-*: in usenet, \1ZC-*: in FTN */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,"X-ZC-",5))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt, "\1%s:", tmp->key+2); + kwrite(tmp->val, pkt, postlocal); + } + /* mondo.org gateway uses ".MSGID: ..." in usenet */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,".",1)) && (strcasecmp(tmp->key,".MSGID"))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"\1%s:",tmp->key+1); + kwrite(tmp->val, pkt, postlocal); + } + + rfcheaders = 0; + for (tmp=msg;tmp;tmp=tmp->next) + if ((needputrfc(tmp) == 1)) { + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(pkt,"\1RFC-Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"\1RFC-%s:",tmp->key); + } + kwrite(hdrconv(tmp->val, incode, outcode),pkt, postlocal); + } + for (tmp=msg;tmp;tmp=tmp->next) + if ((needputrfc(tmp) > 1)) { + rfcheaders++; + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(pkt,"Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"%s:",tmp->key); + } + cwrite(hdrconv(tmp->val, incode, outcode),pkt,postlocal); + } + if (rfcheaders) + cwrite((char *)"\n",pkt, postlocal); + if ((hdr((char *)"X-FTN-SOT",msg)) || (sot_kludge)) { + if (postlocal) + fprintf(pkt,"\1SOT:\n"); + else + fprintf(pkt,"\1SOT:\r"); + } + if ((splitpart == 0) && (hdr((char *)"X-PGP-Signed",msg))) { + if (postlocal) + fprintf(pkt,PGP_SIGNED_BEGIN"\n"); + else + fprintf(pkt,PGP_SIGNED_BEGIN"\r"); + } + } + + if (replyaddr) { +// free(replyaddr); /* Gives SIGSEGV */ + replyaddr=NULL; + } + if (needsplit) { + if (postlocal) + fprintf(pkt," * Continuation %d of a split message *\n\n", splitpart); + else + fprintf(pkt," * Continuation %d of a split message *\r\r", splitpart); + needsplit=0; + } else if ((p=hdr((char *)"X-Body-Start",msg))) { + datasize += strlen(p); + if (qp_or_base64==1) + cwrite(strkconv(qp_decode(p), incode, outcode), pkt, postlocal); + else if (qp_or_base64==2) + cwrite(strkconv(b64_decode(p), incode, outcode), pkt, postlocal); + else + cwrite(strkconv(p, incode, outcode), pkt, postlocal); + } + while (!(needsplit=(!forbidsplit) && (((splitpart && (datasize > (CFG.new_split * 1024))) || + (!splitpart && ((datasize+hdrsize) > (CFG.new_split * 1024)))))) && (bgets(buf,sizeof(buf)-1,fp))) { +// Syslog('m', "putmessage body %s",buf); + datasize += strlen(buf); + if (qp_or_base64==1) + cwrite(strkconv(qp_decode(buf), incode, outcode), pkt, postlocal); + else if (qp_or_base64==2) + cwrite(strkconv(b64_decode(buf), incode, outcode), pkt, postlocal); + else + cwrite(strkconv(buf, incode, outcode), pkt, postlocal); + } + if (needsplit) { + if (postlocal) + fprintf(pkt,"\n * Message split, to be continued *\n"); + else + fprintf(pkt,"\r * Message split, to be continued *\r"); + splitpart++; + } else if ((p=hdr((char *)"X-PGP-Signed",msg))) { + if (postlocal) + fprintf(pkt,PGP_SIG_BEGIN"\n"); + else + fprintf(pkt,PGP_SIG_BEGIN"\r"); + if ((q=hdr((char *)"X-PGP-Version",msg))) { + fprintf(pkt,"Version:"); + cwrite(q,pkt, postlocal); + } + if ((q=hdr((char *)"X-PGP-Charset",msg))) { + fprintf(pkt,"Charset:"); + cwrite(q,pkt, postlocal); + } + if ((q=hdr((char *)"X-PGP-Comment",msg))) { + fprintf(pkt,"Comment:"); + cwrite(q,pkt, postlocal); + } + if (postlocal) + fprintf(pkt,"\n"); + else + fprintf(pkt,"\r"); + p=xstrcpy(p); + q=strtok(p," \t\n"); + if (postlocal) + fprintf(pkt,"%s\n",q); + else + fprintf(pkt,"%s\r",q); + while ((q=(strtok(NULL," \t\n")))) { + if (postlocal) + fprintf(pkt,"%s\n",q); + else + fprintf(pkt,"%s\r",q); + } + if (postlocal) + fprintf(pkt,PGP_SIG_END"\n"); + else + fprintf(pkt,PGP_SIG_END"\r"); + } + + if ((p=hdr((char *)"X-FTN-EOT",msg)) || (eot_kludge)) { + if (postlocal) + fprintf(pkt,"\1EOT:\n"); + else + fprintf(pkt,"\1EOT:\r"); + } + + if ((p=hdr((char *)"X-FTN-Tearline",msg))) { + fprintf(pkt,"---"); + if (strcasecmp(p," (none)\n") == 0) + cwrite((char *)"\n",pkt,postlocal); + else + cwrite(p,pkt,postlocal); + } else { + if (postlocal) + fprintf(pkt,"--- MBSE BBSv.%s\n",VERSION); + else + fprintf(pkt,"--- MBSE BBSv.%s\r",VERSION); + } + + if ((p=hdr((char *)"X-FTN-Origin",msg))) { + if (*(q=p+strlen(p)-1) == '\n') + *q='\0'; + fprintf(pkt," * Origin:"); + cwrite(hdrconv(p, incode, outcode),pkt, postlocal); + if (postlocal) + fprintf(pkt, "\n"); + else + fprintf(pkt,"\r"); + } else { + fprintf(pkt," * Origin: "); + if (fmsg->origin) + cwrite(hdrconv(fmsg->origin, incode, outcode), pkt, postlocal); + else + fprintf(pkt, "%s", CFG.origin); + if (postlocal) + fprintf(pkt, " (%s)\n", ascfnode(fmsg->from,tinyorigin?0x0f:0x1f)); + else + fprintf(pkt, " (%s)\r", ascfnode(fmsg->from,tinyorigin?0x0f:0x1f)); + } + + for (tmp = msg; tmp; tmp = tmp->next) + if (!strcasecmp(tmp->key,"X-FTN-Via")) { + datasize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"\1Via"); + kwrite(tmp->val,pkt, postlocal); + } + + /* + * @Via mbmail 2:293/2219@fidonet, Wed Jan 3 1996 at 07:49 (2.8c) + */ + if (postlocal) + fprintf(pkt,"\1Via mbmail %s, %s (%s)\n", ascfnode(bestaka,0x1f), viadate(),VERSION); + else + fprintf(pkt,"\1Via mbmail %s, %s (%s)\r", ascfnode(bestaka,0x1f), viadate(),VERSION); + + if (postlocal) { + subj = xstrcpy(fmsg->subj); + + /* + * Check userlist real names, handles, unix names. + * Import if one fits. + */ + if (!SearchUser(fmsg->to->name)) { + Syslog('+', " \"%s\" is not a known BBS user", fmsg->to->name); + /* + * Unknown, readdress it to the sysop. + */ + net_bad++; + Syslog('+', " Readdress from %s to %s", fmsg->to->name, CFG.sysop_name); + fmsg->to->name = xstrcpy(CFG.sysop_name); + } + if (SearchUser(fmsg->to->name)) { + Syslog('m', "importnet(%s, %s, %s, %04x)", ascfnode(fmsg->from,0x7f), + ascfnode(fmsg->to,0x7f), ftndate(fmsg->date), fmsg->flags); + if (importnet(fmsg->from, fmsg->to, fmsg->date, fmsg->flags, pkt)) + return 2; + } else { + WriteError("Unknown bbs user"); + return 2; + } + } else { + awrite((char *)"",pkt); /* trailing zero byte */ + if (ferror(pkt)) { + WriteError("$error writing to ftn packet"); + return 1; + } + net_out++; + } + tidy_falist(&ptl); + } + while (needsplit); + + Syslog('m', "putmessage exiting..."); + return 0; +} + diff --git a/mbfido/message.h b/mbfido/message.h new file mode 100644 index 00000000..ce27317a --- /dev/null +++ b/mbfido/message.h @@ -0,0 +1,12 @@ +#ifndef _MESSAGE_H +#define _MESSAGE_H + + +void StatAdd(statcnt *, unsigned long); +int needputrfc(rfcmsg*); +char *viadate(void); +int putmessage(rfcmsg *, ftnmsg *, FILE *, faddr *, char,fa_list **, int, int); + + +#endif + diff --git a/mbfido/mgrutil.c b/mbfido/mgrutil.c new file mode 100644 index 00000000..4b97573b --- /dev/null +++ b/mbfido/mgrutil.c @@ -0,0 +1,223 @@ +/***************************************************************************** + * + * File ..................: mbfido/mgrutil.c + * Purpose ...............: AreaMgr and FileMgr utilities. + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "sendmail.h" +#include "mgrutil.h" + + + + +void WriteMailGroups(FILE *fp, faddr *f) +{ + int Count = 0, First = TRUE; + char *Group, *temp; + FILE *gp; + + temp = calloc(128, sizeof(char)); + fprintf(fp, "Dear %s\r\r", nodes.Sysop); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + fprintf(fp, "The following is a list of mail groups at %s\r\r", ascfnode(f, 0x1f)); + + if ((gp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + return; + } + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + +// 123456789012 1234567890123456789012345678901234567890123456789012345 + fprintf(fp, "Group Description\r"); + fprintf(fp, "--------------------------------------------------------------------\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + fprintf(fp, "%-12s %s\r", mgroup.Name, mgroup.Comment); + Count++; + break; + } + } + } + + fprintf(fp, "--------------------------------------------------------------------\r"); + fprintf(fp, "%d group(s)\r\r\r", Count); + + fclose(gp); + free(temp); +} + + + +void WriteFileGroups(FILE *fp, faddr *f) +{ + int Count = 0, First = TRUE; + char *Group, *temp; + FILE *gp; + + temp = calloc(128, sizeof(char)); + fprintf(fp, "Dear %s\r\r", nodes.Sysop); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + fprintf(fp, "The following is a list of file groups at %s\r\r", ascfnode(f, 0x1f)); + + if ((gp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + return; + } + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + +// 123456789012 1234567890123456789012345678901234567890123456789012345 + fprintf(fp, "Group Description\r"); + fprintf(fp, "--------------------------------------------------------------------\r"); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + (fgroup.UseAka.zone == f->zone) && + (fgroup.UseAka.net == f->net) && + (fgroup.UseAka.node == f->node) && + (fgroup.UseAka.point == f->point)) { + fprintf(fp, "%-12s %s\r", fgroup.Name, fgroup.Comment); + Count++; + break; + } + } + } + + fprintf(fp, "--------------------------------------------------------------------\r"); + fprintf(fp, "%d group(s)\r\r\r", Count); + + fclose(gp); + free(temp); +} + + + +char *GetBool(int Flag) +{ + if (Flag) + return (char *)"Yes"; + else + return (char *)"No"; +} + + + +void ShiftBuf(char *Buf, int Cnt) +{ + int i; + + for (i = Cnt; i < strlen(Buf); i++) + Buf[i - Cnt] = Buf[i]; + Buf[i - Cnt] = '\0'; +} + + + +void CleanBuf(char *Buf) +{ + while (strlen(Buf) && ((Buf[0] == ' ') || (Buf[0] == '='))) + ShiftBuf(Buf, 1); +} + + + +void MgrPasswd(faddr *t, char *Buf, FILE *tmp, int Len) +{ + fidoaddr Node; + + ShiftBuf(Buf, Len); + CleanBuf(Buf); + + if ((strlen(Buf) < 3) || (strlen(Buf) > 15)) { + fprintf(tmp, "A new password must be between 3 and 15 characters in length\n"); + Syslog('+', "XxxxMgr: Password length %d, not changed", strlen(Buf)); + return; + } + + memset(&nodes.Apasswd, 0, 16); + sprintf(nodes.Apasswd, "%s", tu(Buf)); + fprintf(tmp, "AreaMgr and FileMgr password is now \"%s\"\n", nodes.Apasswd); + Syslog('+', "XxxxMgr: Password \"%s\"", nodes.Apasswd); + UpdateNode(); + memcpy(&Node, faddr2fido(t), sizeof(fidoaddr)); + SearchNode(Node); +} + + + +void MgrNotify(faddr *t, char *Buf, FILE *tmp) +{ + fidoaddr Node; + + /* + * First strip leading garbage + */ + ShiftBuf(Buf, 7); + CleanBuf(Buf); + + if (!strncasecmp(Buf, "on", 2)) + nodes.Notify = TRUE; + else if (!strncasecmp(Buf, "off", 3)) + nodes.Notify = FALSE; + else + return; + + UpdateNode(); + memcpy(&Node, faddr2fido(t), sizeof(fidoaddr)); + SearchNode(Node); + Syslog('+', "XxxxMgr: Notify %s", GetBool(nodes.Notify)); + fprintf(tmp, "AreaMgr and FileMgr Notify is %s\n", GetBool(nodes.Notify)); +} + + diff --git a/mbfido/mgrutil.h b/mbfido/mgrutil.h new file mode 100644 index 00000000..7fbd2fa8 --- /dev/null +++ b/mbfido/mgrutil.h @@ -0,0 +1,15 @@ +#ifndef _MGRUTIL_H +#define _MGRUTIL_H + + +void WriteMailGroups(FILE *, faddr *); +void WriteFileGroups(FILE *, faddr *); +char *GetBool(int); +void CleanBuf(char *); +void ShiftBuf(char *, int); +void MgrPasswd(faddr *, char *, FILE *, int); +void MgrNotify(faddr *, char *, FILE *); + + +#endif + diff --git a/mbfido/mkftnhdr.c b/mbfido/mkftnhdr.c new file mode 100644 index 00000000..074c2ac5 --- /dev/null +++ b/mbfido/mkftnhdr.c @@ -0,0 +1,543 @@ +/***************************************************************************** + * + * File ..................: mbmail/mkftnhdr.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 25-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* Base on E.C. Crosser's ifmail. + * + * ### Modified by P.Saratxaga on 19 Sep 1995 ### + * - Added X-FTN-From and X-FTN-To support + * - added code by T.Tanaka, dated 13 Mar 1995, to put the freename in the ftn + * header, instead of the userid, when the address is fido parseable + * - modified ^aREPLY: code, to look in In-Reply-To: + * - support to decode MSGID from fidogate "Message-ID: " + * - suport for X-Apparently-To: (generated by the french fido->usenet gate) + * - added don't regate code by Wim Van Sebroeck + * - corriged a bug when Organization: has only blanks + */ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "atoul.h" +#include "hash.h" +#include "aliasdb.h" +#include "mkftnhdr.h" + + + +#ifndef ULONG_MAX +#define ULONG_MAX 4294967295 +#endif + + +char *replyaddr=NULL; +char *ftnmsgidstyle=NULL; +faddr *bestaka; + + + +int ftnmsgid(char *msgid, char **s, unsigned long *n, char *areaname) +{ + char *buf, *l, *r, *p; + unsigned long nid = 0L; + faddr *tmp; + static int ftnorigin = 0; + + if (msgid == NULL) { + *s = NULL; + *n = 0L; + return ftnorigin; + } + + buf = malloc(strlen(msgid)+65); + strcpy(buf, msgid); + if ((l = strchr(buf,'<'))) + l++; + else + l = buf; + while (isspace(*l)) + l++; + if ((r = strchr(l,'>'))) + *r = '\0'; + r = l + strlen(l) - 1; + while (isspace(*r) && (r > l)) + (*r--)='\0'; + if ((tmp = parsefaddr(l))) { + if (tmp->name) { + if (strspn(tmp->name,"0123456789") == strlen(tmp->name)) + nid = atoul(tmp->name); + else + nid = ULONG_MAX; + if (nid == ULONG_MAX) { + hash_update_s(&nid, tmp->name); + } else + ftnorigin = 1; + } else { + hash_update_s(&nid,l); + } + *s = xstrcpy(ascfnode(tmp, 0x1f)); + tidy_faddr(tmp); + } else { + if ((r=strchr(l,'@')) == NULL) { /* should never happen */ + Syslog('!', "ftnmsgid: should never happen"); + *s = xstrcpy(l); + hash_update_s(&nid,l); + /* */ + } else if (strncmp(l,"MSGID_",6) == 0) { + *r = '\0'; + r = strrchr(l+6,'_'); + if (r) + *r++ = '\0'; + *s = xstrcpy(qp_decode(l+6)); + if (r) + sscanf(r,"%lx",&nid); + ftnorigin = 1; + /* */ + } else if (strncmp(l,"NOMSGID_",8) == 0) { + *s = NULL; + *n = 0L; + ftnorigin = 1; + return ftnorigin; + /* */ + } else if (strncmp(l,"ftn_",4) == 0) { + *r = '\0'; + if ((r = strchr(l+4,'$')) || (r=strchr(l+4,'#'))) { + if (*r=='$') + *r='@'; + if ((r=strchr(l+4,'.'))) + *r=':'; + if ((r=strchr(l+4,'.'))) + *r='/'; + } + while ((r=strrchr(l+4,'_')) != strchr(l+4,'_')) + *r='\0'; + r=strchr(l+4,'_'); + *r++='\0'; + *s=xstrcpy(l+4); + sscanf(r,"%lx",&nid); + ftnorigin=1; + /* */ + } else if (strncmp(l,"wgcid$",6) == 0) { + *r='\0'; + if ((r=strstr(l+6,"$g"))) { + *r='\0'; + *s=xstrcpy(l+6); + *s=xstrcat(*s,(char *)":"); + l=r+2; + } + if ((r=strstr(l,"$h"))) { + *r++='\0'; + *s=xstrcat(*s,l); + *s=xstrcat(*s,(char *)"/"); + l=r+2; + } + if ((r=strstr(l,"$i"))) { + *r='\0'; + *s=xstrcat(*s,l); + *s=xstrcat(*s,(char *)"."); + l=r+2; + } + if ((r=strstr(l,"$k"))) { + *r='\0'; + *s=xstrcat(*s,l); + *s=xstrcat(*s,(char *)"@"); + l=r+2; + } + if ((r=strstr(l,"$j"))) { + *r='\0'; + *s=xstrcat(*s,l); + sscanf(r+2,"%lx",&nid); + } + } else { + *r='\0'; + if ((p=strchr(l,'%'))) { + *p='\0'; + if (strspn(l,"0123456789") == strlen(l)) { + *r='@'; + r=p; + } else + *p='%'; + } + r++; + if (strspn(l,"0123456789") == strlen(l)) + nid = atoul(l); + else + nid = ULONG_MAX; + if (nid == ULONG_MAX) + hash_update_s(&nid,l); + *s=xstrcpy(r); + } + } + *n=nid; + + free(buf); + return ftnorigin; +} + + + +ftnmsg *mkftnhdr(rfcmsg *msg, int incode, int outcode, int newsmode) +{ + char *freename = NULL, *rfcfrom = NULL, *p, *q, *l, *r; + char *fbuf = NULL; + char *ftnfrom=NULL; + static ftnmsg *tmsg; + int needreplyaddr = 1; + faddr *tmp; + + tmsg=(ftnmsg *)malloc(sizeof(ftnmsg)); + memset(tmsg, 0, sizeof(ftnmsg)); + + if (newsmode) { + p = xstrcpy(hdr((char *)"Comment-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Comment-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-FTN-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Fidonet-Comment-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Apparently-To",msg)); + if (p) { + Syslog('N', "getting `to' address from: \"%s\"",p); + if ((tmsg->to = parsefaddr(p)) == NULL) + tmsg->to = parsefaddr((char *)"All@p0.f0.n0.z0"); + if ((l = strrchr(p,'<')) && (r = strchr(p,'>')) && (l < r)) { + r = l; + *r-- = '\0'; + if ((l = strchr(p,'"')) && (r = strrchr(p,'"')) && (l < r)) { + l++; + *r-- = '\0'; + } + while (isspace(*r)) + *r-- = '\0'; + if (!l) + l = p; + while (isspace(*l)) + l++; + } else if ((l = strrchr(p,'(')) && (r = strchr(p,')')) && (l < r)) { + *r-- = '\0'; + while (isspace(*r)) + *r-- = '\0'; + l++; + while (isspace(*l)) + l++; + } else { + l = p; + while (isspace(*l)) + l++; + r = p + strlen(p) -1; + if (*r == '\n') + *r-- = '\0'; + while (isspace(*r)) + *r-- = '\0'; + } + + if (*l) { + strcpy(l,hdrnconv(l,incode,outcode,MAXNAME)); + if (strlen(l) > MAXNAME) + l[MAXNAME]='\0'; + free(tmsg->to->name); + tmsg->to->name=xstrcpy(l); + } + free(p); + } else + tmsg->to = parsefaddr((char *)"All@p0.f0.n0.z0"); + Syslog('n', "TO: %s",ascinode(tmsg->to,0x7f)); + } + + p = fbuf = xstrcpy(hdr((char *)"Reply-To", msg)); + if (fbuf == NULL) + p = fbuf = xstrcpy(hdr((char *)"From", msg)); + if (fbuf == NULL) + p = fbuf = xstrcpy(hdr((char *)"X-UUCP-From", msg)); + if (p) { + q = p; + while (isspace(*q)) + q++; + fbuf = parserfcaddr(q).remainder; + if (parserfcaddr(q).target) { + fbuf = xstrcat(fbuf, (char *)"@"); + fbuf = xstrcat(fbuf, parserfcaddr(q).target); + } + rfcfrom = fbuf; + } + if (p) + free(p); + p = NULL; + if (!rfcfrom) + rfcfrom = xstrcpy((char *)"postmaster"); + p = fbuf = xstrcpy(hdr((char *)"From", msg)); + if (fbuf == NULL) + p = fbuf = xstrcpy(hdr((char *)"X-UUCP-From", msg)); + if (p) { + q = p; + while (isspace(*q)) + q++; + if ((q) && (*q != '\0')) + freename = parserfcaddr(q).comment; + else + freename = NULL; + } else + freename = xstrcpy((char *)"Unidentified User"); + if (freename) { + while (isspace(*freename)) + freename++; + } +// if (p) NOT IN IFMAIL +// free(p); +// p = NULL; + if (rfcfrom) { + while (isspace(*rfcfrom)) + rfcfrom++; + p = rfcfrom + strlen(rfcfrom) -1; + while ((isspace(*p)) || (*p == '\n')) + *(p--)='\0'; + } + + if ((freename) && (*freename != '\0')) { + while (isspace(*freename)) + freename++; + p = freename + strlen(freename) -1; + while ((isspace(*p)) || (*p == '\n')) + *(p--)='\0'; + strcpy(freename, hdrconv(freename, incode, outcode)); + if ((*freename == '\"') && (*(p=freename+strlen(freename)-1) == '\"')) { + freename++; + *p='\0'; + } + } + if ((!freename) || ((freename) && (*freename == '\0')) || (strcmp(freename,".")==0)) + freename=rfcfrom; + +// p = NULL; + if (newsmode) + Syslog('n', "FROM: %s <%s>", freename, rfcfrom); + else + Syslog('+', "from: %s <%s>",freename,rfcfrom); + + needreplyaddr = 1; + if ((tmsg->from=parsefaddr(rfcfrom)) == NULL) { + if (freename && rfcfrom) + if (!strchr(freename,'@') && !strchr(freename,'%') && + strncasecmp(freename,rfcfrom,MAXNAME) && + strncasecmp(freename,"uucp",4) && + strncasecmp(freename,"usenet",6) && + strncasecmp(freename,"news",4) && + strncasecmp(freename,"super",5) && + strncasecmp(freename,"admin",5) && + strncasecmp(freename,"postmaster",10) && + strncasecmp(freename,"sys",3)) + needreplyaddr=registrate(freename,rfcfrom); + } else { + tmsg->ftnorigin = 1; + tmsg->from->name = xstrcpy(freename); + if (strlen(tmsg->from->name) > MAXNAME) + tmsg->from->name[MAXNAME]='\0'; + } + if (replyaddr) { + free(replyaddr); + replyaddr=NULL; + } + if (needreplyaddr && (tmsg->from == NULL)) { + Syslog('m', "fill replyaddr with \"%s\"",rfcfrom); + replyaddr=xstrcpy(rfcfrom); + } + + Syslog('m', "From address was%s distinguished as ftn", tmsg->from ? "" : " not"); + + /* FIXME: received email from an Unix mailer comes here as well, only the From address is set. + The msgs.Aka next is not valid. */ + if ((tmsg->from == NULL) && ((bestaka = bestaka_s(fido2faddr(msgs.Aka))))) { + if (CFG.dontregate) { + p = xstrcpy(hdr((char *)"X-FTN-Sender",msg)); + if (p == NULL) { + if ((p = hdr((char *)"X-FTN-From",msg))) { + tmp = parsefnode(p); + p = xstrcpy(ascinode(tmp, 0xff)); + tidy_faddr(tmp); + } + } + if (p) { + q = p; + while (isspace(*q)) + q++; + ftnfrom = parserfcaddr(q).remainder; + if (parserfcaddr(q).target) { + ftnfrom = xstrcat(ftnfrom,(char *)"@"); + ftnfrom = xstrcat(ftnfrom,parserfcaddr(q).target); + } + Syslog('m', "Ftn gateway: \"%s\"", ftnfrom); + Syslog('+', "Ftn sender: %s",ftnfrom); + if (ftnfrom) + tmsg->from = parsefaddr(ftnfrom); + if ((tmsg->from) && (!tmsg->from->name)) + tmsg->from->name = xstrcpy(rfcfrom); + } + if (p) + free(p); + p = NULL; + if (tmsg->from == NULL) { + tmsg->from=(faddr *)malloc(sizeof(faddr)); + tmsg->from->name=xstrcpy(freename); + if (tmsg->from->name && (strlen(tmsg->from->name) > MAXNAME)) + tmsg->from->name[MAXNAME]='\0'; + tmsg->from->point=bestaka->point; + tmsg->from->node=bestaka->node; + tmsg->from->net=bestaka->net; + tmsg->from->zone=bestaka->zone; + tmsg->from->domain=xstrcpy(bestaka->domain); + } + } else { + tmsg->from=(faddr *)xmalloc(sizeof(faddr)); + tmsg->from->name=xstrcpy(freename); + if (tmsg->from->name && (strlen(tmsg->from->name) > MAXNAME)) + tmsg->from->name[MAXNAME]='\0'; + tmsg->from->point=bestaka->point; + tmsg->from->node=bestaka->node; + tmsg->from->net=bestaka->net; + tmsg->from->zone=bestaka->zone; + tmsg->from->domain=xstrcpy(bestaka->domain); + } + } + if (fbuf) + free(fbuf); + fbuf = NULL; + + p = hdr((char *)"Subject", msg); + if (p) { + while (isspace(*p)) + p++; + /* + * charset conversion for subject line is done in message.c + * here we only convert quoted-printable and base64 to 8 bit + */ + tmsg->subj = xstrcpy(hdrnconv(p, 0, 0, MAXSUBJ)); + tmsg->subj = xstrcpy(p); + if (*(p=tmsg->subj+strlen(tmsg->subj)-1) == '\n') + *p='\0'; + if (strlen(tmsg->subj) > MAXSUBJ) + tmsg->subj[MAXSUBJ]='\0'; + } else { + tmsg->subj = xstrcpy((char *)" "); + } +// if (p) +// free(p); +// p = NULL; + + Syslog('m', "SUBJ: \"%s\"", tmsg->subj); + + if ((p = hdr((char *)"X-FTN-FLAGS",msg))) + tmsg->flags |= flagset(p); + if (hdr((char *)"Return-Receipt-To",msg)) + tmsg->flags |= M_RRQ; + if (hdr((char *)"Notice-Requested-Upon-Delivery-To",msg)) + tmsg->flags |= M_RRQ; + if (!newsmode) { + tmsg->flags |= M_PVT; + tmsg->flags |= M_KILLSENT; + } + + if ((p = hdr((char *)"X-Origin-Date",msg))) + tmsg->date = parsedate(p, NULL); + else if ((p = hdr((char *)"Date",msg))) + tmsg->date = parsedate(p, NULL); + else + tmsg->date = time((time_t *)NULL); + + if ((p = hdr((char *)"X-FTN-MSGID", msg))) { + tmsg->ftnorigin &= 1; + while (isspace(*p)) + p++; + tmsg->msgid_s = xstrcpy(p); + if (*(p = tmsg->msgid_s + strlen(tmsg->msgid_s) -1) == '\n') + *p='\0'; + } else if ((p = hdr((char *)".MSGID",msg))) { + tmsg->ftnorigin &= 1; + while (isspace(*p)) + p++; + tmsg->msgid_s = xstrcpy(p); + if (*(p = tmsg->msgid_s + strlen(tmsg->msgid_s) -1) == '\n') + *p='\0'; + } else if ((p = hdr((char *)"Message-ID",msg))) { + tmsg->ftnorigin &= ftnmsgid(p,&(tmsg->msgid_a),&(tmsg->msgid_n),tmsg->area); + } else + tmsg->msgid_a = NULL; + + if ((p = hdr((char *)"X-FTN-REPLY",msg))) { + while (isspace(*p)) + p++; + tmsg->reply_s = xstrcpy(p); + if (*(p=tmsg->reply_s + strlen(tmsg->reply_s) -1) == '\n') + *p='\0'; + } else { + if (newsmode) { + p = hdr((char *)"References",msg); + if (p) { + l = xstrcpy(p); + r = strtok(l," \t\n"); + while ((l=strtok(NULL," \t\n")) != NULL) + r = l; + p = r; + free(l); + } + } else + p = hdr((char *)"In-Reply-To",msg); + } + if (p) + (void)ftnmsgid(p,&(tmsg->reply_a),&(tmsg->reply_n),NULL); + else + tmsg->reply_a=NULL; + + Syslog('m', "DATE: %s, MSGID: %s %lx, REPLY: %s %lx", + ftndate(tmsg->date), MBSE_SS(tmsg->msgid_a),tmsg->msgid_n, MBSE_SS(tmsg->reply_a),tmsg->reply_n); + + if ((p = hdr((char *)"Organization",msg))) { + while (isspace(*p)) + p++; + tmsg->origin = xstrcpy(hdrconv(p, incode, outcode)); + if (tmsg->origin) + if (*(p = tmsg->origin + strlen(tmsg->origin)-1) == '\n') + *p='\0'; + } else { + /* + * No Organization header, insert the default BBS origin. + */ + tmsg->origin = xstrcpy(CFG.origin); + } + + Syslog('m', "ORIGIN: %s", MBSE_SS(tmsg->origin)); + return tmsg; +} + + diff --git a/mbfido/mkftnhdr.h b/mbfido/mkftnhdr.h new file mode 100644 index 00000000..ad06c554 --- /dev/null +++ b/mbfido/mkftnhdr.h @@ -0,0 +1,10 @@ +#ifndef _MKFTNHDR_H +#define _MKFTNHDR_H + + +int ftnmsgid(char *,char **,unsigned long *,char *); +ftnmsg *mkftnhdr(rfcmsg *, int, int, int); + + +#endif + diff --git a/mbfido/mkrfcmsg.c b/mbfido/mkrfcmsg.c new file mode 100644 index 00000000..e62c1564 --- /dev/null +++ b/mbfido/mkrfcmsg.c @@ -0,0 +1,1490 @@ +/***************************************************************************** + * + * File ..................: mbfido/mkrfcmsg.c + * Purpose ...............: Import a email or news + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/dbftn.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "rollover.h" +#include "aliasdb.h" +#include "postemail.h" +#include "backalias.h" +#include "mkrfcmsg.h" + + +#define KWDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" +#define MAXPATH 73 +#define BOUNDARY 79 + +/* + * Global variables + */ +extern int news_in; /* Total news articles */ +extern int news_out; /* News articles posted */ +extern int news_bad; /* News articles refused */ +extern int defaultrfcchar; /* Default RFC charset */ +extern int defaultftnchar; /* Default FTN charset */ + +int newsopen = FALSE; /* News tempfile status */ +FILE *nfp; /* News tempfile */ + + +void fill_rlist(fa_list **, char *); +void fill_rlist(fa_list **fap, char *str) +{ + fa_list *tmp; + faddr *ta; + static unsigned int oldnet; + char *buf, *p, *q; + + if ((str == NULL) || (*str == '\0')) + return; + + Syslog('N' ,"fill_rlist %s",str); + buf = xstrcpy(str); + for (p = buf, q = strchr(p,'!'); *p; p = q, q = strchr(p,'!')) { + if (q) + *q++='\0'; + else + q=p+strlen(p); + if ((ta=parsefaddr(p))) { + if (ta->net == 0) + ta->net=oldnet; + else + oldnet=ta->net; + tmp=(fa_list *)malloc(sizeof(fa_list)); + tmp->next=*fap; + tmp->addr=ta; + *fap=tmp; + } + } + free(buf); + for (tmp=*fap;tmp;tmp=tmp->next) + Syslog('N', "fill_rlist returns: %s",ascfnode(tmp->addr,0x06)); + return; +} + + + +char *rfcmsgid(char *, faddr *); +char *rfcmsgid(char *msgid, faddr *bestaka) +{ + static char *buf, *p, *q, *r; + unsigned long id = 0L; + faddr *ta = NULL; + + if (msgid == NULL) + return NULL; + + /* + * +40 for the additionnal stuff we need to write, should be enough + * FIXME: This buffer is never freed!!!! + */ + buf = malloc(strlen(msgid)+40); + if ((r = strrchr(msgid,'\n'))) + *r = '\0'; + /* + * sometimes there is "^aMSGID: 1:23/45@@domain 152ad589" + */ + if ((p = strstr(msgid, "@@"))) { + *p='\0'; + strcat(msgid, p+1); + } else if ((p = strstr(msgid,"@ "))) { + /* + * other times there is "^aMSGID: 1:23/45@ 152ad589" + */ + *p='\0'; + strcat(msgid,p+1); + } + + if ((p=strrchr(msgid,' '))) { + /* + * here we have a parseable address + */ + *p = '\0'; + sscanf(p+1, "%lx", &id); + ta = parsefnode(msgid); + *p=' '; + } + + if (id != 0L) { + /* if we only check for (ta) a Message-ID like + * <123456.7890@internet.domain> will be recognized as + * a fidonet one (ta->node=123456, ta->point=7890, + * ta->domain="internet", but ta->net=0) which obviously + * isn't the case. By cheking also (ta->net) we avoid that + */ + if ((ta) && (ta->net)) { + sprintf(buf,"<%lu@%s.ftn>",id,ascinode(ta,0x1f)); + } else { + p=xstrcpy(msgid); + if ((q=strchr(p,' '))) + *q='\0'; + /* ### Modified by P.Saratxaga on 18 Aug 1995 */ + if (strstr(p,"@")) { + /* "mid__" are generated by gigo */ + if (!strncmp(p,"mid__<",6)) { + sprintf(buf,"%s",p+6); + while ((q=strstr(buf,">_<"))) + *(q+1)=' '; + } + /* "mid__local@domain" are also generated by gigo */ + else if (!strncmp(p,"mid__",5)) + sprintf(buf,"<%s>",p+5); + /* "wgmid$" */ + else if (!strncmp(p,"wgmid$<",7)) + sprintf(buf,"%s",p+6); + /* in case we have "" */ + else if (!strncmp(p,"<",1)) + sprintf(buf,"%s",p); + /* or "local@domain" */ + else + sprintf(buf,"<%s>",p); + while ((q = strchr(buf, '@')) != strrchr(buf, '@')) { + /* we (still) have more than one @ */ + *q = '%'; + } + } else { + sprintf(buf,"<%lu@%s>",id,p); + } + free(p); + } + } else { + sprintf(buf,"<%lu@%s.ftn>",(unsigned long)sequencer(), ascinode(bestaka,0x1f)); + } + tidy_faddr(ta); + if (r) + *r='\n'; + return buf; +} + + + +/* + * check address for localness, substitute alises and replace it *in place* + */ +void substitude(char *); +void substitute(char *buf) +{ + faddr *fa; + char *l,*r,*p=NULL; + int inquotes,inbrackets; + + Syslog('m', "to address before subst: \"%s\"",buf); + if ((l=strchr(buf,'<')) && (r=strchr(buf,'>')) && (l < r)) { + l++; + *r='\0'; + } else + l=buf; + while (*l == ' ') + l++; + for (r=l,inquotes=0,inbrackets=0;*r;r++) + switch (*r) { + case '"': inquotes=(!inquotes); break; + case ',': + case ' ': if (!inquotes && !inbrackets) *r='\0'; break; + case '(': if (!inquotes) inbrackets++; break; + case ')': if (!inquotes && inbrackets) inbrackets--; break; + default: break; + } + if ((fa=parsefaddr(l))) { + Syslog('m', "it is an ftn address: %s",ascfnode(fa,0x7f)); + if (is_local(fa)) { + Syslog('m', "it is local"); + sprintf(buf,"%s",fa->name); + if (!strchr(buf,'@') && (p=strrchr(buf,'%'))) + *p='@'; + if (!strchr(buf,'@')) { + /* + * Lookup the name first in the alias database, then + * the userbase and finally check the password file + * (gecos->username). If not found it's and error. + */ + if ((p = lookup(buf))) + strcpy(buf, p); + else if (SearchUser(buf)) + sprintf(buf, "%s@%s", usr.Name, CFG.sysdomain); + else if (!strcasecmp(buf,"sysop")) + strcpy(buf,"postmaster"); + else + sprintf(buf,"%s",ascinode(fa,0x7f)); + } + } else { + WriteError("substitute(%s) it is not local, may not happen", buf); + sprintf(buf,"%s",ascinode(fa,0x7f)); + } + tidy_faddr(fa); + } else { + Syslog('m', "it is not ftn address"); + for (r=buf;*l;l++,r++) + *r=*l; + *r='\0'; + } + if (buf[0] == '\0') + strcpy(buf,"postmaster"); + Syslog('m', "to address after subst: \"%s\"",buf); + return; +} + + + +/* + * Lines to send, terminated with a newline character. + */ +void Send(int, const char *, ...); +void Send(int newsmode, const char *format, ...) +{ + char *outstr, *p; + va_list va_ptr; + unsigned long crc; + + outstr = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + + fwrite(outstr, 1, strlen(outstr), nfp); + + if (newsmode) { + Striplf(outstr); + if (strncmp(outstr, (char*)"Message-ID: ", 12) == 0) { + /* + * The Message-ID that is sent to the newsserver is stored in + * the dupes database. The database isn't checked for dupes, this + * message is already checked for dupes. The function that will + * pull news articles from the news server will check the dupes + * database and thus will not fetch this local posted article. + */ + p = xstrcpy(outstr+12); + p = xstrcat(p, msgs.Newsgroup); + crc = str_crc32(p); + CheckDupe(crc, D_NEWS, CFG.nntpdupes); + free(p); + } + } + + free(outstr); +} + + + +/* + * Import gated email into users email box or import news article + * on the news server. + * + * 0 - All seems well. + * 1 - Something went wrong. + * 4 - Unable to open temporary file + * + */ +int mkrfcmsg(faddr *f, faddr *t, char *subj, char *origline, time_t mdate, int flags, FILE *pkt, off_t endoff, int ftn_from) +{ + int rrq, result = 1, modtype = 0; + int incode = CHRS_NOTSET, outcode = CHRS_NOTSET; + int waskludge = FALSE, badkludge, pgpsigned = FALSE; + int bNeedToGetAddressFromMsgid = (int)NULL; + int newsmode = 0, lines, pass, count, first; + char *newsgroup = NULL, *distribution = NULL, *moderator = NULL; + char *temp, *p, *q, *r, *l, *b; + char *To = NULL, buf[4096], *charset, c; + time_t now; + rfcmsg *kmsg = NULL, **tmsg, *qmsg, *msg = NULL; + off_t endmsg_off, tear_off, orig_off, via_off; + faddr *o, *bestaka, *ta, *tfaddr; + FILE *fp; + fa_list *rlist, *tfa, *ftnpath = NULL; + int dirtyoutcode = CHRS_NOTSET; + struct utsname utsbuf; + char MailFrom[128], MailTo[128]; + + temp = calloc(2048, sizeof(char)); + tmsg = &kmsg; + tear_off = orig_off = via_off = 0L; + + if ((fp = tmpfile()) == NULL) { + WriteError("$Unable to open temporary file"); + free(temp); + return 4; + } + + Syslog('m', "Message input start ============="); + rewind(pkt); + while ((fgets(buf, sizeof(buf)-2, pkt)) != NULL) { + /* + * Simple test to see how large the buffer must be. 2048 bytes has been seen. + */ + if (strlen(buf) > (sizeof(buf) /2)) + Syslog('+', "Possible bufferoverflow: line read %d bytes", strlen(buf)); + if (strlen(buf) > 200) { + Syslog('m', "Next line should be %d characters", strlen(buf)); + Syslogp('m', printable(buf, 200)); +// } else { +// Syslogp('m', printable(buf, 0)); + } + if ((buf[0] == '\1') || !strncmp(buf,"AREA:",5) || !strncmp(buf,"SEEN-BY",7)) { /* This is a kluge line */ + waskludge = TRUE; + badkludge = FALSE; + if (buf[0] == '\1') { + l = buf+1; + if (!strncmp(l,"AREA:",5) || !strncmp(l,"SEEN-BY",7)) + badkludge = TRUE; + } else + l = buf; + if (*l == '\n') + badkludge = TRUE; + else + while (isspace(*l)) + l++; + if (strncmp(l, "RFC-", 4)) + for (p = l; *p; p++) + if ((*p != '\n') && (((*p)&0x7f) < ' ')) + badkludge = TRUE; + p = strchr(l,':'); + r = strchr(l,' '); + if (p && (!r || (r > p))) + r = p; + else + p = r; + if (r == NULL) + badkludge = TRUE; + else if (!*(p+1) || (*(p+1)=='\n')) + badkludge = TRUE; + else { + c = *r; + *r = '\0'; + if (strspn(l,KWDCHARS) != strlen(l)) + badkludge = TRUE; + *r = c; + } + *tmsg = (rfcmsg *)malloc(sizeof(rfcmsg)); + (*tmsg)->next = NULL; + if (badkludge) { + (*tmsg)->key = xstrcpy((char *)"KLUDGE"); + p = printable(l,0); + r = p+strlen(p)-2; + if (strcmp(r,"\\n") == 0) { + *r++ = '\n'; + *r = '\0'; + } + (*tmsg)->val = xstrcpy(p); + } else { + *r++ = '\0'; + while (isspace(*r)) + r++; + (*tmsg)->key = xstrcpy(l); + (*tmsg)->val = xstrcpy(r); + } + tmsg = &((*tmsg)->next); + + if (!strcmp(l,"Via") && (via_off == 0L)) { + via_off = ftell(fp); + Syslog('m', "^AVia \"%s\" at offset %ld", printable(buf, 0), (long)via_off); + } + } else { + /* + * this is not a kludge line + */ + if (waskludge && (isspace(buf[0]))) + fputs("\n",fp); /* first body line is not RFC hdr */ + waskludge=0; + if (!strncmp(buf,PGP_SIGNED_BEGIN, strlen(PGP_SIGNED_BEGIN))) + pgpsigned = TRUE; + else if ((!strncmp(buf,"---",3)) && ((buf[3] == '\r') || (buf[3] == ' ') || (buf[3] == '\n'))) { + tear_off=ftell(fp); + if ((hdr((char *)"Tearline",kmsg) == NULL)) { + *tmsg=(rfcmsg *)malloc(sizeof(rfcmsg)); + (*tmsg)->next=NULL; + (*tmsg)->key=xstrcpy((char *)"Tearline"); + if (strlen(buf+3) == strspn(buf+3," \t\r\n")) + (*tmsg)->val=xstrcpy((char *)"(none)\n"); + else + (*tmsg)->val=xstrcpy(buf+4); + tmsg=&((*tmsg)->next); + } + Syslog('M', "tearline \"%s\" at offset %ld", buf,(long)tear_off); + } else if (!strncmp(buf," * Origin:",10)) { + orig_off = ftell(fp); + *tmsg = (rfcmsg *)malloc(sizeof(rfcmsg)); + (*tmsg)->next = NULL; + (*tmsg)->key = xstrcpy((char *)"Origin"); + (*tmsg)->val = xstrcpy(buf+11); + tmsg = &((*tmsg)->next); + Syslog('M', "origin \"%s\" at offset %ld", buf,(long)orig_off); + p = buf+10; + while (*p == ' ') + p++; + if ((l = strrchr(p,'(')) && (r = strrchr(p,')')) && (l < r)) { + /* + * Extract origin address from the Origin line. + */ + *l = '\0'; + *r = '\0'; + l++; + if ((o = parsefnode(l))) { + f->point = o->point; + f->node = o->node; + f->net = o->net; + f->zone = o->zone; + if (o->domain) + f->domain = o->domain; + o->domain = NULL; + tidy_faddr(o); + } + } else { + bNeedToGetAddressFromMsgid = !NULL; + Syslog('+', "Couldn't find address in origin line (%s of %s, [%s])", + f->name, ascfnode(f, 0x1f), hdr((char *)"Origin", kmsg)); + if (*(l = p+strlen(p)-1) == '\n') + *l = '\0'; + } + for (l = p+strlen(p)-1; *l == ' '; l--) + *l = '\0'; + origline = xstrcpy(p); + } else if (!strncmp(buf," * Message split",16)) { + *tmsg = (rfcmsg *)malloc(sizeof(rfcmsg)); + (*tmsg)->next = NULL; + (*tmsg)->key = xstrcpy((char *)"Split"); + (*tmsg)->val = xstrcpy((char *)"already\n"); + tmsg=&((*tmsg)->next); + Syslog('m', "Split indicator found"); + } + fputs(buf,fp); + } + + } + Syslog('m', "Message input end ==============="); + + if (bNeedToGetAddressFromMsgid && (p = hdr((char *)"MSGID", kmsg))) { + Syslog('m', "Need To Get Address From Msgid start..."); + l = p; + while(isspace(*l) && *l) + l++; + r = strchr(l, ' '); + if(r) { + *r-- = '\0'; + while(isspace(*r) && *r) + r--; + } + if (l && r && l > r) { + if ((o = parsefnode(l))) { + f->point = o->point; + f->node = o->node; + f->net = o->net; + f->zone = o->zone; + if (o->domain) + f->domain = o->domain; + o->domain = NULL; + tidy_faddr(o); + Syslog('+', "Origin from: %s (src MSGID)", ascfnode(f,0x7f)); + } + } + } + + endmsg_off=ftell(fp); + if ((tear_off) && (tear_off < endmsg_off)) + endmsg_off = tear_off; + if ((orig_off) && (orig_off < endmsg_off)) + endmsg_off = orig_off; + if ((via_off) && (via_off < endmsg_off)) + endmsg_off = via_off; + Syslog('M', "end message offset %ld",(long)endmsg_off); + + rewind(fp); + msg = parsrfc(fp); + bestaka = bestaka_s(f); + rewind(fp); + + p = hdr((char *)"CHRS", kmsg); + if (p == NULL) + p = hdr((char *)"CHARSET", kmsg); + if (p == NULL) + p = hdr((char *)"CODEPAGE", kmsg); + if (p) + outcode = readchrs(p); + else { + p=hdr((char *)"Content-Type",msg); + if (p == NULL) + p=hdr((char *)"RFC-Content-Type",kmsg); + if (p == NULL) + p=hdr((char *)"Content-Type",kmsg); + if (p) + outcode=readcharset(p); + else { + q = rfcmsgid(hdr((char *)"MSGID",kmsg),bestaka); + Syslog('m', "start headers checking 1j"); + if ((hdr((char *)"Message-ID",msg)) || (hdr((char *)"RFC-Message-ID",kmsg)) || + (hdr((char *)"Message-ID",kmsg)) || (hdr((char *)"RFCID",kmsg)) || + (hdr((char *)"ORIGID",kmsg)) || ((hdr((char *)"MSGID",kmsg)) && (!chkftnmsgid(q)))) + outcode = defaultrfcchar; + else + outcode = defaultftnchar; + if (q) + free(q); + q = NULL; + } + } + + /* + * A hack for TerMail + */ + p = hdr((char *)"PID", kmsg); + if ((p) && (!strncmp(p, "TerMail", 7)) && (outcode == defaultrfcchar)) + outcode = defaultftnchar; + + if (dirtyoutcode != CHRS_NOTSET) + outcode = dirtyoutcode; + if (pgpsigned) + incode = outcode; + + if (kmsg && !strcmp(kmsg->key,"AREA")) { + /* + * The msgs record is already loaded. + */ + newsgroup = xstrcpy(msgs.Newsgroup); + if (strlen(msgs.Distribution)) + distribution = xstrcpy(msgs.Distribution); + if (strlen(msgs.Moderator)) { + moderator = xstrcpy(msgs.Moderator); + if (msgs.MsgKinds == USEMOD) + modtype = 1; + } + Syslog('m', "newsgroup %s, distribution %s, moderator %s modtype %d", + printable(newsgroup, 0), printable(distribution, 0), printable(moderator, 0), modtype); + newsmode = TRUE; + if ((modtype == 1) && (!hdr((char *)"Approved",msg)) && + (!hdr((char *)"RFC-Approved",kmsg)) && (!hdr((char *)"Approved",kmsg))) + newsmode = TRUE; + } else + newsmode = FALSE; + Syslog('m', "Got %s message", newsmode?"echo":"netmail"); + + if ((outcode == CHRS_NOTSET) && (hdr((char *)"MSGID", kmsg))) { + p = rfcmsgid(hdr((char *)"MSGID",kmsg),bestaka); + if ((hdr((char *)"Message-ID",msg)) || (hdr((char *)"RFC-Message-ID",kmsg)) || + (hdr((char *)"Message-ID",kmsg)) || (hdr((char *)"RFCID",kmsg)) || + (hdr((char *)"ORIGID",kmsg)) || ((hdr((char *)"MSGID",kmsg)) && (!chkftnmsgid(p)))) + outcode = defaultrfcchar; + else + outcode = defaultftnchar; + free(p); + } + if (pgpsigned) + incode = outcode; + else if (incode == CHRS_NOTSET) + incode = getincode(outcode); + + + /* + * fsc-0038 defines "^aDOMAIN: othernet 99:12/34 fidonet 2:293/2219" + */ + if ((p=hdr((char *)"DOMAIN",kmsg)) && (!strchr(p,'@'))) { + strncpy(buf,p,sizeof(buf)-1); + buf[sizeof(buf)-1]='\0'; + l=strtok(buf," \n"); + p=strtok(NULL," \n"); + r=strtok(NULL," \n"); + q=strtok(NULL," \n"); + if ((ta=parsefnode(p))) { + t->point=ta->point; + t->node=ta->node; + t->net=ta->net; + t->zone=ta->zone; + tidy_faddr(ta); + } + t->domain=xstrcpy(l); + if ((ta=parsefnode(q))) { + f->point=ta->point; + f->node=ta->node; + f->net=ta->net; + f->zone=ta->zone; + tidy_faddr(ta); + } + f->domain=xstrcpy(r); + } else if ((p=hdr((char *)"INTL",kmsg))) { + strncpy(buf,p,sizeof(buf)-1); + buf[sizeof(buf)-1]='\0'; + l=strtok(buf," \n"); + r=strtok(NULL," \n"); + if ((ta=parsefnode(l))) { + t->point=ta->point; + t->node=ta->node; + t->net=ta->net; + t->zone=ta->zone; + if (ta->domain) { + if (t->domain) + free(t->domain); + t->domain=ta->domain; + ta->domain=NULL; + } + tidy_faddr(ta); + } + if ((ta=parsefnode(r))) { + f->point=ta->point; + f->node=ta->node; + f->net=ta->net; + f->zone=ta->zone; + if (ta->domain) { + if (f->domain) + free(f->domain); + f->domain=ta->domain; + ta->domain=NULL; + } + tidy_faddr(ta); + } + } + + /* + * fidogate generates "^aDOMAIN: Z2@fidonet" + */ + if ((f->domain==NULL) && ((p=hdr((char *)"DOMAIN",kmsg)) && (q=strchr(p,'@')))) { + *q='\0'; + f->domain=xstrcpy(q+1); + *q='@'; + } + + if ((p=hdr((char *)"FMPT",kmsg))) + f->point=atoi(p); + if ((p=hdr((char *)"TOPT",kmsg))) + t->point=atoi(p); + + Syslog('m', "final from: %s",ascfnode(f,0xff)); + Syslog('m', "final to: %s",ascfnode(t,0xff)); + + if (!newsmode) { + p=hdr((char *)"Resent-To",msg); + if (p == NULL) + p=hdr((char *)"To",msg); + if (p == NULL) + p=hdr((char *)"RFC-Resent-To",kmsg); + if (p == NULL) + p=hdr((char *)"RFC-To",kmsg); + if (p && is_local(t)) { + while (*p == ' ') + p++; + strncpy(buf, p, sizeof(buf) -1); + if (*(p = buf + strlen(buf) -1) == '\n') + *p='\0'; + } else if (modtype == 1) + sprintf(buf,"%s",moderator); + else + sprintf(buf,"%s",ascinode(t,0x7f)); + substitute(buf); + Syslog('+', "mail from %s to %s",ascfnode(f,0x7f),buf); + To = xstrcpy(buf); + } + + + if (!newsmode) { + Syslog('m', "Preparing email"); +// if (p) +// free(p); + p = NULL; + p = hdr((char *)"Return-Path",msg); + if (p == NULL) + p=hdr((char *)"RFC-Return-Path",kmsg); + if (p == NULL) + p=hdr((char *)"Return-Path",kmsg); + if (p) + sprintf(MailFrom, "%s", p); + else + sprintf(MailFrom, "%s", ascinode(f,0x7f)); + Syslog('m', "MailFrom: %s", MailFrom); + + if (To) + sprintf(MailTo, "%s", To); + else + sprintf(MailTo, "%s", t->name); + Syslog('m', "MailTo: %s", MailTo); + + /* + * Because we need the same stream for news and email + * we need to check if the newsfile is already open. + */ + if (newsopen) { + fclose(nfp); + newsopen = FALSE; + } + + if ((nfp = tmpfile()) == NULL) { + WriteError("$Unable to open temporary file"); + return 4; + } + + Syslog('m', "Prepare is ready"); + + if (modtype == 1) + newsmode = TRUE; + } + + if (newsmode) { + /* + * Open temporary newsfile, append messages if it already exists. + */ + if (!newsopen) { + p = calloc(PATH_MAX, sizeof(char)); + sprintf(p, "%s/tmp/newsout", getenv("MBSE_ROOT")); + if ((nfp = fopen(p, "a")) == NULL) { + WriteError("$Can't open %s", p); + free(p); + return 2; + } + free(p); + newsopen = TRUE; + } + + if ((p=hdr((char *)"Path",msg)) == NULL) + p=hdr((char *)"RFC-Path",kmsg); + rlist=NULL; + fill_rlist(&rlist, p); + for (qmsg = kmsg; qmsg; qmsg = qmsg->next) + if (strcasecmp(qmsg->key, "SPTH") == 0) + fill_list(&ftnpath, qmsg->val, &rlist, FALSE); + for (qmsg = kmsg; qmsg; qmsg = qmsg->next) + if (strcasecmp(qmsg->key, "PATH") == 0) + fill_list(&ftnpath, qmsg->val, &rlist, FALSE); + tidy_falist(&rlist); + + /* + * Build Path: headerline + */ + q = xstrcpy((char *)"Path: "); + if (CFG.newsfeed == FEEDUUCP) { + /* + * If we don't run our own newsserver we have to simulate and + * add the UUCP nodename here. + */ + memset(&utsbuf, 0, sizeof(utsbuf)); + if (uname(&utsbuf)) { + WriteError("Can't get system nodename"); + } else { + q = xstrcat(q, utsbuf.nodename); + q = xstrcat(q, (char *)"!"); + } + } + tfaddr = fido2faddr(msgs.Aka); + q = xstrcat(q, ascinode(tfaddr, 0x07)); + tidy_faddr(tfaddr); + q = xstrcat(q, (char *)"!"); + if (ftnpath) + for (tfa=ftnpath->next;tfa;tfa=tfa->next) { + /* FIXME: possible memory leak */ + q = xstrcat(q, ascinode(tfa->addr,0x1f)); + q = xstrcat(q, (char *)"!"); + } + tidy_falist(&ftnpath); + + if (p) { + while (isspace(*p)) + p++; + q = xstrcat(q, p); + } else + q = xstrcat(q, (char *)"not-for-mail"); + Send(newsmode, "%s\n", q); + + if ((p = hdr((char *)"Newsgroups",msg))) { + /* + * The gate at puddle.fidonet.org put spaces in Newsgroups header + */ + if ((strstr(p,", "))) { + while ((r = strchr(p, ' '))) { + *r = '\0'; + strcat(p,r+1); + } + } + } + + if (p == NULL) + p=hdr((char *)"RFC-Newsgroups",kmsg); + if (p == NULL) + p=hdr((char *)"Newsgroups",kmsg); + if (p) { + while (*p && isspace(*p)) + p++; + Send(newsmode,"Newsgroups: %s\n",newsgroup); + Send(newsmode,"X-Origin-Newsgroups: %s",p); + } else + Send(newsmode,"Newsgroups: %s\n",newsgroup); + + if ((p=hdr((char *)"Distribution",msg))) + Send(newsmode,"Distribution:%s",p); + else if ((p=hdr((char *)"RFC-Distribution",kmsg))) + Send(newsmode,"Distribution: %s",p); + else if ((p=hdr((char *)"Distribution",kmsg))) + Send(newsmode,"Distribution: %s",p); + else if (distribution) + Send(newsmode,"Distribution: %s\n",distribution); + + p = hdr((char *)"Comment-To",msg); + if (p == NULL) + p=hdr((char *)"X-Comment-To",msg); + if (p == NULL) + p=hdr((char *)"To",msg); + if ((p) && (strcasecmp(p,"All\n"))) + Send(newsmode,"X-Comment-To:%s",hdrconv(p,outcode,incode)); + else { + if (p == NULL) + p=hdr((char *)"RFC-X-Comment-To",kmsg); + if (p == NULL) + p=hdr((char *)"RFC-Comment-To",kmsg); + if (p == NULL) + p=hdr((char *)"RFC-To",kmsg); + if ((p) && (strcasecmp(p,"All\n"))) + Send(newsmode,"X-Comment-To: %s",hdrconv(p,outcode,incode)); + else if ((t) && (t->name) && (strcasecmp(t->name,"All"))) + Send(newsmode,"X-Comment-To: %s\n",hdrconv(t->name,outcode,incode)); + else + Send(newsmode,"X-Comment-To: All\n"); + } + +// for (tmpml=approve;tmpml;tmpml=tmpml->next) { +// if ((strncmp(newsgroup,tmpml->prefix, strlen(tmpml->prefix)) == 0)) { +// modtype=2; +// moderator=xstrcpy(tmpml->address); +// break; +// } +// } + + if ((p=hdr((char *)"Approved",msg))) + Send(newsmode,"Approved:%s",p); + else if ((p=hdr((char *)"RFC-Approved",kmsg))) + Send(newsmode,"Approved: %s",p); + else if ((p=hdr((char *)"Approved",kmsg))) + Send(newsmode,"Approved: %s",p); + else if (modtype==2) + Send(newsmode,"Approved: %s\n",moderator); + + } else { /* if newsmode */ + time(&now); + if (CFG.EmailMode == E_NOISP) { + /* + * Probaly not needed as messages for systems without ISP never get here. + * Perhaps only news to moderators. + */ + Send(FALSE, "From: %s!", ascinode(f,0x3f)); + Send(FALSE, "%s %s", ascinode(f,0x40), ctime(&mdate)); + } + for (qmsg = kmsg; qmsg; qmsg = qmsg->next) + if (!strcasecmp(qmsg->key,"RFC-Received")) + Send(FALSE, "%s: %s", qmsg->key+4, qmsg->val); + for (qmsg = msg; qmsg; qmsg = qmsg->next) + if (!strcasecmp(qmsg->key,"Received")) + Send(FALSE, "%s:%s", qmsg->key, qmsg->val); + + if ((p=hdr((char *)"Apparently-To",msg))) + Send(FALSE, "Apparently-To: %s\n",p); + else if ((p=hdr((char *)"RFC-Apparently-To",kmsg))) + Send(FALSE, "Apparently-To: %s\n",p); + else if ((p=hdr((char *)"Apparently-To",kmsg))) + Send(FALSE, "Apparently-To: %s\n",p); + else if ((is_local(t))) + Send(FALSE, "Apparently-To: %s\n",buf); + + if (flags & M_RRQ) + rrq=TRUE; + else + rrq=FALSE; + if (rrq && !hdr((char *)"RFC-Return-Receipt-To",kmsg) && + !hdr((char *)"Return-Receipt-To",msg) && + !hdr((char *)"RFC-Notice-Requested-Upon-Delivery-To",kmsg) && + !hdr((char *)"Notice-Requested-Upon-Delivery-To",msg)) { + Send(FALSE,"Notice-Requested-Upon-Delivery-To: %s\n",buf); + } + + if (t->name == NULL) + t->name=xstrcpy((char *)"Postmaster"); + p=hdr((char *)"Resent-To",msg); + if (p == NULL) + p=hdr((char *)"To",msg); + if (p) { + Send(FALSE,"To:%s",p); + } else { + if (p == NULL) + p=hdr((char *)"RFC-Resent-To",kmsg); + if (p == NULL) + p=hdr((char *)"RFC-To",kmsg); + if (p) { + Syslog('m', "2"); + Send(FALSE,"To: %s\n",p); + } else if (modtype == 1) + Send(FALSE,"To: %s\n",moderator); + else if (is_local(t)) { + Syslog('m', "3"); + Send(FALSE, "To: %s <%s>\n", t->name, buf); + } else { + Syslog('m', "4"); + Send(FALSE,"To: %s\n",ascinode(t,0xff)); + } + } + } + + if ((p = hdr((char *)"From",msg))) { + if (!ftn_from) + Send(newsmode, "From:%s", hdrconv(p,outcode,incode)); + else + Send(newsmode, "From: %s\n",hdrconv(ascinode(f,0xff),outcode,incode)); + } else if ((p = hdr((char *)"RFC-From",kmsg))) { + Syslog('m', "b"); + Send(newsmode, "From: %s", hdrconv(p,outcode,incode)); + } else if ((p = hdr((char *)"From\n",kmsg))) { + Syslog('m', "c"); + Send(newsmode, "From: %s", hdrconv(p,outcode,incode)); + } else if ((p = hdr((char *)"X-PcBoard-FROM",msg))) { + if (f->name) { + while (isspace(*p)) + p++; + p[strlen(p)-1] = '\0'; + Send(newsmode,"From: %s <%s>\n", hdrconv(f->name,outcode,incode), p); + } else { + Send(newsmode,"From:%s\n", p); + } + } else if ((hdr((char *)"REPLYADDR",kmsg)) && (p=xstrcpy(hdr((char *)"REPLYADDR",kmsg)))) { + if (*(r=p+strlen(p)-1) == '\n') + *(r--)='\0'; + while (isspace(*r)) + *(r--)='\0'; + q=xstrcpy(hdr((char *)"X-RealName",msg)); + if (q == NULL) + q=xstrcpy(hdr((char *)"RealName",msg)); + if (q == NULL) + q=xstrcpy(hdr((char *)"X-RealName",kmsg)); + if (q == NULL) + q=xstrcpy(hdr((char *)"RealName",kmsg)); + if (q) { + if (*(r=q+strlen(q)-1) == '\n') + *(r--)='\0'; + while (isspace(*r)) + *(r--)='\0'; + for (l=q; isspace(*l); ) + l++; + if ((*l == '\"') && (*r == '\"')) { + l++; + *r--='\0'; + } + Syslog('m', "d"); + Send(newsmode,"From: \"%s\" <%s>\n",hdrconv(l,outcode,incode),p); + free(q); + } else if (f->name) { + Syslog('m', "e"); + Send(newsmode,"From: \"%s\" <%s>\n",hdrconv(f->name,outcode,incode),p); + } else { + Syslog('m', "f"); + Send(newsmode,"From: %s\n",p); + } + free(p); + } + + if (p) + Send(newsmode,"X-FTN-Sender: %s\n",hdrconv(ascinode(f,0xff),outcode,incode)); + else + Send(newsmode,"From: %s\n",hdrconv(ascinode(f,0xff),outcode,incode)); + + if ((p=hdr((char *)"Reply-To",msg))) + Send(newsmode,"Reply-To:%s",p); + else if ((p=hdr((char *)"RFC-Reply-To",kmsg))) + Send(newsmode,"Reply-To: %s",p); + else if ((p=hdr((char *)"Reply-To",kmsg))) + Send(newsmode,"Reply-To: %s",p); + else if (((p=backalias(f))) && strlen(CFG.sysdomain)) + Send(newsmode,"Reply-To: %s@%s\n",p,CFG.sysdomain); + else if ((p=hdr((char *)"REPLYADDR",kmsg))) + Send(newsmode,"Reply-To: %s",p); + else if ((p=hdr((char *)"REPLYTO",kmsg))) + Send(newsmode,"Reply-To: %s\n",ascinode(parsefaddr(p),0xff)); + + if ((p=hdr((char *)"Date",msg))) + Send(newsmode,"Date:%s",p); + else if ((p=hdr((char *)"RFC-Date",kmsg))) + Send(newsmode,"Date: %s",p); + else if ((p=hdr((char *)"Date",kmsg))) + Send(newsmode,"Date: %s",p); + else if (newsmode) { + /* + * Restamp future postings + */ + if(mdate > time(&now)) { + Syslog('+', "Future posting: %s", rfcdate(mdate)); + Send(newsmode,"Date: %s\n", rfcdate(now)); + Send(newsmode,"X-Origin-Date: %s\n", rfcdate(mdate)); + } else if((mdate < time(&now)-14*24*60*60) && (mdate > time(&now)-RESTAMP_OLD_POSTINGS*24*60*60)) { + /* + * Restamp old postings + */ + Syslog('+', "Article too old, restamped: %s", rfcdate(mdate)); + Send(newsmode,"Date: %s\n", rfcdate(now)); + Send(newsmode,"X-Origin-Date: %s\n", rfcdate(mdate)); + } else + Send(newsmode,"Date: %s\n",rfcdate(mdate)); + } else + Send(newsmode,"Date: %s\n",rfcdate(mdate)); + + if ((p = hdr((char *)"Subject",msg))) + Send(newsmode, "Subject:%s", hdrconv(p,outcode,incode)); + else if ((p = hdr((char *)"RFC-Subject",kmsg))) + Send(newsmode, "Subject: %s", hdrconv(p,outcode,incode)); + else if ((p = hdr((char *)"Subject",kmsg))) + Send(newsmode, "Subject: %s", hdrconv(p,outcode,incode)); + else if ((p = hdr((char *)"X-PcBoard-SUBJECT",msg))) + Send(newsmode, "Subject:%s", hdrconv(p,outcode,incode)); + else if (subj && (strspn(subj," \t\n\r") != strlen(subj))) + Send(newsmode, "Subject: %s\n", hdrconv(subj,outcode,incode)); + else + Send(newsmode, "Subject: \n"); + + if ((p=hdr((char *)"Message-ID",msg))) + Send(newsmode,"Message-ID:%s",p); + else if ((p=hdr((char *)"RFC-Message-ID",kmsg))) + Send(newsmode,"Message-ID: %s",p); + else if ((p=hdr((char *)"Message-ID",kmsg))) + Send(newsmode,"Message-ID: %s",p); + else if ((p=hdr((char *)"RFCID",kmsg))) + if ((p[0]=='<')) { + /* "^aRFCID: " */ + if ((p[strlen(p)-2]=='>')) + Send(newsmode,"Message-ID: %s",p); + /* "^aRFCID: \n",p); + } + } + /* "^aRFCID: local@machine" */ + else { + p[strlen(p)-1]='\0'; + Send(newsmode,"Message-ID: <%s>\n",p); + } else if ((p=hdr((char *)"ORIGID",kmsg))) + Send(newsmode,"Message-ID: %s",p); + else if ((p = hdr((char *)"MSGID",kmsg))) { + q = rfcmsgid(p, bestaka); + Send(newsmode,"Message-ID: %s\n", q); + free(q); + } else + Send(newsmode,"Message-ID: <%lu@%s.ftn>\n", mdate^(subj?str_crc32(subj):0L), ascinode(f,0x1f)); + + if (newsmode) { + if ((p=hdr((char *)"References",msg))) + Send(newsmode,"References:%s",p); + else if ((p=hdr((char *)"RFC-References",kmsg))) + Send(newsmode,"References: %s",p); + else if ((p=hdr((char *)"References",kmsg))) + Send(newsmode,"References: %s",p); + else if ((p=hdr((char *)"ORIGREF",kmsg))) + Send(newsmode,"References: %s",p); + else if ((p=hdr((char *)"REPLY",kmsg))) { + q = rfcmsgid(p, bestaka); + Send(newsmode,"References: %s\n", q); + free(q); + } + } else { + if ((p=hdr((char *)"In-Reply-To",msg))) + Send(newsmode,"In-Reply-To:%s",p); + else if ((p=hdr((char *)"RFC-In-Reply-To",kmsg))) + Send(newsmode,"In-Reply-To: %s",p); + else if ((p=hdr((char *)"REPLY",kmsg))) { + q = rfcmsgid(p,bestaka); + Send(newsmode,"In-Reply-To: %s\n", q); + free(q); + } + } + + if ((p=hdr((char *)"Organization",msg))) + Send(newsmode,"Organization:%s",hdrconv(p,outcode,incode)); + else if ((p=hdr((char *)"RFC-Organization",kmsg))) + Send(newsmode,"Organization: %s",hdrconv(p,outcode,incode)); + else if ((p=hdr((char *)"Organization",kmsg))) + Send(newsmode,"Organization: %s",hdrconv(p,outcode,incode)); + else if (origline) + Send(newsmode,"Organization: %s\n",hdrconv(origline,outcode,incode)); + + if ((p=hdr((char *)"Supersedes",msg))) + Send(newsmode,"Supersedes:%s",p); + else if ((p=hdr((char *)"RFC-Supersedes",kmsg))) + Send(newsmode,"Supersedes: %s",p); + else if ((p=hdr((char *)"Supersedes",kmsg))) + Send(newsmode,"Supersedes: %s",p); + else if ((p=hdr((char *)"ACUPDATE",kmsg)) && (strstr(p,"MODIFY"))) { + q = rfcmsgid(p+8,bestaka); + Send(newsmode,"Supersedes: %s\n", q); + free(q); + } + if (CFG.allowcontrol) { + if ((p=hdr((char *)"Control",msg))) + Send(newsmode,"Control:%s",p); + else if ((p=hdr((char *)"RFC-Control",kmsg))) + Send(newsmode,"Control: %s",p); + else if ((p=hdr((char *)"Control",kmsg))) + Send(newsmode,"Control: %s",p); + else if ((p=hdr((char *)"ACUPDATE",kmsg)) && (strstr(p,"DELETE"))) { + q = rfcmsgid(p+8,bestaka); + Send(newsmode,"Control: cancel %s\n", q); + free(q); + } + } + + Send(newsmode, "X-FTN-CHRS: %s\n", getchrs(incode)); + if (incode != outcode) + Send(newsmode, "X-FTN-ORIGCHRS: %s\n", getchrs(outcode)); + charset = getcharset(incode); + + if ((p=hdr((char *)"Mime-Version",msg))) + Send(newsmode,(char *)"Mime-Version:%s",p); + else if ((p=hdr((char *)"RFC-Mime-Version",kmsg))) + Send(newsmode,(char *)"Mime-Version: %s",p); + else if ((p=hdr((char *)"Mime-Version",kmsg))) + Send(newsmode,(char *)"Mime-Version: %s",p); + else if ((charset) && (incode != CHRS_NOTSET)) + Send(newsmode,"Mime-Version: 1.0\n"); + + temp[0] = '\0'; + if ((p=hdr((char *)"Content-Type",msg))) + Send(newsmode,"Content-Type:%s",p); + else if ((p=hdr((char *)"RFC-Content-Type",kmsg))) + Send(newsmode,"Content-Type: %s",p); + else if ((p=hdr((char *)"Content-Type",kmsg))) + Send(newsmode,"Content-Type: %s",p); + else if ((charset) && (incode != CHRS_NOTSET)) { + if ((p=hdr((char *)"FSCHTML",kmsg)) || (p=hdr((char *)"HTML",kmsg))) + Send(newsmode,"Content-Type: text/html; charset=%s\n",charset); + else + Send(newsmode,"Content-Type: text/plain; charset=%s\n",charset); + } + + if ((p=hdr((char *)"Content-Length",msg))) + Send(newsmode,"Content-Length%s",p); + else if ((p=hdr((char *)"RFC-Content-Length",kmsg))) + Send(newsmode,"Content-Length: %s",p); + else if ((p=hdr((char *)"Content-Length",kmsg))) + Send(newsmode,"Content-Length: %s",p); + + temp[0] = '\0'; + if ((p=hdr((char *)"Content-Transfer-Encoding",msg))) + sprintf(temp,"Content-Transfer-Encoding:%s",p); + else if ((p=hdr((char *)"RFC-Content-Transfer-Encoding",kmsg))) + sprintf(temp,"Content-Transfer-Encoding: %s",p); + else if ((p=hdr((char *)"Content-Transfer-Encoding",kmsg))) + sprintf(temp,"Content-Transfer-Encoding: %s",p); + else if ((charset) && (incode == CHRS_ISO_8859_1_QP)) + sprintf(temp,"Content-Transfer-Encoding: quoted-printable\n"); + else if ((charset) && (incode != CHRS_NOTSET)) { + if ((incode == CHRS_ASCII || incode == CHRS_UTF_7)) + sprintf(temp,"Content-Transfer-Encoding: 7bit\n"); + else if (strncasecmp(charset,"iso-2022-",9) == 0) + sprintf(temp,"Content-Transfer-Encoding: 7bit\n"); + else + sprintf(temp,"Content-Transfer-Encoding: 8bit\n"); /* all others are 8 bit */ + } + if (temp[0]) + Send(newsmode, temp); + + if (newsmode) { + if ((p=hdr((char *)"X-Newsreader",msg))) + Send(newsmode,"X-Newsreader: %s",p); + else if ((p=hdr((char *)"RFC-X-Newsreader",kmsg))) + Send(newsmode,"X-Newsreader: %s",p); + else if ((p=hdr((char *)"X-Newsreader",kmsg))) + Send(newsmode,"X-Newsreader: %s",p); + else if ((p=hdr((char *)"PID",kmsg))) + Send(newsmode,"X-Newsreader: %s",p); + } else { + if ((p=hdr((char *)"X-Mailer",msg))) + Send(newsmode,"X-Mailer:%s",p); + else if ((p=hdr((char *)"RFC-X-Mailer",kmsg))) + Send(newsmode,"X-Mailer: %s",p); + else if ((p=hdr((char *)"X-Mailer",kmsg))) + Send(newsmode,"X-Mailer: %s",p); + else if ((p=hdr((char *)"PID",kmsg))) + Send(newsmode,"X-Mailer: %s",p); + } + + for (qmsg=msg;qmsg;qmsg=qmsg->next) { + if (strcasecmp(qmsg->key,"X-Body-Start") && + strcasecmp(qmsg->key,"X-PcBoard-FROM") && + strcasecmp(qmsg->key,"X-PcBoard-SUBJECT") && + strcasecmp(qmsg->key,"X-PcBoard-PACKOUT") && + (strcasecmp(qmsg->key,"Control") || !CFG.allowcontrol) && + strcasecmp(qmsg->key,"Supersedes") && + strcasecmp(qmsg->key,"Mime-Version") && + strcasecmp(qmsg->key,"Content-Type") && + strcasecmp(qmsg->key,"Content-Lenght") && + strcasecmp(qmsg->key,"Content-Transfer-Encoding") && + strcasecmp(qmsg->key,"Lines") && + strcasecmp(qmsg->key,"Path") && + strcasecmp(qmsg->key,"Received") && + strcasecmp(qmsg->key,"From") && + strcasecmp(qmsg->key,"To") && + strcasecmp(qmsg->key,"Comment-To") && + strcasecmp(qmsg->key,"X-Comment-To") && + strcasecmp(qmsg->key,"Date") && + strcasecmp(qmsg->key,"Subject") && + strcasecmp(qmsg->key,"Reply-To") && + strcasecmp(qmsg->key,"In-Reply-To") && + strcasecmp(qmsg->key,"References") && + strcasecmp(qmsg->key,"Organization") && + strcasecmp(qmsg->key,"X-Mailer") && + strcasecmp(qmsg->key,"X-Newsreader") && + (strcasecmp(qmsg->key,"Newsgroups") || !newsmode) && + strcasecmp(qmsg->key,"Apparently-To") && + strcasecmp(qmsg->key,"Distribution") && + strcasecmp(qmsg->key,"Approved") && + strcasecmp(qmsg->key,"Message-ID")) + Send(newsmode,"%s:%s",qmsg->key,hdrconv(qmsg->val,outcode,incode)); + } + + if ((p=compose_flags(flags,hdr((char *)"FLAGS",kmsg)))) { + Send(newsmode,"X-FTN-FLAGS:%s\n",p); + free(p); + } + + for (qmsg=kmsg;qmsg;qmsg=qmsg->next) { + if (strcasecmp(qmsg->key,"INTL") && + strcasecmp(qmsg->key,"FMPT") && + strcasecmp(qmsg->key,"TOPT") && + strcasecmp(qmsg->key,"FLAGS") && + strcasecmp(qmsg->key,"CHARSET") && + strcasecmp(qmsg->key,"CHRS") && + strcasecmp(qmsg->key,"CODEPAGE") && + strcasecmp(qmsg->key,"ORIGCHRS") && + /* + * RFC: is used by fidogate to tell how completly RFC headers were + * gated (0=no headers at all; 1=some headers; 2=all headers) + */ + strcasecmp(qmsg->key,"RFC") && + strcasecmp(qmsg->key,"RFCID") && + strcasecmp(qmsg->key,"ORIGID") && + strcasecmp(qmsg->key,"ORIGREF") && + strcasecmp(qmsg->key,"X-GATEWAY") && + strcasecmp(qmsg->key,"Lines") && + /* strcmp(qmsg->key,"Path") && */ + strcasecmp(qmsg->key,"PATH") && + strcasecmp(qmsg->key,"Received") && + strcasecmp(qmsg->key,"From") && + strcasecmp(qmsg->key,"To") && + strcasecmp(qmsg->key,"Comment-To") && + strcasecmp(qmsg->key,"X-Comment-To") && + strcasecmp(qmsg->key,"Date") && + strcasecmp(qmsg->key,"Subject") && + strcasecmp(qmsg->key,"Reply-To") && + strcasecmp(qmsg->key,"In-Reply-To") && + strcasecmp(qmsg->key,"References") && + strcasecmp(qmsg->key,"Organization") && + strcasecmp(qmsg->key,"X-Mailer") && + strcasecmp(qmsg->key,"X-Newsreader") && + (strcasecmp(qmsg->key,"Newsgroups") || !newsmode) && + strcasecmp(qmsg->key,"Apparently-To") && + strcasecmp(qmsg->key,"Message-ID") && + strcasecmp(qmsg->key,"Mime-Version") && + strcasecmp(qmsg->key,"Content-Type") && + strcasecmp(qmsg->key,"Content-Lenght") && + strcasecmp(qmsg->key,"Content-Transfer-Encoding") && + (strcasecmp(qmsg->key,"RFC-Control") || !CFG.allowcontrol) && + strcasecmp(qmsg->key,"RFC-Supersedes") && + strcasecmp(qmsg->key,"RFC-Mime-Version") && + strcasecmp(qmsg->key,"RFC-Content-Type") && + strcasecmp(qmsg->key,"RFC-Content-Lenght") && + strcasecmp(qmsg->key,"RFC-Content-Transfer-Encoding") && + strcasecmp(qmsg->key,"RFC-Lines") && + strcasecmp(qmsg->key,"RFC-Path") && + strcasecmp(qmsg->key,"RFC-Received") && + strcasecmp(qmsg->key,"RFC-From") && + strcasecmp(qmsg->key,"RFC-To") && + strcasecmp(qmsg->key,"RFC-Comment-To") && + strcasecmp(qmsg->key,"RFC-X-Comment-To") && + strcasecmp(qmsg->key,"RFC-Date") && + strcasecmp(qmsg->key,"RFC-Subject") && + strcasecmp(qmsg->key,"RFC-Reply-To") && + strcasecmp(qmsg->key,"RFC-In-Reply-To") && + strcasecmp(qmsg->key,"RFC-References") && + strcasecmp(qmsg->key,"RFC-Organization") && + strcasecmp(qmsg->key,"RFC-X-Mailer") && + strcasecmp(qmsg->key,"RFC-X-Newsreader") && + (strcasecmp(qmsg->key,"RFC-Newsgroups") || !newsmode) && + strcasecmp(qmsg->key,"RFC-Apparently-To") && + strcasecmp(qmsg->key,"RFC-Distribution") && + strcasecmp(qmsg->key,"RFC-Approved") && + strcasecmp(qmsg->key,"RFC-Message-ID")) { + if (!strncmp(qmsg->key,"RFC-",4)) + Send(newsmode,"%s: %s",qmsg->key+4,hdrconv(qmsg->val,outcode,incode)); + else if ((!strncasecmp(qmsg->key,"X-",2)) || (!strncasecmp(qmsg->key,"NNTP-",5))) + Send(newsmode,"%s: %s",qmsg->key,hdrconv(qmsg->val,outcode,incode)); + else if ((!strncasecmp(qmsg->key,"ZC-",3))) + Send(newsmode,"X-%s: %s",qmsg->key,qmsg->val); + else if ((!strcasecmp(qmsg->key,"Origin")) || (!strcasecmp(qmsg->key,"MOOD"))) + Send(newsmode,"X-FTN-%s: %s",qmsg->key,hdrconv(qmsg->val,outcode,incode)); + else + Send(newsmode,"X-FTN-%s: %s",qmsg->key,qmsg->val); + } + } + + if (newsmode) { + fa_list *tmpl,*ptl=NULL; + char sbe[16]; + int seenlen=0,oldnet; + + for (qmsg = kmsg; qmsg; qmsg = qmsg->next) + if (!strcmp(qmsg->key, "PATH")) { + fill_path(&ptl, qmsg->val); + } + + uniq_list(&ptl); + + /* + * ensure it will not match for the first entry + */ + oldnet = ptl->addr->net-1; + q = xstrcpy((char*)"X-FTN-PATH:"); + for (tmpl = ptl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe," %u",tmpl->addr->node); + else + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + oldnet=tmpl->addr->net; + seenlen+=strlen(sbe); + if (seenlen > MAXPATH) { + seenlen=0; + Send(newsmode, "%s\n", q); + free(q); + q = xstrcpy((char *)"X-FTN-PATH:"); + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + seenlen=strlen(sbe); + } + q = xstrcat(q, sbe); + } + Send(newsmode,"%s\n", q); + free(q); + tidy_falist(&ptl); + + if ((hdr((char *)"X-FTN-SPTH", msg))) + Send(newsmode,"X-FTN-SPTH: %s\n", ascfnode(bestaka,0x1f)); + } + + /* + * Search past RFC headers. + */ + while (fgets(buf,sizeof(buf)-1,fp)) { + if ((strlen(buf) == 1) && (buf[0] == '\n')) { + break; + } + } + + /* + * Send the message body + */ + pass=1; + count = lines = 0; + first = TRUE; + + Syslog('M', "Start sending message body"); + while (fgets(buf,sizeof(buf)-1,fp) && pass) { + if (first) { + Send(newsmode, (char *)"\n"); + first = FALSE; + +/* FIXME: Maybe scan now for repeating headers and drop them as they will appear in the message text */ + + if ((p=hdr((char *)"X-Body-Start",msg))) { + lines++; + Send(newsmode, "%s", strkconv(p, outcode, incode)); + } + } + + if (ftell(fp) > endmsg_off) { + Syslog('M', "line \"%s\" past message end %ld %ld", buf,(long)endmsg_off, ftell(fp)); + pass=0; + } + if (pass) { + p=buf; + b=NULL; + while ((c=*p++)) { + switch (c) { + case ' ': b=p-1; break; + case '\n': b=NULL; count=0; lines++; break; + } + if ((count++ > BOUNDARY) && (!pgpsigned)) { + if (b) { + *b++='\r'; + *b = '\n'; + p=b+2; + b=NULL; + lines++; + count=0; + } + } + } + if (strncmp(buf, ".\r\n", 3)) + Send(newsmode, strkconv(buf, outcode, incode)); + else + Send(newsmode, (char *)" .\n"); + } + } + Syslog('M', "End sending message body"); + + if ((modtype==1) && (!hdr((char *)"Approved",msg)) && + (!hdr((char *)"RFC-Approved",kmsg)) && (!hdr((char *)"Approved",kmsg))) + newsmode = FALSE; + + tidyrfc(msg); + fclose(fp); + tidyrfc(kmsg); + + if (!newsmode) { + result = postemail(nfp, MailFrom, MailTo); + fclose(nfp); + } else { + news_in++; + /* + * The newsfile stays open and will be closed later after processing + * all echomail. + */ + fprintf(nfp, ".\n"); + } + +// if (p) Geeft segfault +// free(p); + if (newsgroup) + free(newsgroup); + if (distribution) + free(distribution); + if (moderator) + free(moderator); + free(temp); + return result; +} + + diff --git a/mbfido/mkrfcmsg.h b/mbfido/mkrfcmsg.h new file mode 100644 index 00000000..f8eafc5b --- /dev/null +++ b/mbfido/mkrfcmsg.h @@ -0,0 +1,8 @@ +#ifndef _MKRFCMSG_H +#define _MKRFCMSG_H + + +int mkrfcmsg(faddr *, faddr *, char *, char *, time_t, int, FILE *, off_t, int); + +#endif + diff --git a/mbfido/mover.c b/mbfido/mover.c new file mode 100644 index 00000000..35ecf4a0 --- /dev/null +++ b/mbfido/mover.c @@ -0,0 +1,73 @@ +/***************************************************************************** + * + * File ..................: mbfido/mover.c + * Purpose ...............: Bad file mover + * Last modification date : 02-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tic.h" +#include "mover.h" + + + +void mover(char *srcdir, char *fn) +{ + char *From, *To; + + From = calloc(128, sizeof(char)); + To = calloc(128, sizeof(char)); + + sprintf(From, "%s%s", srcdir, fn); + sprintf(To, "%s/%s", CFG.badtic, fn); + Syslog('!', "Moving %s to %s", From, To); + + if (mkdirs(To)) { + if (file_mv(From, To) != 0) + WriteError("$Failed to move %s to %s", From, To); + } + + free(From); + free(To); +} + + + +/* + * Move the file and .tic file to the bad directory + */ +void MoveBad() +{ + mover(TIC.Inbound, TIC.TicName); + mover(TIC.FilePath, TIC.TicIn.OrgName); +} + + diff --git a/mbfido/mover.h b/mbfido/mover.h new file mode 100644 index 00000000..2b1c7f60 --- /dev/null +++ b/mbfido/mover.h @@ -0,0 +1,10 @@ +#ifndef _MOVER_H +#define _MOVER_H + + +void mover(char *, char *); +void MoveBad(void); + + +#endif + diff --git a/mbfido/msgutil.c b/mbfido/msgutil.c new file mode 100644 index 00000000..0f3018f8 --- /dev/null +++ b/mbfido/msgutil.c @@ -0,0 +1,226 @@ +/***************************************************************************** + * + * File ..................: mbaff/msgutil.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 21-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "msgutil.h" + + +extern int do_quiet; /* Supress screen output */ + + +/* + * Translation table from Hi-USA-ANSI to Lo-ASCII + */ +char lotab[] = { +"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" +"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +"\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" +"\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" +"\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" +"\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" +"\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" +"\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" +"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" +"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" +"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" +"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" +"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" +"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" +"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" +"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" +}; + + + +void Msg_Id(fidoaddr aka) +{ + char *temp; + unsigned long crc = -1; + + temp = calloc(81, sizeof(char)); + sprintf(temp, "\001MSGID: %s %08lx", aka2str(aka), sequencer()); + MsgText_Add2(temp); + Msg.MsgIdCRC = upd_crc32(temp, crc, strlen(temp)); + Msg.ReplyCRC = 0xffffffff; + free(temp); +} + + + +void Msg_Pid(void) +{ + char *temp; + time_t tt; + + temp = calloc(81, sizeof(char)); + sprintf(temp, "\001PID: MBSE-FIDO %s", VERSION); + MsgText_Add2(temp); + sprintf(temp, "\001CHRS: %s", getchrs(msgs.Ftncode)); + (void)time(&tt); + sprintf(temp, "\001TZUTC: %s", gmtoffset(tt)); + MsgText_Add2(temp); + free(temp); +} + + + +void Msg_Top(void) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "System name %s", CFG.bbs_name); + MsgText_Add2(temp); + sprintf(temp, "Sysop %s", CFG.sysop_name); + MsgText_Add2(temp); + sprintf(temp, "Location %s", CFG.location); + MsgText_Add2(temp); + sprintf(temp, "Remark %s", CFG.comment); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) != NULL) { + + MsgText_Add2((char *)"Line Phone number Maximum speed Fidonet Flags"); + MsgText_Add2((char *)"---- -------------------- -------------------- -------------------------"); + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fp); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fp) == 1) { + if (((ttyinfo.type == POTS) || (ttyinfo.type == ISDN)) && + ttyinfo.available && strlen(ttyinfo.phone)) { + switch (ttyinfo.type) { + case POTS: sprintf(temp, "POTS %-20s %-20s %s", ttyinfo.phone, ttyinfo.speed, ttyinfo.flags); + break; + case ISDN: sprintf(temp, "ISDN %-20s %-20s %s", ttyinfo.phone, ttyinfo.speed, ttyinfo.flags); + break; + } + MsgText_Add2(temp); + } + } + + fclose(fp); + } + + MsgText_Add2((char *)""); + MsgText_Add2((char *)""); + free(temp); +} + + + +void Msg_Bot(fidoaddr UseAka, char *Org) +{ + char *temp, *aka; + + temp = calloc(81, sizeof(char)); + aka = calloc(40, sizeof(char)); + + MsgText_Add2((char *)""); + sprintf(temp, "With regards, %s", CFG.sysop_name); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + sprintf(temp, "--- MBSE BBS v%s (Linux)", VERSION); + MsgText_Add2(temp); + + if (UseAka.point) + sprintf(aka, "(%d:%d/%d.%d)", UseAka.zone, UseAka.net, UseAka.node, UseAka.point); + else + sprintf(aka, "(%d:%d/%d)", UseAka.zone, UseAka.net, UseAka.node); + + sprintf(temp, " * Origin: %s %s", Org, aka); + MsgText_Add2(temp); + free(aka); + free(temp); +} + + + +void CountPosted(char *Base) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r+")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, fp); + + while (fread(&msgs, msgshdr.recsize, 1, fp) == 1) { + if (msgs.Active && (strlen(Base) == strlen(msgs.Base)) && + (!strcmp(Base, msgs.Base))) { + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + fseek(fp, - msgshdr.recsize, SEEK_CUR); + fwrite(&msgs, msgshdr.recsize, 1, fp); + break; + } + fseek(fp, msgshdr.syssize, SEEK_CUR); + } + + fclose(fp); + } else { + WriteError("$Can't open %s", temp); + } + + free(temp); +} + + + +char *To_Low(char *inp, int High) +{ + static char temp[81]; + int i; + + memset(&temp, 0, sizeof(temp)); + sprintf(temp, "%s", inp); + + if (High) + return temp; + + for (i = 0; i < strlen(temp); i++) + temp[i] = lotab[temp[i] & 0xff]; + + return temp; +} + + diff --git a/mbfido/msgutil.h b/mbfido/msgutil.h new file mode 100644 index 00000000..12349cec --- /dev/null +++ b/mbfido/msgutil.h @@ -0,0 +1,13 @@ +#ifndef _MSGUTIL_H +#define _MSGUTIL_H + + +void Msg_Id(fidoaddr); +void Msg_Pid(void); +void Msg_Top(void); +void Msg_Bot(fidoaddr, char *); +void CountPosted(char *); +char *To_Low(char *, int); + +#endif + diff --git a/mbfido/newspost.c b/mbfido/newspost.c new file mode 100644 index 00000000..4629972d --- /dev/null +++ b/mbfido/newspost.c @@ -0,0 +1,232 @@ +/***************************************************************************** + * + * File ..................: mbfido/newspost.c + * Purpose ...............: Post newsarticles in temp newsfile. + * Last modification date : 21-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2801 + * Beekmansbos 10 Internet: mbroek@users.sourceforge.net + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "newspost.h" + + +extern FILE *nfp; +extern int newsopen; +extern int news_out; +extern int news_bad; + + + +int newspost(void) +{ + int start = TRUE; + char *buf, *p; + long curpos, count, seqnr; + FILE *ofp = NULL, *nb; + struct utsname utsbuf; + + if (newsopen) + fclose(nfp); + buf = calloc(10240, sizeof(char)); + + /* + * Now reopen the file for reading. If it fails and + * the file was original closed we leave quiet. + * If the file wasn't open previously but there is + * a file, try to post the articles. They may be + * still here if the newsserver wasn't available. + */ + sprintf(buf, "%s/tmp/newsout", getenv("MBSE_ROOT")); + if ((nfp = fopen(buf, "r")) == NULL) { + if (newsopen) + WriteError("$Can't reopen %s", buf); + free(buf); + return newsopen; + } + IsDoing("Post news"); + + if (CFG.newsfeed == FEEDINN) { + Syslog('+', "Posting news articles to the NNTP server"); + if (nntp_connect() == -1) { + free(buf); + return TRUE; + } + + while (fgets(buf, 10240, nfp)) { + if (start) { + if (nntp_cmd((char *)"POST\r\n", 340) != 0) { + WriteError("NNTP POST refused"); + free(buf); + return TRUE; + } + } + start = FALSE; + if (!strcmp(buf, ".\n")) { + if (nntp_cmd((char *)".\r\n", 240) == 0) { + news_out++; + } else { + WriteError("NNTP: refused article %d", news_out+1); + news_bad++; + } + start = TRUE; + } else { + /* + * Most NNTP servers like cr/lf after each line. + */ + Striplf(buf); + p = buf+strlen(buf); + *p++ = '\r'; + *p++ = '\n'; + *p = '\0'; + nntp_send(buf); + } + Nopper(); + } + nntp_close(); + } + + /* + * Create newsbatch file. + */ + if ((CFG.newsfeed == FEEDUUCP) || (CFG.newsfeed == FEEDRNEWS)) { + Syslog('n', "Building uncompressed batchfile"); + sprintf(buf, "%s/tmp/newsbatch", getenv("MBSE_ROOT")); + if ((ofp = fopen(buf, "w+")) == NULL) { + WriteError("$Can't create %s", buf); + free(buf); + fclose(nfp); + return TRUE; + } + buf = calloc(10240, sizeof(char)); + + count = curpos = 0; + while (feof(ofp) == 0) { + /* + * Count the total length of the message + */ + while (fgets(buf, 10240, nfp)) { + if (strcmp(buf, ".\n")) { + count += strlen(buf); + } else { + break; + } + } + if (!count) + break; + fseek(nfp, curpos, SEEK_SET); + fprintf(ofp, "#! rnews %ld\n", count); + while (fgets(buf, 10240, nfp)) { + if (strcmp(buf, ".\n")) { + fprintf(ofp, buf); + } else { + break; + } + } + news_out++; + curpos = ftell(nfp); + count = 0; + } + /* + * Rewind the newsbatch and leave it open. + */ + rewind(ofp); + } + + fclose(nfp); + newsopen = FALSE; + + /* + * Mode rnews, pipe just created newsbatch to rnews. + */ + if (CFG.newsfeed == FEEDRNEWS) { + if ((nb = (expipe(CFG.rnewspath, NULL, NULL))) == NULL) { + WriteError("Could not open (pip) output for %s", CFG.rnewspath); + newsopen = FALSE; + return TRUE; + } + while (fgets(buf, 10240, ofp)) { + fputs(buf, nb); + } + if (exclose(nb)) { + WriteError("Error closing pipe"); + newsopen = FALSE; + return TRUE; + } else + Syslog('+', "Articles send through %s", CFG.rnewspath); + fclose(ofp); + sprintf(buf, "%s/tmp/newsbatch", getenv("MBSE_ROOT")); + unlink(buf); + } + + /* + * Mode UUCP, create UUCP files. + */ + if (CFG.newsfeed == FEEDUUCP) { + seqnr = sequencer(); + memset(&utsbuf, 0, sizeof(utsbuf)); + if (uname(&utsbuf)) { + WriteError("Can't get system nodename"); + newsopen = FALSE; + return TRUE; + } + + sprintf(buf, "%s/C.%s%lx", CFG.rnewspath, CFG.nntpnode, seqnr); + if ((nb = fopen(buf, "a")) == NULL) { + WriteError("Can't create %s", buf); + newsopen = FALSE; + return TRUE; + } + seqnr = sequencer(); + fprintf(nb, "E D.%s%lx D.%s%lx news -C D.%s%lx 0666 \"\" 0 rnews\n", + utsbuf.nodename, seqnr, utsbuf.nodename, seqnr, utsbuf.nodename, seqnr); + fclose(nb); + sprintf(buf, "%s/D.%s%lx", CFG.rnewspath, utsbuf.nodename, seqnr); + if ((nb = fopen(buf, "a")) == NULL) { + WriteError("Can't create %s", buf); + newsopen = FALSE; + return TRUE; + } + while (fgets(buf, 10240, ofp)) { + fputs(buf, nb); + } + Syslog('+', "Articles placed in %s", CFG.rnewspath); + fclose(ofp); + sprintf(buf, "%s/tmp/newsbatch", getenv("MBSE_ROOT")); + unlink(buf); + } + + sprintf(buf, "%s/tmp/newsout", getenv("MBSE_ROOT")); + unlink(buf); + free(buf); + return FALSE; +} + + diff --git a/mbfido/newspost.h b/mbfido/newspost.h new file mode 100644 index 00000000..2117b755 --- /dev/null +++ b/mbfido/newspost.h @@ -0,0 +1,9 @@ +#ifndef _NEWSPOST_H +#define _NEWSPOST_H + + +int newspost(void); + + +#endif + diff --git a/mbfido/notify.c b/mbfido/notify.c new file mode 100644 index 00000000..9ddeadc9 --- /dev/null +++ b/mbfido/notify.c @@ -0,0 +1,170 @@ +/***************************************************************************** + * + * File ..................: mbfido/notify.c + * Purpose ...............: Write notify messages. + * Last modification date : 28-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbnode.h" +#include "filemgr.h" +#include "areamgr.h" +#include "sendmail.h" +#include "notify.h" + + + +extern int do_quiet; /* Quiet flag */ +int notify = 0; /* Nr of notify messages */ + + + +/* + * Write AreaMgr and FileMgr notify messages. + */ +int Notify(char *Options) +{ + short Zones = -1, Nets = -1, Nodes = -1, Points = -1; + short Lzone, Lnet; + FILE *np; + char *temp, Opt[44]; + int i; + + Syslog('+', "Notify \"%s\"", Options); + + if (!do_quiet) { + colour(9, 0); + printf("Writing notify messages\n"); + colour(3, 0); + } + + if (strlen(Options)) { + sprintf(Opt, "%s~", Options); + if (strchr(Opt, '.') != NULL) { + temp = strdup(strtok(Opt, ":")); + if (atoi(temp)) + Zones = atoi(temp); + temp = strdup(strtok(NULL, "/")); + if (strncmp(temp, "*", 1)) + Nets = atoi(temp); + temp = strdup(strtok(NULL, ".")); + if (strncmp(temp, "*", 1)) + Nodes = atoi(temp); + temp = strdup(strtok(NULL, "~")); + if (strncmp(temp, "*", 1)) + Points = atoi(temp); + else + Points = -1; + } else if (strchr(Opt, '/') != NULL) { + temp = strdup(strtok(Opt, ":")); + if (atoi(temp)) + Zones = atoi(temp); + temp = strdup(strtok(NULL, "/")); + if (strncmp(temp, "*", 1)) + Nets = atoi(temp); + temp = strdup(strtok(NULL, "~")); + if (strncmp(temp, "*", 1)) { + Nodes = atoi(temp); + Points = 0; + } + } else if (strchr(Opt, ':') != NULL) { + temp = strdup(strtok(Opt, ":")); + if (atoi(temp)) + Zones = atoi(temp); + temp = strdup(strtok(NULL, "~")); + if (strncmp(temp, "*", 1)) + Nets = atoi(temp); + } else { + temp = strdup(strtok(Opt, "~")); + if (atoi(temp)) + Zones = atoi(temp); + } + } + Syslog('m', "Parsing nodes %d:%d/%d.%d", Zones, Nets, Nodes, Points); + + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((np = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + return FALSE; + } + fread(&nodeshdr, sizeof(nodeshdr), 1, np); + + while (fread(&nodes, nodeshdr.recsize, 1, np) == 1) { + Lzone = Lnet = 0; + for (i = 0; i < 20; i++) { + if ((((Zones == -1) && nodes.Notify) || (Zones == nodes.Aka[i].zone)) && + (((Nets == -1) && nodes.Notify) || (Nets == nodes.Aka[i].net)) && + (((Nodes == -1) && nodes.Notify) || (Nodes == nodes.Aka[i].node)) && + (((Points == -1) && nodes.Notify) || (Points == nodes.Aka[i].point)) && + (nodes.Aka[i].zone) && + ((Lzone != nodes.Aka[i].zone) || + (Lnet != nodes.Aka[i].net))) { + Lzone = nodes.Aka[i].zone; + Lnet = nodes.Aka[i].net; + + Syslog('m', "Notify to %s", aka2str(nodes.Aka[i])); + if (!do_quiet) { + printf("\rNotify %-24s", aka2str(nodes.Aka[i])); + fflush(stdout); + } + + if (i == 0) { + F_Status(fido2faddr(nodes.Aka[i])); + A_Status(fido2faddr(nodes.Aka[i])); + } + F_List(fido2faddr(nodes.Aka[i]), TRUE); + A_List(fido2faddr(nodes.Aka[i]), TRUE); + A_Flow(fido2faddr(nodes.Aka[i]), TRUE); + notify++; + } + } + fseek(np, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + } + + fclose(np); + free(temp); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + if (notify) + return TRUE; + else + return FALSE; +} + + + diff --git a/mbfido/notify.h b/mbfido/notify.h new file mode 100644 index 00000000..af6eb3de --- /dev/null +++ b/mbfido/notify.h @@ -0,0 +1,9 @@ +#ifndef _NOTIFY_H +#define _NOTIFY_H + + +int Notify(char *); + + +#endif + diff --git a/mbfido/pack.c b/mbfido/pack.c new file mode 100644 index 00000000..19cf1417 --- /dev/null +++ b/mbfido/pack.c @@ -0,0 +1,416 @@ +/***************************************************************************** + * + * File ..................: tosser/pack.c + * Purpose ...............: Pack mail + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbftn.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "pack.h" + + +extern int do_quiet; /* Quiet flag */ + + +/* + * Pack queued arcmail mail for a node. If the node is locked, the mail won't + * be packed, and the queue stays as it is. The mail will then be packed + * on a next run. + */ +int pack_queue(char *name) +{ + FILE *fp; + faddr noden; + fidoaddr nodenr; + char flavor, nr, oldnr, maxnr; + char srcfile[128], *arcfile, *pktfile; + int Attach, fage; + long fsize; + time_t Now; + + sprintf(srcfile, "%s", name); + + /* + * Get the nodenumber from the filename + */ + noden.domain = NULL; + noden.name = NULL; + noden.zone = atoi(strtok(name, ".")); + noden.net = atoi(strtok(NULL, ".")); + noden.node = atoi(strtok(NULL, ".")); + noden.point = atoi(strtok(NULL, ".")); + if (SearchFidonet(noden.zone)) + noden.domain = xstrcpy(fidonet.domain); + + memset(&nodenr, 0, sizeof(nodenr)); + nodenr.zone = noden.zone; + nodenr.net = noden.net; + nodenr.node = noden.node; + nodenr.point = noden.point; + sprintf(nodenr.domain, "%s", noden.domain); + + if (!SearchNode(nodenr)) { + WriteError("Downlink %s not found", aka2str(nodenr)); + if (noden.domain) + free(noden.domain); + return FALSE; + } + + /* + * If we route via another aka, change everything. + */ + if (nodes.RouteVia.zone) { + Syslog('p', "Route Via %s", aka2str(nodes.RouteVia)); + noden.zone = nodes.RouteVia.zone; + noden.net = nodes.RouteVia.net; + noden.node = nodes.RouteVia.node; + noden.point = nodes.RouteVia.point; + if (noden.domain) + free(noden.domain); + noden.domain = xstrcpy(nodes.RouteVia.domain); + /* + * Load routevia noderecord to get the correct flavor. + * If there is no noderecord, reload the old one. + */ + if (!SearchNode(nodes.RouteVia)) + SearchNode(nodenr); + } + + Syslog('+', "Pack ARCmail for %s, via %s", aka2str(nodenr), ascfnode(&noden, 0x1f)); + + if (!do_quiet) { + printf("\rAdding ARCmail for %s ", ascfnode(&noden, 0x1f)); + fflush(stdout); + } + + if (getarchiver((char *)"ZIP")) { + flavor = 'f'; + if (nodes.Crash) + flavor = 'c'; + if (nodes.Hold) + flavor = 'h'; + } else { + WriteError("Archiver ZIP not found"); + return FALSE; + } + + /* + * Generate ARCmail filename and .PKT filename, + */ + arcfile = calloc(128, sizeof(char)); + sprintf(arcfile, "%s", arcname(&noden, nodes.Aka[0].zone, nodes.ARCmailCompat)); + pktfile = calloc(40, sizeof(char)); + sprintf(pktfile, "%08lx.pkt", sequencer()); + + if (nodelock(&noden)) { + WriteError("Node %s lock error", ascfnode(&noden, 0x1f)); + if (noden.domain) + free(noden.domain); + free(arcfile); + free(pktfile); + return FALSE; + } + + if (rename(srcfile, pktfile)) { + WriteError("$Can't rename %s to %s", srcfile, pktfile); + nodeulock(&noden); + if (noden.domain) + free(noden.domain); + free(arcfile); + free(pktfile); + return FALSE; + } + + /* + * Add zero word at the end of the .pkt file + */ + if ((fp = fopen(pktfile, "a+")) == NULL) { + WriteError("$Can't open %s", pktfile); + nodeulock(&noden); + if (noden.domain) + free(noden.domain); + free(arcfile); + free(pktfile); + return FALSE; + } + putc('\0', fp); + putc('\0', fp); + fsync(fileno(fp)); + fclose(fp); + + /* + * Check the size of the existing archive if there is a size limit. + * Change to new archive names if the existing is too large. + * If the archive size is zero, it's an already sent archive, the + * number will be bumped also. + * If the archive is older then 6 days, the name is also bumped. + * Do this until we find a new name or if the last digit is a '9' or 'z'. + * Purge archives older then toss_days. + */ + nr = oldnr = '0'; + Now = time(NULL); + if (nodes.ARCmailAlpha) + maxnr = 'z'; + else + maxnr = '9'; + Attach = FALSE; + + for (;;) { + fsize = file_size(arcfile); + fage = (int)((Now - file_time(arcfile)) / 86400); + + if (fsize == -1L) { + Attach = TRUE; + break; + } + + if (fsize == 0L) { + if ((fage > 6) && (nr < maxnr)) { + /* + * Remove truncated ARCmail files older then 6 days. + */ + unlink(arcfile); + fsize = -1L; + Attach = TRUE; + break; + } + /* + * Increase filename extension if there is a truncated file of today. + */ + nr++; + if (nr == ('9' +1)) + nr = 'a'; + arcfile[strlen(arcfile) -1] = nr; + + } else if (CFG.maxarcsize && (fsize > (CFG.maxarcsize * 1024)) && (nr < maxnr)) { + /* + * Use a new ARCmail file if the last one is too big. + */ + nr++; + if (nr == ('9' +1)) + nr = 'a'; + arcfile[strlen(arcfile) -1] = nr; + } + + fsize = file_size(arcfile); + fage = (int)((Now - file_time(arcfile)) / 86400); + + if ((fsize > 0L) && (fage > 6) && (nr < maxnr)) { + /* + * If there is ARCmail of a week old or older, add mail + * to a new ARCmail bundle. + */ + nr++; + if (nr == ('9' +1)) + nr = 'a'; + arcfile[strlen(arcfile) -1] = nr; + } + + if (oldnr == nr) + break; + else + oldnr = nr; + } + + fsize = file_size(arcfile); + if (execute(archiver.marc, arcfile, pktfile, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) + unlink(pktfile); + + /* + * Attach file to .flo + */ + if (Attach) + attach(noden, arcfile, TFS, flavor); + + nodeulock(&noden); + if (noden.domain) + free(noden.domain); + free(arcfile); + free(pktfile); + return TRUE; +} + + + +/* + * Add queued unpacked mail for a node. If the node is locked, the mail + * stays in the queue. + */ +int add_queue(char *name) +{ + faddr noden; + char flavor; + char srcfile[128], *outfile; + char *buf; + FILE *inf, *ouf; + int bread; + + sprintf(srcfile, "%s", name); + + /* + * Get the nodenumber from the filename + */ + noden.domain = NULL; + noden.name = NULL; + noden.zone = atoi(strtok(name, ".")); + noden.net = atoi(strtok(NULL, ".")); + noden.node = atoi(strtok(NULL, ".")); + noden.point = atoi(strtok(NULL, ".")); + if (SearchFidonet(noden.zone)) + noden.domain = xstrcpy(fidonet.domain); + + Syslog('+', "Add Netmail for %s", ascfnode(&noden, 0x1f)); + if (!do_quiet) { + printf("\rAdding Netmail for %s ", ascfnode(&noden, 0x1f)); + fflush(stdout); + } + + outfile = calloc(128, sizeof(char)); + if (strstr(srcfile, ".iii")) + flavor = 'i'; + else if (strstr(srcfile, ".ccc")) + flavor = 'c'; + else if (strstr(srcfile, ".hhh")) + flavor = 'h'; + else + flavor = 'f'; + sprintf(outfile, "%s", pktname(&noden, flavor)); + Syslog('p', "Outfile: %s", outfile); + + if (nodelock(&noden)) { + WriteError("Node %s lock error", ascfnode(&noden, 0x1f)); + free(outfile); + if (noden.domain) + free(noden.domain); + return FALSE; + } + + /* + * Now we must see if there is already mail in the outbound. + * If that's the case, we must skip the .pkt header from the queue + * because there is already a .pkt header also, append to the + * outbound 2 bytes before the end of file, this is the zero word. + */ + if ((inf = fopen(srcfile, "r")) != NULL) { + if (access(outfile, R_OK) == -1) { + ouf = fopen(outfile, "w"); /* create new */ + Syslog('p', "Create new %s", outfile); + } else { + ouf = fopen(outfile, "r+"); /* open R/W */ + fseek(ouf, -2, SEEK_END); /* b4 0 word */ + fseek(inf, 58, SEEK_SET); /* skip header */ + Syslog('p', "Append to %s", outfile); + } + if (ouf != NULL) { + buf = malloc(16384); + + do { + bread = fread(buf, 1, 16384, inf); + fwrite(buf, 1, bread, ouf); + } while (bread); + + free(buf); + putc('\0', ouf); + putc('\0', ouf); + fsync(fileno(ouf)); + fclose(ouf); + fclose(inf); + unlink(srcfile); + } else { + WriteError("$Can't open %s", outfile); + fclose(inf); + } + } + + nodeulock(&noden); + if (noden.domain) + free(noden.domain); + free(outfile); + return TRUE; +} + + + +/* + * Pack mailqueue file(s) in the $MBSE_ROOT/tmp directory. + */ +void packmail() +{ + char *temp; + struct dirent *de; + DIR *dp; + + IsDoing("Packing mail"); + if (!do_quiet) { + colour(9, 0); + printf("Packing mail\n"); + colour(3, 0); + } + + temp = calloc(129, sizeof(char)); + sprintf(temp, "%s/tmp", getenv("MBSE_ROOT")); + + if (chdir(temp) == -1) { + WriteError("$Error chdir to %s", temp); + free(temp); + return; + } + + if ((dp = opendir(temp)) == NULL) { + WriteError("$Error opendir %s", temp); + free(temp); + return; + } + + /* + * Scan the $MBSE_ROOT/tmp directory for .qqq or .nnn files + */ + while ((de = readdir(dp))) { + if (strstr(de->d_name, ".qqq")) + pack_queue(de->d_name); + if (strstr(de->d_name, ".nnn") || strstr(de->d_name, ".iii") || + strstr(de->d_name, ".ccc") || strstr(de->d_name, ".hhh")) + add_queue(de->d_name); + } + + closedir(dp); + free(temp); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } +} + + + diff --git a/mbfido/pack.h b/mbfido/pack.h new file mode 100644 index 00000000..b2a4f635 --- /dev/null +++ b/mbfido/pack.h @@ -0,0 +1,11 @@ +#ifndef _PACK_H +#define _PACK_H + + +int pack_queue(char *); +int add_queue(char *); +void packmail(void); + + +#endif + diff --git a/mbfido/paths.h.in b/mbfido/paths.h.in new file mode 100644 index 00000000..46ab79c9 --- /dev/null +++ b/mbfido/paths.h.in @@ -0,0 +1,7 @@ +/* + Autogenerated by configure + */ +#define _PATH_COMPRESS "@COMPRESS@" +#define _PATH_GZIP "@GZIP@" + + diff --git a/mbfido/ping.c b/mbfido/ping.c new file mode 100644 index 00000000..ad6a41a6 --- /dev/null +++ b/mbfido/ping.c @@ -0,0 +1,149 @@ +/***************************************************************************** + * + * File ..................: mbfido/ping.c + * Purpose ...............: Ping Service + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbtic.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "sendmail.h" +#include "mgrutil.h" +#include "postnetmail.h" +#include "ping.h" + + + +/* + * External declarations + */ +extern int do_quiet; + + + +/* + * Global variables + */ +extern int net_in; /* Netmails received */ +extern int net_out; /* Netmails forwarded */ +extern int net_bad; /* Bad netmails (tracking errors */ +extern char *subj; /* Message subject */ +extern char *msgid; /* Original message id */ + + + +int Ping(faddr *f, faddr *t, FILE *fp, int intransit) +{ + int rc = 0; + char *Buf; + FILE *np; + time_t Now; + faddr *from; + + Now = time(NULL); + if (SearchFidonet(f->zone)) + f->domain = xstrcpy(fidonet.domain); + + Syslog('+', "%s ping msg from %s", intransit ? "Intransit":"Final", ascfnode(f, 0xff)); + Buf = calloc(2049, sizeof(char)); + rewind(fp); + + np = tmpfile(); + from = bestaka_s(f); + if (intransit) { + from->name = xstrcpy((char *)"Ping TRACE service"); + } else { + from->zone = t->zone; + from->net = t->net; + from->node = t->node; + from->point = t->point; + from->name = xstrcpy((char *)"Ping service"); + } + + if (f->point) + fprintf(np, "\001TOPT %d\r", f->point); + if (from->point) + fprintf(np, "\001FMPT %d\r", from->point); + fprintf(np, "\001INTL %d:%d/%d %d:%d/%d\r", f->zone, f->net, f->node, from->zone, from->net, from->node); + + /* + * Add MSGID, REPLY and PID + */ + fprintf(np, "\001MSGID: %s %08lx\r", ascfnode(from, 0x1f), sequencer()); + while ((fgets(Buf, 2048, fp)) != NULL) { + Striplf(Buf); + if (strncmp(Buf, "\001MSGID:", 7) == 0) { + fprintf(np, "\001REPLY:%s\r", Buf+7); + } + } + fprintf(np, "\001PID: MBSE-FIDO %s\r", VERSION); + fprintf(np, "\001TZUTC: %s\r", gmtoffset(Now)); + + fprintf(np, " Dear %s\r\r", MBSE_SS(f->name)); + if (intransit) { + fprintf(np, "You did send a PING to %s\r", ascfnode(t, 0x1f)); + fprintf(np, "This is a TRACE response from \"%s\" aka %s\r", CFG.bbs_name, ascfnode(from, 0x1f)); + fprintf(np, "The time of arrival is %s\r", rfcdate(Now)); + } else + fprintf(np, "Your Ping arrived here at %s\r", rfcdate(Now)); + fprintf(np, "Here are all the detected Via lines of the message from you:\r\r"); + fprintf(np, "======================================================================\r"); + + rewind(fp); + while ((fgets(Buf, 2048, fp)) != NULL) { + Striplf(Buf); + if (strncmp(Buf, "\1Via", 4) == 0) { + fprintf(np, "%s\r", Buf+1); + } + } + fprintf(np, "======================================================================\r"); + + fprintf(np, "\rWith regards, %s\r\r", CFG.sysop_name); + fprintf(np, "--- MBSE BBS v%s (Linux)\r", VERSION); + + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + rc = postnetmail(np, from, f, NULL, (char *)"Re: Ping", Now, 0x0000, FALSE); + tidy_faddr(from); + + fclose(np); + + free(Buf); + return rc; +} + + diff --git a/mbfido/ping.h b/mbfido/ping.h new file mode 100644 index 00000000..182ee991 --- /dev/null +++ b/mbfido/ping.h @@ -0,0 +1,9 @@ +#ifndef _PINGMGR_H +#define _PINGMGR_H + + +int Ping(faddr *, faddr *, FILE *, int); + + +#endif + diff --git a/mbfido/post.c b/mbfido/post.c new file mode 100644 index 00000000..b12db6d3 --- /dev/null +++ b/mbfido/post.c @@ -0,0 +1,245 @@ +/***************************************************************************** + * + * File ..................: mbfido/post.c + * Purpose ...............: Post a message from a file. + * Last modification date : 20-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "post.h" + + +extern int do_quiet; /* Supress screen output */ + + + +void Post(char *To, long Area, char *Subj, char *File, char *Flavor) +{ + int i, rc = FALSE; + char *aka, *temp, *sAreas; + FILE *fp, *tp; + unsigned long crc = -1; + time_t tt; + struct tm *t; + + + if (!do_quiet) { + colour(3, 0); + printf("Post \"%s\" to \"%s\" in area %ld\n", File, To, Area); + } + + IsDoing("Posting"); + Syslog('+', "Post \"%s\" area %ld to \"%s\" flavor %s", File, Area, To, Flavor); + Syslog('+', "Subject: \"%s\"", Subj); + + if ((tp = fopen(File, "r")) == NULL) { + WriteError("$Can't open %s", File); + return; + } + + sAreas = calloc(128, sizeof(char)); + sprintf(sAreas, "%s//etc/mareas.data", getenv("MBSE_ROOT")); + if ((fp = fopen(sAreas, "r")) == NULL) { + WriteError("$Can't open %s", sAreas); + free(sAreas); + fclose(tp); + return; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fp); + if (fseek(fp, (msgshdr.recsize + msgshdr.syssize) * (Area - 1), SEEK_CUR) == 0) { + if (fread(&msgs, msgshdr.recsize, 1, fp) == 1) { + rc = TRUE; + } else { + WriteError("$Can't read area %ld", Area); + } + } else { + WriteError("$Can't seek area %ld", Area); + } + + free(sAreas); + if (rc == FALSE) { + fclose(fp); + fclose(tp); + return; + } + + if (!msgs.Active) { + WriteError("Area %s not active", msgs.Name); + fclose(fp); + fclose(tp); + return; + } + + if (!Msg_Open(msgs.Base)) { + WriteError("Can't open %s", msgs.Base); + fclose(fp); + fclose(tp); + return; + } + + if (!Msg_Lock(30L)) { + WriteError("Can't lock %s", msgs.Base); + Msg_Close(); + fclose(fp); + fclose(tp); + return; + } + + (void)time(&tt); + t = localtime(&tt); + Diw = t->tm_wday; + Miy = t->tm_mon; + memset(&Msg, 0, sizeof(Msg)); + Msg_New(); + + /* + * Update statistic counter for message area + */ + fseek(fp, - msgshdr.recsize, SEEK_CUR); + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + fwrite(&msgs, msgshdr.recsize, 1, fp); + fclose(fp); + + /* + * Start writing the message + */ + sprintf(Msg.From, CFG.sysop_name); + sprintf(Msg.To, To); + + /* + * If netmail, clean the To field. + */ + if ((msgs.Type == NETMAIL) && strchr(To, '@')) { + for (i = 0; i < strlen(Msg.To); i++) { + if (Msg.To[i] == '_') + Msg.To[i] = ' '; + if (Msg.To[i] == '@') { + Msg.To[i] = '\0'; + break; + } + } + } + + sprintf(Msg.Subject, "%s", Subj); + sprintf(Msg.FromAddress, "%s", aka2str(msgs.Aka)); + Msg.Written = time(NULL); + Msg.Arrived = time(NULL); + Msg.Local = TRUE; + + if (strchr(Flavor, 'c')) + Msg.Crash = TRUE; + if (strchr(Flavor, 'p')) + Msg.Private = TRUE; + if (strchr(Flavor, 'h')) + Msg.Hold = TRUE; + + switch (msgs.Type) { + case LOCALMAIL: + Msg.Localmail = TRUE; + break; + + case NETMAIL: + Msg.Netmail = TRUE; + sprintf(Msg.ToAddress, "%s", ascfnode(parsefaddr(To), 0xff)); + break; + + case ECHOMAIL: + Msg.Echomail = TRUE; + break; + + case NEWS: + Msg.News = TRUE; + break; + } + + temp = calloc(128, sizeof(char)); + sprintf(temp, "\001MSGID: %s %08lx", aka2str(msgs.Aka), sequencer()); + MsgText_Add2(temp); + Msg.MsgIdCRC = upd_crc32(temp, crc, strlen(temp)); + Msg.ReplyCRC = 0xffffffff; + sprintf(temp, "\001PID: MBSE-FIDO %s", VERSION); + MsgText_Add2(temp); + sprintf(temp, "\001CHRS: %s", getchrs(msgs.Ftncode)); + MsgText_Add2(temp); + sprintf(temp, "\001TZUTC: %s", gmtoffset(tt)); + MsgText_Add2(temp); + + /* + * Add the file as text + */ + Msg_Write(tp); + fclose(tp); + + /* + * Finish the message + */ + aka = calloc(40, sizeof(char)); + MsgText_Add2((char *)""); + sprintf(temp, "--- MBSE BBS v%s (Linux)", VERSION); + MsgText_Add2(temp); + + if (msgs.Aka.point) + sprintf(aka, "(%d:%d/%d.%d)", msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node, msgs.Aka.point); + else + sprintf(aka, "(%d:%d/%d)", msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node); + + if (strlen(msgs.Origin)) + sprintf(temp, " * Origin: %s %s", msgs.Origin, aka); + else + sprintf(temp, " * Origin: %s %s", CFG.origin, aka); + + MsgText_Add2(temp); + free(aka); + + Msg_AddMsg(); + Msg_UnLock(); + Syslog('+', "Posted message %ld", Msg.Id); + + sprintf(temp, "%s/tmp/%smail.jam", getenv("MBSE_ROOT"), (msgs.Type == ECHOMAIL) ? "echo" : "net"); + if ((fp = fopen(temp, "a")) != NULL) { + fprintf(fp, "%s %lu\n", msgs.Base, Msg.Id); + fclose(fp); + } + free(temp); + Msg_Close(); + CreateSema((char *)"mailout"); + + return; +} + + diff --git a/mbfido/post.h b/mbfido/post.h new file mode 100644 index 00000000..abab25f5 --- /dev/null +++ b/mbfido/post.h @@ -0,0 +1,9 @@ +#ifndef _POST_H +#define _POST_H + + +void Post(char *, long, char *, char *, char *); /* Post a Message */ + + +#endif + diff --git a/mbfido/postemail.c b/mbfido/postemail.c new file mode 100644 index 00000000..a1d52d2b --- /dev/null +++ b/mbfido/postemail.c @@ -0,0 +1,122 @@ +/***************************************************************************** + * + * File ..................: mbfido/postemail.c + * Purpose ...............: Post Email message from temp file + * Last modification date : 06-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/dbuser.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "postemail.h" + + +/* + * Global variables + */ +extern int email_in; /* Total emails processed */ +extern int email_imp; /* Netmails imported */ +extern int email_bad; /* Bad netmails */ + + + +/* + * Post email message + * + * 0 - All seems well. + * 1 - Something went wrong. + * 2 - SMTP error. + * + */ +int postemail(FILE *fp, char *MailFrom, char *MailTo) +{ + char *temp, *p; + char buf[4096]; + int result = 1; + + temp = calloc(2048, sizeof(char)); + rewind(fp); + + Syslog('+', "SMTP: posting from %s to %s", MailFrom, MailTo); + if (smtp_connect() == -1) { + WriteError("SMTP: connection refused"); + return 2; + } + + sprintf(temp, "MAIL FROM: <%s>\r\n", MailFrom); + if (smtp_cmd(temp, 250)) { + WriteError("SMTP: refused FROM <%s>", MailFrom); + return 2; + } + + sprintf(temp, "RCPT TO: <%s>\r\n", MailTo); + if (smtp_cmd(temp, 250)) { + WriteError("SMTP: refused TO <%s>", MailTo); + return 2; + } + + if (smtp_cmd((char *)"DATA\r\n", 354)) { + WriteError("SMTP refused DATA mode"); + return 2; + } + + while ((fgets(buf, sizeof(buf)-2, fp)) != NULL) { + if (strncmp(buf, ".\r\n", 3)) { + p = buf+strlen(buf)-1; + if (*p == '\n') { + *p++ = '\r'; + *p++ = '\n'; + *p = '\0'; + } + smtp_send(buf); + } else { + sprintf(temp, " .\r\n"); + smtp_send(temp); + } + } + + email_in++; + if (smtp_cmd((char *)".\r\n", 250) == 0) { + Syslog('+', "SMTP: Message accepted"); + result = 0; + email_imp++; + } else { + WriteError("SMTP: refused message"); + email_bad++; + } + + free(temp); + smtp_close(); + + return result; +} + + diff --git a/mbfido/postemail.h b/mbfido/postemail.h new file mode 100644 index 00000000..07ce68de --- /dev/null +++ b/mbfido/postemail.h @@ -0,0 +1,8 @@ +#ifndef _POSTEMAIL_H +#define _POSTEMAIL_H + + +int postemail(FILE *, char *, char *); + +#endif + diff --git a/mbfido/postnetmail.c b/mbfido/postnetmail.c new file mode 100644 index 00000000..b0448f33 --- /dev/null +++ b/mbfido/postnetmail.c @@ -0,0 +1,316 @@ +/***************************************************************************** + * + * File ..................: mbfido/postnetmail.c + * Purpose ...............: Post Netmail message from temp file + * Last modification date : 21-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/dbcfg.h" +#include "../lib/dbuser.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tracker.h" +#include "addpkt.h" +#include "importnet.h" +#include "mkrfcmsg.h" +#include "areamgr.h" +#include "filemgr.h" +#include "ping.h" +#include "postemail.h" + + + +/* + * Global variables + */ +extern int net_in; /* Total netmails processed */ +extern int net_out; /* Netmails exported */ +extern int net_imp; /* Netmails imported */ +extern int net_bad; /* Bad netmails */ +extern int most_debug; /* Headvy debugging flag */ + + + +/* + * Post netmail message for temp file. The tempfile is an FTN style message. + * + * 0 - All seems well. + * 1 - Something went wrong. + * + */ +int postnetmail(FILE *fp, faddr *f, faddr *t, char *orig, char *subject, time_t mdate, int flags, int DoPing) +{ + char *p, *reply = NULL; + char name[36], *buf; + char System[36], ext[4]; + int result = 1, email = FALSE; + faddr *ta, *ra; + fidoaddr na, route, Orig; + FILE *sfp, *net; + time_t now; + struct tm *tm; + + Syslog('m', "Post netmail from: %s", ascfnode(f, 0xff)); + Syslog('m', "Post netmail to : %s", ascfnode(t, 0xff)); + Syslog('m', "Post netmail subj: %s", MBSE_SS(subject)); + net_in++; + + memset(&na, 0, sizeof(na)); + na.zone = t->zone; + na.net = t->net; + na.node = t->node; + na.point = t->point; + if (SearchFidonet(na.zone)) + sprintf(na.domain, "%s", fidonet.domain); + + switch(TrackMail(na, &route)) { + case R_LOCAL: + /* + * Check the To: field. + */ + if (strchr(t->name, '@') != NULL) { + sprintf(name, "%s", strtok(t->name, "@")); + sprintf(System, "%s", strtok(NULL, "\000")); + email = TRUE; + } else { + sprintf(name, "%s", t->name); + sprintf(System, "%s", CFG.sysdomain); + } + + if (email) { + /* + * Send this netmail via mkrfcmsg -> postemail. + */ + if (reply) + free(reply); + most_debug = TRUE; + result = mkrfcmsg(f, t, subject, orig, mdate, flags, fp, 0L, FALSE); + most_debug = FALSE; + return result; + } + + /* + * If message to "sysop" or "postmaster" replace it + * with the sysops real name. + */ + if ((strncasecmp(name, "sysop", 5) == 0) || (strcasecmp(name, "postmaster") == 0)) { + Syslog('+', " Readdress from %s to %s", name, CFG.sysop_name); + sprintf(name, "%s", CFG.sysop_name); + } + + /* + * If the message is a service message, check the + * services database to see what action is needed. + * First make sure that the right noderecord is loaded. + */ + (void)noderecord(f); + p = calloc(PATH_MAX, sizeof(char)); + sprintf(p, "%s/etc/service.data", getenv("MBSE_ROOT")); + if ((sfp = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + } else { + fread(&servhdr, sizeof(servhdr), 1, sfp); + while (fread(&servrec, servhdr.recsize, 1, sfp) == 1) { + if ((strncasecmp(servrec.Service, name, strlen(servrec.Service)) == 0) && servrec.Active) { + switch (servrec.Action) { + case AREAMGR: result = AreaMgr(f, t, mdate, flags, fp); + break; + case FILEMGR: result = FileMgr(f, t, mdate, flags, fp); + break; + case EMAIL: most_debug = TRUE; + result = mkrfcmsg(f, t, subject, orig, mdate, flags, fp, 0L, FALSE); + most_debug = FALSE; + break; + } + Syslog('m', "Handled service %s, rc=%d", servrec.Service, result); + if (reply) + free(reply); + fclose(sfp); + return result; + } + } + fclose(sfp); + } + free(p); + + /* + * Ping function + */ + if (!strcasecmp(name, (char *)"ping") && DoPing) { + return Ping(f, t, fp, FALSE); + } + + /* + * Check userlist real names, handles, unix names. + * Import if one fits. + */ + if (SearchUser(name)) { + if (reply) + free(reply); + return importnet(f, t, mdate, flags, fp); + } + + Syslog('+', " \"%s\" is not a known BBS user", name); + /* + * Unknown, readdress it to the sysop. + */ + net_bad++; + Syslog('+', " Readdress from %s to %s", name, CFG.sysop_name); + sprintf(name, "%s", CFG.sysop_name); + if (SearchUser(name)) { + return importnet(f, t, mdate, flags, fp); + } else { + WriteError("Readdress import failed"); + return 0; + } + break; + + case R_DIRECT: + case R_ROUTE: + Syslog('+', "Route netmail via %s", aka2str(route)); + if (!strcasecmp(t->name, (char *)"ping") && DoPing) { + Syslog('+', "In transit \"Ping\" message detected"); + Ping(f, t, fp, TRUE); + (void)noderecord(f); + } + + /* + * Forward this message. Will not work for unknown + * direct links. + */ + if (SearchNode(route)) { + memset(&Orig, 0, sizeof(Orig)); + ra = fido2faddr(route); + ta = bestaka_s(ra); + Orig.zone = ta->zone; + Orig.net = ta->net; + Orig.node = ta->node; + Orig.point = ta->point; + tidy_faddr(ra); + tidy_faddr(ta); + + memset(&ext, 0, sizeof(ext)); + if (nodes.PackNetmail) + sprintf(ext, (char *)"qqq"); + else if (nodes.Crash) + sprintf(ext, (char *)"ccc"); + else if (nodes.Hold) + sprintf(ext, (char *)"hhh"); + else + sprintf(ext, (char *)"nnn"); + + if ((net = OpenPkt(Orig , route, (char *)ext)) == NULL) { + net_bad++; + WriteError("Can't create netmail"); + return 0; + } + } else { + /* + * If it's not a direct link, create a outbound + * .pkt anyway, better then that this mail is + * lost. It gets the normal status, it might + * get delivered during ZMH this way. + */ + Syslog('!', "Warning: not a direct link, check setup"); + memset(&Orig, 0, sizeof(Orig)); + ra = fido2faddr(route); + ta = bestaka_s(ra); + Orig.zone = ta->zone; + Orig.net = ta->net; + Orig.node = ta->node; + Orig.point = ta->point; + tidy_faddr(ra); + tidy_faddr(ta); + + if ((net = OpenPkt(Orig , route, (char *)"nnn")) == NULL) { + net_bad++; + WriteError("Can't create netmail"); + return 0; + } + } + + /* + * Now start forward. + */ + Syslog('m', "Net from %s", ascfnode(f, 0xff)); + Syslog('m', "Net to %s", ascfnode(t, 0xff)); + Syslog('m', "Net flags %08x", flags); + Syslog('m', "Net subj %s", subject); + + if (AddMsgHdr(net, f, t, flags, 0, mdate, t->name, f->name, subject)) { + WriteError("Can't write message header"); + net_bad++; + return 0; + } + rewind(fp); + + /* + * Copy all text including kludges, when + * finished, insert our ^aVia line. + */ + buf = calloc(2048, sizeof(char)); + while ((fgets(buf, 2048, fp)) != NULL) + fprintf(net, "%s\r", buf); + + now = time(NULL); + tm = gmtime(&now); + fprintf(net, "\001Via %s @%d%02d%02d.%02d%02d%02d.00.UTC mbfido %s\r", + ascfnode(bestaka_s(t), 0x1f), tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, VERSION); + + putc(0, net); + fclose(net); + free(buf); + net_out++; + if (reply) + free(reply); + Syslog('m', "Forward done."); + return 0; + + default: + /* + * If we came this far, there's definitly something wrong + * with this netmail. + */ + WriteError("No ROUTE for this netmail"); + net_bad++; + if (reply) + free(reply); + return importnet(f, t, mdate, flags, fp); + break; + } + + /* Never reached */ + return result; +} + + diff --git a/mbfido/postnetmail.h b/mbfido/postnetmail.h new file mode 100644 index 00000000..10b4b315 --- /dev/null +++ b/mbfido/postnetmail.h @@ -0,0 +1,8 @@ +#ifndef _POSTNETMAIL_H +#define _POSTNETMAIL_H + + +int postnetmail(FILE *, faddr *, faddr *, char *, char *, time_t, int, int); + +#endif + diff --git a/mbfido/ptic.c b/mbfido/ptic.c new file mode 100644 index 00000000..b74a5df1 --- /dev/null +++ b/mbfido/ptic.c @@ -0,0 +1,782 @@ +/***************************************************************************** + * + * File ..................: mbfido/ptic.c + * Purpose ...............: Process 1 .tic file + * Last modification date : 08-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbtic.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "../lib/dbdupe.h" +#include "ulock.h" +#include "mover.h" +#include "toberep.h" +#include "tic.h" +#include "utic.h" +#include "addbbs.h" +#include "magic.h" +#include "forward.h" +#include "rollover.h" +#include "ptic.h" +#include "magic.h" + + +#define UNPACK_FACTOR 300 + +extern int tic_bad; +extern int tic_dup; +extern int tic_out; +extern int do_quiet; +extern int check_crc; +extern int check_dupe; + + +/* + * Return values: + * 0 - Success + * 1 - Some error + * 2 - Orphaned tic + */ +int ProcessTic(fa_list *sbl, char *Realname) +{ + time_t Now, Fdate; + int Age, First, Listed = FALSE; + int DownLinks = 0; + int MustRearc = FALSE, MustVirus = FALSE; + int IsVirus = FALSE, UnPacked = FALSE, IsArchive = FALSE; + int i, j, k, File_Id = FALSE; + char *Temp, *Temp2, *unarc = NULL, *cmd = NULL; + char temp1[PATH_MAX], temp2[PATH_MAX], sbe[24], TDesc[256]; + unsigned long crc, crc2, Kb; + sysconnect Link; + FILE *fp; + long FwdCost = 0, FwdSize = 0; + struct utimbuf ut; + int BBS_Imp = FALSE, DidBanner = FALSE; + + + time(&Now); + + if (TIC.PathErr) { + WriteError("Our Aka is in the path"); + return 1; + } + + Temp = calloc(PATH_MAX, sizeof(char)); + sprintf(Temp, "%s%s", TIC.FilePath, TIC.TicIn.OrgName); + + if (!do_quiet) { + colour(10, 0); + printf("Checking \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + + /* + * A hack to work around received uppercase or mixed case filenames. + */ + Temp2 = calloc(PATH_MAX, sizeof(char)); + sprintf(Temp2, "%s%s", TIC.FilePath, Realname); + if (file_exist(Temp, R_OK) && !file_exist(Temp2, R_OK)) { + if (rename(Temp2, Temp)) + WriteError("$Rename %s to %s failed", Temp2, Temp); + else + Syslog('f', "File %s renamed to %s", Temp2, Temp); + } + free(Temp2); + + crc = file_crc(Temp, CFG.slow_util && do_quiet); + if (crc == -1) { + WriteError("File not in inbound: %s", Temp); + /* + * Now check the age of the .tic file. + */ + sprintf(Temp, "%s%s", TIC.Inbound, TIC.TicName); + Fdate = file_time(Temp); + Age = (Now - Fdate) / 84400; + Syslog('+', "Orphaned tic age %d days", Age); + + if (Age > 21) { + tic_bad++; + mover(TIC.Inbound, TIC.TicName); + } + + free(Temp); + return 2; + } + + TIC.FileSize = file_size(Temp); + TIC.FileDate = file_time(Temp); + + if (TIC.TicIn.Size) { + if (TIC.TicIn.Size != TIC.FileSize) + WriteError("Size is %ld, expected %ld", TIC.FileSize, TIC.TicIn.Size); + } + + if (TIC.Crc_Int) { + if (crc != TIC.Crc_Int) { + Syslog('!', "CRC: expected %08lX, the file is %08lX", TIC.Crc_Int, crc); + if (check_crc) { + Bad((char *)"CRC: error, %s may be damaged", TIC.TicIn.OrgName); + free(Temp); + return 1; + } else { + Syslog('!', "CRC: error, recalculating crc"); + ReCalcCrc(Temp); + } + } + } else { + Syslog('+', "CRC: missing, calculating CRC"); + ReCalcCrc(Temp); + } + + /* + * Load and check the .TIC area. + */ + if (!SearchTic(TIC.TicIn.Area)) { + Bad((char *)"Unknown file area %s", TIC.TicIn.Area); + free(Temp); + return 1; + } + + if ((tic.Secure) && (!TIC.Hatch)) { + First = TRUE; + while (GetTicSystem(&Link, First)) { + First = FALSE; + if (Link.aka.zone) { + if ((Link.aka.zone == TIC.Aka.zone) && + (Link.aka.net == TIC.Aka.net) && + (Link.aka.node == TIC.Aka.node) && + (Link.aka.point== TIC.Aka.point) && + (Link.receivefrom)) + Listed = TRUE; + } + } + if (!Listed) { + Bad((char *)"%s NOT connected to %s", aka2str(TIC.Aka), TIC.TicIn.Area); + free(Temp); + return 1; + } + } + + if ((!SearchNode(TIC.Aka)) && (!TIC.Hatch)) { + Bad((char *)"%s NOT known", aka2str(TIC.Aka)); + free(Temp); + return 1; + } + + if (!TIC.Hatch) { + if (strcasecmp(TIC.TicIn.Pw, nodes.Fpasswd)) { + Bad((char *)"Pwd error, got %s, expected %s", TIC.TicIn.Pw, nodes.Fpasswd); + free(Temp); + return 1; + } + } else { + if (strcasecmp(TIC.TicIn.Pw, CFG.hatchpasswd)) { + Bad((char *)"Password error in local Hatch"); + WriteError("WARNING: it might be a Trojan in your inbound"); + free(Temp); + return 1; + } + } + + if (Magic_DeleteFile()) { + sprintf(temp1, "%s%s", TIC.Inbound, TIC.TicName); + file_rm(temp1); + Syslog('+', "Deleted file %s", temp1); + free(Temp); + return 0; + } + + + if (Magic_MoveFile()) { + if (!SearchTic(TIC.TicIn.Area)) { + Bad((char *)"Unknown Area: %s", TIC.TicIn.Area); + free(Temp); + return 1; + } + } + + strcpy(T_File.Echo, tic.Name); + strcpy(T_File.Group, tic.Group); + TIC.KeepNum = tic.KeepLatest; + + Magic_Keepnum(); + + if (!tic.FileArea) { + Syslog('f', "Passthru area!"); + strcpy(TIC.BBSpath, CFG.ticout); + strcpy(TIC.BBSdesc, tic.Comment); + } else { + sprintf(Temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((fp = fopen(Temp, "r")) == NULL) { + WriteError("Can't access fareas.data area: %ld", tic.FileArea); + free(Temp); + return 1; + } + fread(&areahdr, sizeof(areahdr), 1, fp); + if (fseek(fp, ((tic.FileArea -1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET)) { + fclose(fp); + WriteError("Can't seek area %ld in fareas.data", tic.FileArea); + free(Temp); + return 1; + } + if (fread(&area, areahdr.recsize, 1, fp) != 1) { + fclose(fp); + WriteError("Can't read area %ld in fareas.data", tic.FileArea); + free(Temp); + return 1; + } + fclose(fp); + strcpy(TIC.BBSpath, area.Path); + strcpy(TIC.BBSdesc, area.Name); + + /* + * If the File area has a special announce group, change + * the group to that name. + */ + if (strlen(area.NewGroup)) + strcpy(T_File.Group, area.NewGroup); + } + strcpy(T_File.Comment, tic.Comment); + + /* + * The destination may be changed now. + */ + Magic_OtherPath(); + + /* + * Check if the destination area really exists, it may be that + * the area is not linked to an existing BBS area. + */ + if (tic.FileArea && access(TIC.BBSpath, W_OK)) { + WriteError("$No write access to \"%s\"", TIC.BBSpath); + Bad((char *)"Dest directory not available"); + free(Temp); + return 1; + } + + if ((tic.DupCheck) && (check_dupe)) { + sprintf(Temp, "%s%s", TIC.TicIn.Area, TIC.TicIn.Crc); + crc2 = 0xffffffff; + crc2 = upd_crc32(Temp, crc2, strlen(Temp)); + if (CheckDupe(crc2, D_FILEECHO, CFG.tic_dupes)) { + Bad((char *)"Duplicate file"); + tic_dup++; + free(Temp); + return 1; + } + } + + /* + * Count the actual downlinks for this area + */ + First = TRUE; + while (GetTicSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto)) + DownLinks++; + } + + /* + * Calculate the cost of this file + */ + T_File.Size = TIC.FileSize; + T_File.SizeKb = TIC.FileSize / 1024; + if ((fgroup.UnitCost) || (TIC.TicIn.UplinkCost)) + TIC.Charge = TRUE; + else + TIC.Charge = FALSE; + + if (TIC.Charge) { + /* + * Calculate our filetransfer cost. + */ + FwdCost = fgroup.UnitCost; + FwdSize = fgroup.UnitSize; + + /* + * If FwdSize <> 0 then calculate per size, else + * charge for each file. + */ + if (FwdSize) + TIC.FileCost = ((TIC.FileSize / 1024) / FwdSize) * FwdCost; + else + TIC.FileCost = FwdCost; + + if (TIC.TicIn.UplinkCost) + TIC.FileCost += TIC.TicIn.UplinkCost; + + if (fgroup.AddProm) + TIC.FileCost += (TIC.FileCost * fgroup.AddProm / 1000); + + if (fgroup.DivideCost) { + /* + * If not a passthru area, we are a link too. + */ + if (DownLinks) + TIC.FileCost = TIC.FileCost / (DownLinks + 1); + } + + /* + * At least charge one unit. + */ + if (!TIC.FileCost) + TIC.FileCost = 1; + + Syslog('+', "The file cost will be %ld", TIC.FileCost); + } + + /* + * Update the uplink's counters. + */ + Kb = TIC.FileSize / 1024; + if (SearchNode(TIC.Aka)) { + nodes.Debet -= TIC.TicIn.UplinkCost; + if (TIC.TicIn.UplinkCost) + Syslog('f', "Uplink cost %ld, debet %ld", TIC.TicIn.UplinkCost, nodes.Debet); + StatAdd(&nodes.FilesRcvd, 1L); + StatAdd(&nodes.F_KbRcvd, Kb); + UpdateNode(); + SearchNode(TIC.Aka); + } + + /* + * Update the fileecho and group counters. + */ + StatAdd(&fgroup.Files, 1L); + StatAdd(&fgroup.KBytes, Kb); + fgroup.LastDate = time(NULL); + StatAdd(&tic.Files, 1L); + StatAdd(&tic.KBytes, Kb); + tic.LastAction = time(NULL); + UpdateTic(); + + if (!TIC.HatchNew) { + + if (!do_quiet) { + printf("Unpacking \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + + /* + * Move the file to the inbound directory if it isn't + * already there (needed by unpacker). + */ + if (strcmp(TIC.FilePath,TIC.Inbound)) { + sprintf(temp1, "%s%s", TIC.FilePath, TIC.TicIn.OrgName); + sprintf(temp2, "%s%s", TIC.Inbound, TIC.TicIn.OrgName); + if (!file_mv(temp1, temp2)) { + sprintf(TIC.FilePath, "%s/", TIC.Inbound); + } else { + WriteError("Can't move %s to inbound", temp1); + } + } + + /* + * Check if this is an archive, and if so, compression method + * is used for this file. + */ + if (strlen(tic.Convert) || tic.VirScan || tic.FileId || tic.ConvertAll || strlen(tic.Banner)) { + if ((unarc = unpacker(TIC.TicIn.OrgName)) == NULL) + Syslog('+', "Unknown archive format %s", TIC.TicIn.OrgName); + else { + IsArchive = TRUE; + if ((strlen(tic.Convert) && (strcmp(unarc, tic.Convert) == 0)) || (tic.ConvertAll)) + MustRearc = TRUE; + } + } + + /* + * Copy the file if there are downlinks and we send the + * original file, but want to rearc it for ourself, or if + * it's a passthru area. + */ + if (((tic.SendOrg) && (MustRearc || strlen(tic.Banner))) || (!tic.FileArea)) { + sprintf(temp1, "%s%s", TIC.FilePath, TIC.TicIn.OrgName); + sprintf(temp2, "%s/%s", CFG.ticout, TIC.TicIn.OrgName); + if (file_cp(temp1, temp2) == 0) { + TIC.SendOrg = TRUE; + } else { + WriteError("$Copy %s to %s failed", temp1, temp2); + } + } + + if ((tic.VirScan) && (IsArchive)) + MustVirus = TRUE; + + if (MustVirus || MustRearc) { + + /* + * Check if there is a temp directory for the archive + * conversion. + */ + sprintf(temp2, "%s/tmp/arc", getenv("MBSE_ROOT")); + if ((access(temp2, R_OK)) != 0) { + if (mkdir(temp2, 0777)) { + WriteError("$Can't create %s", temp2); + free(Temp); + return 1; + } + } + + /* + * Check for stale FILE_ID.DIZ files + */ + sprintf(temp1, "%s/tmp/arc/FILE_ID.DIZ", getenv("MBSE_ROOT")); + if (!unlink(temp1)) + Syslog('+', "Removed stale %s", temp1); + sprintf(temp1, "%s/tmp/FILE_ID.DIZ", getenv("MBSE_ROOT")); + if (!unlink(temp1)) + Syslog('+', "Removed stale %s", temp1); + + if (!checkspace(temp2, TIC.TicIn.OrgName, UNPACK_FACTOR)) { + Bad((char *)"Not enough free diskspace left"); + free(Temp); + return 1; + } + + if (chdir(temp2) != 0) { + WriteError("$Can't change to %s", temp2); + free(Temp); + return 1; + } + + if (!getarchiver(unarc)) { + chdir(TIC.Inbound); + free(Temp); + return 1; + } + + cmd = xstrcpy(archiver.funarc); + + if ((cmd == NULL) || (cmd == "")) { + Syslog('!', "No unarc command available"); + } else { + sprintf(temp1, "%s%s", TIC.Inbound, TIC.TicIn.OrgName); + if (execute(cmd, temp1, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) { + UnPacked = TRUE; + } else { + chdir(TIC.Inbound); + Bad((char *)"Archive maybe corrupt"); + free(Temp); + DeleteVirusWork(); + return 1; + } + free(cmd); + } + } + + if (MustVirus && UnPacked) { + + if (!do_quiet) { + printf("Virscan \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + sprintf(temp2, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp2, "r")) == NULL) { + WriteError("No virus scanners defined"); + } else { + fread(&virscanhdr, sizeof(virscanhdr), 1, fp); + + while (fread(&virscan, virscanhdr.recsize, 1, fp) == 1) { + cmd = NULL; + if (virscan.available) { + cmd = xstrcpy(virscan.scanner); + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, virscan.options); + if (execute(cmd, (char *)"*", (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") != virscan.error) { + Syslog('!', "Virus found by %s", virscan.comment); + IsVirus = TRUE; + } + free(cmd); + } + } + fclose(fp); + + if (IsVirus) { + DeleteVirusWork(); + chdir(TIC.Inbound); + Bad((char *)"Possible virus found!"); + free(Temp); + return 1; + } + } + + if (!do_quiet) { + printf("Checking \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + + } /* MustVirus and Unpacked */ + + if (tic.FileId && tic.FileArea && IsArchive) { + if (UnPacked) { + sprintf(temp1, "%s/tmp/arc/FILE_ID.DIZ", getenv("MBSE_ROOT")); + sprintf(temp2, "%s/tmp/FILE_ID.DIZ", getenv("MBSE_ROOT")); + if (file_cp(temp1, temp2) == 0) + File_Id = TRUE; + } else { + if (!getarchiver(unarc)) { + chdir(TIC.Inbound); + } else { + cmd = xstrcpy(archiver.iunarc); + + if (cmd == NULL) { + WriteError("No unarc command available"); + } else { + sprintf(temp1, "%s/tmp", getenv("MBSE_ROOT")); + chdir(temp1); + sprintf(temp1, "%s%s FILE_ID.DIZ", TIC.Inbound, TIC.TicIn.OrgName); + if (execute(cmd, temp1, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) { + File_Id = TRUE; + } + free(cmd); + } + } /* if getarchiver */ + } /* if not unpacked */ + } /* if need FILE_ID.DIZ and not passthru */ + + /* + * Create internal file description, priority is FILE_ID.DIZ, + * 2nd LDesc, and finally the standard description. + */ + if (!Get_File_Id()) { + if (TIC.TicIn.TotLDesc > 2) { + for (i = 0; i < TIC.TicIn.TotLDesc; i++) { + strcpy(temp1, TIC.TicIn.LDesc[i]); + temp1[48] = '\0'; + strcpy(TIC.File_Id[i], temp1); + } + TIC.File_Id_Ct = TIC.TicIn.TotLDesc; + } else { + /* + * Format the description line (max 255 chars) + * in parts of 48 characters. + */ + if (strlen(TIC.TicIn.Desc) <= 48) { + strcpy(TIC.File_Id[0], TIC.TicIn.Desc); + TIC.File_Id_Ct++; + } else { + memset(&TDesc, 0, sizeof(TDesc)); + strcpy(TDesc, TIC.TicIn.Desc); + while (strlen(TDesc) > 48) { + j = 48; + while (TDesc[j] != ' ') + j--; + strncat(TIC.File_Id[TIC.File_Id_Ct], TDesc, j); + TIC.File_Id_Ct++; + k = strlen(TDesc); + j++; /* Correct space */ + for (i = 0; i <= k; i++, j++) + TDesc[i] = TDesc[j]; + } + strcpy(TIC.File_Id[TIC.File_Id_Ct], TDesc); + TIC.File_Id_Ct++; + } + } + } /* not get FILE_ID.DIZ */ + + if ((MustRearc) && (UnPacked) && (tic.FileArea)) { + if (Rearc(tic.Convert)) { + if (strlen(tic.Banner)) { + Syslog('f', "Must replace banner 1"); + } + + /* + * Get new filesize for import and announce + */ + sprintf(temp1, "%s%s", TIC.FilePath, TIC.NewName); + TIC.FileSize = file_size(temp1); + T_File.Size = TIC.FileSize; + T_File.SizeKb = TIC.FileSize / 1024; + /* + * Calculate the CRC if we must send the new + * archived file. + */ + if (!TIC.SendOrg) { + ReCalcCrc(temp1); + } + } else { + WriteError("Rearc failed"); + } /* if Rearc() */ + } else { + /* + * If the file is not unpacked, change the banner + * direct if this is needed. + */ + if ((strlen(tic.Banner)) && IsArchive) { + cmd = xstrcpy(archiver.barc); + if ((cmd == NULL) || (!strlen(cmd))) { + Syslog('!', "No banner command for %s", archiver.name); + } else { + sprintf(temp1, "%s%s", TIC.Inbound, TIC.TicIn.OrgName); + sprintf(Temp, "%s/etc/%s", getenv("MBSE_ROOT"), tic.Banner); + if (execute(cmd, temp1, (char *)NULL, Temp, (char *)"/dev/null", (char *)"/dev/null")) { + WriteError("$Changing the banner failed"); + } else { + Syslog('+', "New banner %s", tic.Banner); + TIC.FileSize = file_size(temp1); + T_File.Size = TIC.FileSize; + T_File.SizeKb = TIC.FileSize / 1024; + ReCalcCrc(temp1); + DidBanner = TRUE; + } + } + } + } /* if MustRearc and Unpacked and not Passthtru */ + + if (UnPacked) + DeleteVirusWork(); + + chdir(TIC.Inbound); + + /* + * If the file is converted, we set the date of the original + * received file as the file creation date. + */ + if (MustRearc || DidBanner) { + if ((!tic.NoTouch) && (tic.FileArea)) { + ut.actime = mktime(localtime(&TIC.FileDate)); + ut.modtime = mktime(localtime(&TIC.FileDate)); + sprintf(Temp, "%s%s", TIC.FilePath, TIC.NewName); + utime(Temp, &ut); + } + } + + if (tic.FileArea) { + Syslog('+', "Import: %s Area: %s", TIC.NewName, TIC.TicIn.Area); + + if (TIC.OtherPath) { + /* BBS_Imp = Add_DOS */ + } else { + BBS_Imp = Add_BBS(); + } + + if (!BBS_Imp) { + Bad((char *)"File Import Error"); + free(Temp); + return 1; + } + } + + } /* Not TIC.HatchNew */ + + chdir(TIC.Inbound); + + if ((!TIC.HatchNew) && (tic.FileArea)) { + if (strlen(TIC.TicIn.Magic)) + UpDateAlias(TIC.TicIn.Magic); + else + Magic_UpDateAlias(); + + for (i = 0; i <= TIC.File_Id_Ct; i++) + strcpy(T_File.LDesc[i], TIC.File_Id[i]); + T_File.TotLdesc = TIC.File_Id_Ct; + T_File.Announce = tic.Announce; + strcpy(T_File.Name, TIC.NewName); + T_File.Fdate = TIC.FileDate; + T_File.Cost = TIC.TicIn.UplinkCost; + Add_ToBeRep(); + } + + if (TIC.SendOrg && !tic.FileArea) { + /* + * If it's a passthru area we don't need the + * file in the inbound anymore so it can be + * deleted. + */ + sprintf(temp1, "%s%s", TIC.FilePath, TIC.TicIn.OrgName); + if (file_rm(temp1) == 0) + Syslog('f', "Deleted %s", temp1); + } + + if (DownLinks) { + First = TRUE; + + /* + * Add all our system aka's to the seenby lines in the same zone + */ + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (tic.Aka.zone == CFG.aka[i].zone) && + !((tic.Aka.net == CFG.aka[i].net) && (tic.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u:%u/%u", CFG.aka[i].zone, CFG.aka[i].net, CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + + /* + * Add downlinks to seenby lines + */ + while (GetTicSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.aka.point)) { + if (!((TIC.Aka.zone == Link.aka.zone) && (TIC.Aka.net == Link.aka.net) && + (TIC.Aka.node == Link.aka.node) && (TIC.Aka.point == Link.aka.point))) { + sprintf(sbe, "%u:%u/%u", Link.aka.zone, Link.aka.net, Link.aka.node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + } + uniq_list(&sbl); + sort_list(&sbl); + + /* + * Now start forwarding files + */ + First = TRUE; + while (GetTicSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause)) { + if (!((TIC.Aka.zone == Link.aka.zone) && (TIC.Aka.net == Link.aka.net) && + (TIC.Aka.node == Link.aka.node) && (TIC.Aka.point == Link.aka.point))) { + tic_out++; + ForwardFile(Link.aka, sbl); + } + } + } + } + + if (!TIC.HatchNew) { + Magic_ExecCommand(); + Magic_CopyFile(); + Magic_UnpackFile(); + Magic_AdoptFile(); + } + + sprintf(Temp, "%s%s", TIC.Inbound, TIC.TicName); + unlink(Temp); + free(Temp); + return 0; +} + + diff --git a/mbfido/ptic.h b/mbfido/ptic.h new file mode 100644 index 00000000..8842416e --- /dev/null +++ b/mbfido/ptic.h @@ -0,0 +1,7 @@ +#ifndef _PTIC_H +#define _PTIC_H + +int ProcessTic(fa_list *, char *); + +#endif + diff --git a/mbfido/rnews.c b/mbfido/rnews.c new file mode 100644 index 00000000..b59f12b7 --- /dev/null +++ b/mbfido/rnews.c @@ -0,0 +1,652 @@ +/***************************************************************************** + * + * File ..................: mbfido/rnews.c + * Purpose ...............: rnews function + * Last modification date : 19-Jul-2001 + * Remarks ...............: Most of these functions are borrowed from inn. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "../lib/dbdupe.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "pack.h" +#include "scannews.h" +#include "mbfido.h" +#include "paths.h" +#include "rnews.h" + + +#define UUCPBUF 10240 + + +typedef struct _HEADER { + char *Name; + int size; +} HEADER; +typedef void *POINTER; + +static char UNPACK[] = "gzip"; +static HEADER RequiredHeaders[] = { + { (char *)"Message-ID", 10 }, +#define _messageid 0 + { (char *)"Newsgroups", 10 }, +#define _newsgroups 1 + { (char *)"From", 4 }, +#define _from 2 + { (char *)"Date", 4 }, +#define _date 3 + { (char *)"Subject", 7 }, +#define _subject 4 + { (char *)"Path", 4 }, +#define _path 5 +}; +#define IS_MESGID(hp) ((hp) == &RequiredHeaders[_messageid]) +#define IS_PATH(hp) ((hp) == &RequiredHeaders[_path]) +#define IS_NG(hp) ((hp) == &RequiredHeaders[_newsgroups]) + + +/* + * Some macro's + */ +#define NEW(T, c) ((T *)xmalloc((unsigned int)(sizeof (T) * (c)))) +#define RENEW(p, T, c) (p = (T *)realloc((char *)(p), (unsigned int)(sizeof (T) * (c)))) +#define DISPOSE(p) free((void *)p) +#define SIZEOF(array) ((int)(sizeof array / sizeof array[0])) +#define ENDOF(array) (&array[SIZEOF(array)]) +#define ISWHITE(c) ((c) == ' ' || (c) == '\t') +#define caseEQn(a, b, n) (strncasecmp((a), (b), (size_t)(n)) == 0) + +/* + * External variables + */ +extern int do_quiet; +extern int most_debug; +extern int news_in; +extern int news_dupe; + + +void ProcessOne(FILE *); + + +/* + * Find a header in an article. + */ +const char *HeaderFindMem(const char *, const int, const char *, const int); +const char *HeaderFindMem(const char *Article, const int ArtLen, const char *Header, const int HeaderLen) +{ + const char *p; + + for (p = Article; ; ) { + /* Match first character, then colon, then whitespace (don't + * delete that line -- meet the RFC!) then compare the rest + * of the word. */ + if (HeaderLen + 1 < Article + ArtLen - p && p[HeaderLen] == ':' + && ISWHITE(p[HeaderLen + 1]) && caseEQn(p, Header, (size_t)HeaderLen)) { + p += HeaderLen + 2; + while (1) { + for (; p < Article + ArtLen && ISWHITE(*p); p++) + continue; + if (p == Article+ArtLen) + return NULL; + else { + if (*p != '\r' && *p != '\n') + return p; + else { + /* handle multi-lined header */ + if (++p == Article + ArtLen) + return NULL; + if (ISWHITE(*p)) + continue; + if (p[-1] == '\r' && *p== '\n') { + if (++p == Article + ArtLen) + return NULL; + if (ISWHITE(*p)) + continue; + return NULL; + } + return NULL; + } + } + } + } + if ((p = memchr(p, '\n', ArtLen - (p - Article))) == NULL || + (++p >= Article + ArtLen) || (*p == '\n') || + (((*p == '\r') && (++p >= Article + ArtLen)) || (*p == '\n'))) + return NULL; + } +} + + + +/* + * Open up a pipe to a process with fd tied to its stdin. Return a + * descriptor tied to its stdout or -1 on error. + */ +static int StartChild(int, char *, char *[]); +static int StartChild(int fd, char *path, char *argv[]) +{ + int pan[2]; + int i; + pid_t pid; + + /* Create a pipe. */ + if (pipe(pan) < 0) { + WriteError("%Cant pipe for %s", path); + die(101); + } + + /* Get a child. */ + for (i = 0; (pid = fork()) < 0; i++) { + if (i == MAX_FORKS) { + WriteError("$Cant fork %s -- spooling", path); + return -1; + } + Syslog('n', "Cant fork %s -- waiting", path); + (void)sleep(60); + } + + /* Run the child, with redirection. */ + if (pid == 0) { + (void)close(pan[PIPE_READ]); + + /* Stdin comes from our old input. */ + if (fd != STDIN) { + if ((i = dup2(fd, STDIN)) != STDIN) { + WriteError("$Cant dup2 %d to 0 got %d", fd, i); + _exit(1); + } + (void)close(fd); + } + + /* Stdout goes down the pipe. */ + if (pan[PIPE_WRITE] != STDOUT) { + if ((i = dup2(pan[PIPE_WRITE], STDOUT)) != STDOUT) { + WriteError("$Cant dup2 %d to 1 got %d", pan[PIPE_WRITE], i); + _exit(1); + } + (void)close(pan[PIPE_WRITE]); + } + + Syslog('n', "execv %s %s", MBSE_SS(path), MBSE_SS(argv[1])); + (void)execv(path, argv); + WriteError("$Cant execv %s", path); + _exit(1); + } + + (void)close(pan[PIPE_WRITE]); + (void)close(fd); + return pan[PIPE_READ]; +} + + + +/* + * Wait for the specified number of children. + */ +void WaitForChildren(int i) +{ + pid_t pid; + int status; + + while (--i >= 0) { + pid = waitpid(-1, &status, WNOHANG); + if (pid < 0) { + if (errno != ECHILD) + WriteError("$Cant wait"); + break; + } + } +} + + + +/* + * Write an article to the rejected directory. + */ +static void Reject(const char *, const char *, const char *); +static void Reject(const char *article, const char *reason, const char *arg) +{ +#if defined(DO_RNEWS_SAVE_BAD) + char buff[SMBUF]; + FILE *F; + int i; +#endif /* defined(DO_RNEWS_SAVE_BAD) */ + + WriteError(reason, arg); +#if defined(DO_RNEWS_SAVE_BAD) +// TempName(PATHBADNEWS, buff); +// if ((F = fopen(buff, "w")) == NULL) { +// syslog(L_ERROR, "cant fopen %s %m", buff); +// return; +// } +// i = strlen(article); +// if (fwrite((POINTER)article, (size_t)1, (size_t)i, F) != i) +// syslog(L_ERROR, "cant fwrite %s %m", buff); +// if (fclose(F) == EOF) +// syslog(L_ERROR, "cant close %s %m", buff); +#endif /* defined(DO_RNEWS_SAVE_BAD) */ +} + + + +/* + * Process one article. Return TRUE if the article was okay; FALSE if the + * whole batch needs to be saved (such as when the server goes down or if + * the file is corrupted). + */ +static int Process(char *); +static int Process(char *article) +{ + HEADER *hp; + char *p; + char *id = NULL; + FILE *fp; + + Syslog('n', "Process article"); + /* + * Empty article? + */ + if (*article == '\0') + return TRUE; + + /* + * Make sure that all the headers are there. + */ + for (hp = RequiredHeaders; hp < ENDOF(RequiredHeaders); hp++) { + if ((p = (char *)HeaderFindMem(article, strlen(article), hp->Name, hp->size)) == NULL) { + Reject(article, "bad_article missing %s", hp->Name); + return FALSE; + } + if (IS_MESGID(hp)) { + id = p; + continue; + } + } + + /* + * Put the article in a temp file, all other existing functions + * did already work with tempfiles. + */ + fp = tmpfile(); + fwrite(article, 1, strlen(article), fp); + ProcessOne(fp); + fclose(fp); + + return TRUE; +} + + + +/* + * Read the rest of the input as an article. Just punt to stdio in + * this case and let it do the buffering. + */ +static int ReadRemainder(register int, char, char); +static int ReadRemainder(register int fd, char first, char second) +{ + register FILE *F; + register char *article; + register int size; + register int used; + register int left; + register int i; + int ok; + + /* Turn the descriptor into a stream. */ + if ((F = fdopen(fd, "r")) == NULL) { + WriteError("$Can't fdopen %d", fd); + die(101); + } + + /* Get an initial allocation, leaving space for the \0. */ + size = BUFSIZ + 1; + article = NEW(char, size + 2); + article[0] = first; + article[1] = second; + used = second ? 2 : 1; + left = size - used; + + /* Read the input. */ + while ((i = fread((POINTER)&article[used], (size_t)1, (size_t)left, F)) != 0) { + if (i < 0) { + WriteError("$Cant fread after %d bytes", used); + die(101); + } + used += i; + left -= i; + if (left < SMBUF) { + size += BUFSIZ; + left += BUFSIZ; + RENEW(article, char, size); + } + } + if (article[used - 1] != '\n') + article[used++] = '\n'; + article[used] = '\0'; + (void)fclose(F); + + ok = Process(article); + DISPOSE(article); + return ok; +} + + + +/* + * Read an article from the input stream that is artsize bytes long. + */ +static int ReadBytecount(register int, int); +static int ReadBytecount(register int fd, int artsize) +{ + static char *article; + static int oldsize; + register char *p; + register int left; + register int i; + + /* If we haven't gotten any memory before, or we didn't get enough, + * then get some. */ + if (article == NULL) { + oldsize = artsize; + article = NEW(char, oldsize + 1 + 1); + } else if (artsize > oldsize) { + oldsize = artsize; + RENEW(article, char, oldsize + 1 + 1); + } + + /* Read in the article. */ + for (p = article, left = artsize; left; p += i, left -= i) + if ((i = read(fd, p, left)) <= 0) { + i = errno; + WriteError("$Cant read wanted %d got %d", artsize, artsize - left); +#if 0 + /* Don't do this -- if the article gets re-processed we + * will end up accepting the truncated version. */ + artsize = p - article; + article[artsize] = '\0'; + Reject(article, "short read (%s?)", strerror(i)); +#endif /* 0 */ + return TRUE; + } + if (p[-1] != '\n') + *p++ = '\n'; + *p = '\0'; + + return Process(article); +} + + + +/* + * Read a single text line; not unlike fgets(). Just more inefficient. + */ +static int ReadLine(char *, int, int); +static int ReadLine(char *p, int size, int fd) +{ + char *save; + + /* Fill the buffer, a byte at a time. */ + for (save = p; size > 0; p++, size--) { + if (read(fd, p, 1) != 1) { + *p = '\0'; + WriteError("$Cant read first line got %s", save); + die(101); + } + if (*p == '\n') { + *p = '\0'; + return TRUE; + } + } + *p = '\0'; + WriteError("bad_line too long %s", save); + return FALSE; +} + + + +/* + * Unpack a single batch. + */ +static int UnpackOne(int *, int *); +static int UnpackOne(int *fdp, int *countp) +{ + char buff[SMBUF]; + char *cargv[4]; + int artsize; + int i; + int gzip = 0; + int HadCount; + int SawCunbatch; + + *countp = 0; + for (SawCunbatch = FALSE, HadCount = FALSE; ; ) { + /* Get the first character. */ + if ((i = read(*fdp, &buff[0], 1)) < 0) { + WriteError("$cant read first character"); + return FALSE; + } + if (i == 0) + break; + + if (buff[0] == 0x1f) + gzip = 1; + else if (buff[0] != RNEWS_MAGIC1) + /* Not a batch file. If we already got one count, the batch + * is corrupted, else read rest of input as an article. */ + return HadCount ? FALSE : ReadRemainder(*fdp, buff[0], '\0'); + + /* Get the second character. */ + if ((i = read(*fdp, &buff[1], 1)) < 0) { + WriteError("$Cant read second character"); + return FALSE; + } + if (i == 0) + /* A one-byte batch? */ + return FALSE; + + /* Check second magic character. */ + /* gzipped ($1f$8b) or compressed ($1f$9d) */ + if (gzip && ((buff[1] == (char)0x8b) || (buff[1] == (char)0x9d))) { + cargv[0] = (char *)"gzip"; + cargv[1] = (char *)"-d"; + cargv[2] = NULL; + lseek(*fdp, (long) 0, 0); /* Back to the beginning */ + *fdp = StartChild(*fdp, (char*)_PATH_GZIP, cargv); + if (*fdp < 0) + return FALSE; + (*countp)++; + SawCunbatch = TRUE; + continue; + } + if (buff[1] != RNEWS_MAGIC2) + return HadCount ? FALSE : ReadRemainder(*fdp, buff[0], buff[1]); + + /* Some kind of batch -- get the command. */ + if (!ReadLine(&buff[2], (int)(sizeof buff - 3), *fdp)) + return FALSE; + + if (strncmp(buff, "#! rnews ", 9) == 0) { + artsize = atoi(&buff[9]); + if (artsize <= 0) { + WriteError("Bad_line bad count %s", buff); + return FALSE; + } + HadCount = TRUE; + if (ReadBytecount(*fdp, artsize)) + continue; + return FALSE; + } + + if (HadCount) + /* Already saw a bytecount -- probably corrupted. */ + return FALSE; + + if (strcmp(buff, "#! cunbatch") == 0) { + Syslog('n', "Compressed newsbatch"); + if (SawCunbatch) { + WriteError("Nested_cunbatch"); + return FALSE; + } + cargv[0] = UNPACK; + cargv[1] = (char *)"-d"; + cargv[2] = NULL; + *fdp = StartChild(*fdp, (char *)_PATH_GZIP, cargv); + if (*fdp < 0) + return FALSE; + (*countp)++; + SawCunbatch = TRUE; + continue; + } + + WriteError("bad_format unknown command %s", buff); + return FALSE; + } + return TRUE; +} + + + +void NewsUUCP(int unspool) +{ + int fd = STDIN, i, rc; + + Syslog('+', "Processing UUCP newsbatch"); + IsDoing((char *)"UUCP Batch"); + + if (!do_quiet) { + colour(10, 0); + printf("Process UUCP Newsbatch\n"); + } + + if (unspool) { +// Unspool(); + } else { +// if (!UnpackOne(&fd, &i)) +// Spool(fd); + most_debug = TRUE; + rc = UnpackOne(&fd, &i); + most_debug = FALSE; + Syslog('+', "Batch result=%d", rc); + WaitForChildren(i); + } + + Syslog('+', "End of UUCP batch"); + packmail(); + + if (!do_quiet) + printf("\r \r"); +} + + + +/* + * Process one newsarticle. + */ +void ProcessOne(FILE *fp) +{ + char *p, *fn, *buf, *gbuf, *mbuf, *group, *groups[25]; + int i, nrofgroups; + unsigned long crc; + + buf = calloc(UUCPBUF, sizeof(char)); + fn = calloc(PATH_MAX, sizeof(char)); + + /* + * Find newsgroups names in article. + */ + rewind(fp); + nrofgroups = 0; + mbuf = NULL; + gbuf = NULL; + while (fgets(buf, UUCPBUF, fp)) { + if (!strncasecmp(buf, "Newsgroups: ", 12)) { + gbuf = xstrcpy(buf+12); + Striplf(gbuf); + strtok(buf, " "); + while ((group = strtok(NULL, ",\n"))) { + if (SearchMsgsNews(group)) { + Syslog('n', "Add group %s (%s)", msgs.Newsgroup, msgs.Tag); + groups[nrofgroups] = xstrcpy(group); + nrofgroups++; + } else { + Syslog('n', "Newsgroup %s doesn't exist", group); + } + } + } + if (!strncasecmp(buf, "Message-ID: ", 12)) { + /* + * Store the Message-ID without the < > characters. + */ + mbuf = xstrcpy(buf+13); + mbuf[strlen(mbuf)-2] = '\0'; + Syslog('n', "Message ID \"%s\"", printable(mbuf, 0)); + } + } + + if (nrofgroups == 0) { + WriteError("No newsgroups found: %s", gbuf); + } else if (mbuf == NULL) { + WriteError("No valid Message-ID found"); + } else { + news_in++; + IsDoing("Article %d", (news_in + 1)); + for (i = 0; i < nrofgroups; i++) { + Syslog('n', "Process %s", groups[i]); + p = xstrcpy(mbuf); + p = xstrcat(p, groups[i]); + crc = str_crc32(p); + if (CheckDupe(crc, D_NEWS, CFG.nntpdupes)) { + news_dupe++; + Syslog('+', "Duplicate article \"%s\" in group %s", mbuf, groups[i]); + } else { + if (SearchMsgsNews(groups[i])) { + do_article(fp); + } + } + free(groups[i]); + } + } + + if (mbuf) + free(mbuf); + if (gbuf) + free(gbuf); + + free(buf); + free(fn); +} + + + diff --git a/mbfido/rnews.h b/mbfido/rnews.h new file mode 100644 index 00000000..7f832492 --- /dev/null +++ b/mbfido/rnews.h @@ -0,0 +1,20 @@ +#ifndef _RNEWS_H +#define _RNEWS_H + + +#define MAX_FORKS 10 +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 +#define PIPE_READ 0 +#define PIPE_WRITE 1 +#define RNEWS_MAGIC1 '#' +#define RNEWS_MAGIC2 '!' +#define SMBUF 256 + + +void NewsUUCP(int); + + +#endif + diff --git a/mbfido/rollover.c b/mbfido/rollover.c new file mode 100644 index 00000000..7a0c9369 --- /dev/null +++ b/mbfido/rollover.c @@ -0,0 +1,418 @@ +/***************************************************************************** + * + * File ..................: mbfido/rollover.c + * Purpose ...............: Statistic rollover util. + * Last modification date : 23-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "rollover.h" + + +extern int do_quiet; + + +void StatAdd(statcnt *S, unsigned long V) +{ + S->total += V; + S->tweek += V; + S->tdow[Diw] += V; + S->month[Miy] += V; +} + + + +void RollWeek(statcnt *); +void RollWeek(statcnt *S) +{ + int i; + + for (i = 0; i < 7; i++) { + S->ldow[i] = S->tdow[i]; + S->tdow[i] = 0L; + } + + S->lweek = S->tweek; + S->tweek = 0L; + + if (CFG.slow_util && do_quiet) + usleep(1); +} + + + +FILE *OpenData(char *); +FILE *OpenData(char *Name) +{ + char *temp; + FILE *fp; + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/%s", getenv("MBSE_ROOT"), Name); + if ((fp = fopen(temp, "r+")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return NULL; + } + + free(temp); + return fp; +} + + + +/* + * Test all files with statistic counters if a new week has started + * or a new month has started. All the record counters will be + * updated if one of these is the case. + */ +void Rollover() +{ + time_t Now; + struct tm *t; + FILE *fp, *ft; + int do_week, do_month, Day, i; + char *temp, *temp1; + struct _history history; + + IsDoing("Date rollover"); + Now = time(NULL); + t = localtime(&Now); + + Diw = t->tm_wday; + Miy = t->tm_mon; + Day = t->tm_yday; + + if ((fp = OpenData((char *)"nodes.data")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fp); + t = localtime(&nodeshdr.lastupd); + + /* + * Test if it's sunday, and the last update wasn't today. + * If it's not sunday, and the last update was more then + * 7 days ago, we maybe missed last sunday and the update + * is still done. + */ + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + + /* + * If the month is different then the last update, we must + * be in a new month. + */ + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover nodes.data"); + + while (fread(&nodes, nodeshdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&nodes.FilesSent); + RollWeek(&nodes.FilesRcvd); + RollWeek(&nodes.F_KbSent); + RollWeek(&nodes.F_KbRcvd); + RollWeek(&nodes.MailSent); + RollWeek(&nodes.MailRcvd); + } + if (do_month) { + nodes.FilesSent.month[Miy] = 0; + nodes.FilesRcvd.month[Miy] = 0; + nodes.F_KbSent.month[Miy] = 0; + nodes.F_KbRcvd.month[Miy] = 0; + nodes.MailSent.month[Miy] = 0; + nodes.MailRcvd.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - nodeshdr.recsize, SEEK_CUR); + fwrite(&nodes, nodeshdr.recsize, 1, fp); + fseek(fp, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + } + + fseek(fp, 0, SEEK_SET); + nodeshdr.lastupd = time(NULL); + fwrite(&nodeshdr, nodeshdr.hdrsize, 1, fp); + } + + fclose(fp); + } + + if ((fp = OpenData((char *)"mareas.data")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, fp); + t = localtime(&msgshdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover mareas.data"); + + while (fread(&msgs, msgshdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&msgs.Received); + RollWeek(&msgs.Posted); + } + if (do_month) { + msgs.Received.month[Miy] = 0; + msgs.Posted.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - msgshdr.recsize, SEEK_CUR); + fwrite(&msgs, msgshdr.recsize, 1, fp); + fseek(fp, msgshdr.syssize, SEEK_CUR); + } + + msgshdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&msgshdr, msgshdr.hdrsize, 1, fp); + } + fclose(fp); + } + + if ((fp = OpenData((char *)"mgroups.data")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fp); + t = localtime(&mgrouphdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover mgroups.data"); + + while (fread(&mgroup, mgrouphdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&mgroup.MsgsRcvd); + RollWeek(&mgroup.MsgsSent); + } + if (do_month) { + mgroup.MsgsRcvd.month[Miy] = 0; + mgroup.MsgsSent.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - mgrouphdr.recsize, SEEK_CUR); + fwrite(&mgroup, mgrouphdr.recsize, 1, fp); + } + + mgrouphdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&mgrouphdr, mgrouphdr.hdrsize, 1, fp); + } + fclose(fp); + } + + if ((fp = OpenData((char *)"tic.data")) != NULL) { + fread(&tichdr, sizeof(tichdr), 1, fp); + t = localtime(&tichdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover tic.data"); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&tic.Files); + RollWeek(&tic.KBytes); + } + if (do_month) { + tic.Files.month[Miy] = 0; + tic.KBytes.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - tichdr.recsize, SEEK_CUR); + fwrite(&tic, tichdr.recsize, 1, fp); + fseek(fp, tichdr.syssize, SEEK_CUR); + } + + tichdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&tichdr, tichdr.hdrsize, 1, fp); + } + fclose(fp); + } + + if ((fp = OpenData((char *)"fgroups.data")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fp); + t = localtime(&fgrouphdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover fgroups.data"); + + while (fread(&fgroup, fgrouphdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&fgroup.Files); + RollWeek(&fgroup.KBytes); + } + if (do_month) { + fgroup.Files.month[Miy] = 0; + fgroup.KBytes.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - fgrouphdr.recsize, SEEK_CUR); + fwrite(&fgroup, fgrouphdr.recsize, 1, fp); + } + + fgrouphdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&fgrouphdr, fgrouphdr.hdrsize, 1, fp); + } + fclose(fp); + } + + if ((fp = OpenData((char *)"hatch.data")) != NULL) { + fread(&hatchhdr, sizeof(hatchhdr), 1, fp); + t = localtime(&hatchhdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover hatch.data"); + + while (fread(&hatch, hatchhdr.recsize, 1, fp) == 1) { + if (do_week) + RollWeek(&hatch.Hatched); + if (do_month) { + hatch.Hatched.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - hatchhdr.recsize, SEEK_CUR); + fwrite(&hatch, hatchhdr.recsize, 1, fp); + } + + hatchhdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&hatchhdr, hatchhdr.hdrsize, 1, fp); + } + fclose(fp); + } + + temp = calloc(128, sizeof(char)); + temp1 = calloc(128, sizeof(char)); + sprintf(temp, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r"))) { + fread(&history, sizeof(history), 1, fp); + t = localtime(&history.online); + if (t->tm_mon != Miy) { + /* + * Calculate date/time for records to delete + */ + t = localtime(&Now); + if (t->tm_mon == 0) { + t->tm_mon = 11; + t->tm_year--; + } else { + t->tm_mon--; + } + t->tm_mday = 1; + t->tm_hour = 0; + t->tm_min = 0; + t->tm_sec = 0; + Now = mktime(t); + Syslog('+', "Packing mailer history since %s", rfcdate(Now)); + sprintf(temp1, "%s/var/mailer.temp", getenv("MBSE_ROOT")); + if ((ft = fopen(temp1, "a")) == NULL) { + WriteError("$Can't create %s", temp1); + fclose(fp); + } else { + memset(&history, 0, sizeof(history)); + history.online = time(NULL); + history.offline = time(NULL); + fwrite(&history, sizeof(history), 1, ft); + + i = 0; + while (fread(&history, sizeof(history), 1, fp)) { + if (history.online >= Now) { + fwrite(&history, sizeof(history), 1, ft); + i++; + } + } + fclose(ft); + fclose(fp); + unlink(temp); + rename(temp1, temp); + Syslog('+', "Written %d records", i); + } + } else { + fclose(fp); + } + } + free(temp); + free(temp1); +} + + + diff --git a/mbfido/rollover.h b/mbfido/rollover.h new file mode 100644 index 00000000..bfd8f71b --- /dev/null +++ b/mbfido/rollover.h @@ -0,0 +1,10 @@ +#ifndef _ROLLOVER_H +#define _ROLLOVER_H + + +void StatAdd(statcnt *, unsigned long); +void Rollover(void); + + +#endif + diff --git a/mbfido/scan.c b/mbfido/scan.c new file mode 100644 index 00000000..12792b3a --- /dev/null +++ b/mbfido/scan.c @@ -0,0 +1,1085 @@ +/***************************************************************************** + * + * File ..................: mbfido/scan.h + * Purpose ...............: Scan for outgoing mail. + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/msg.h" +#include "../lib/clcomm.h" +#include "../lib/msgtext.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "addpkt.h" +#include "pack.h" +#include "tracker.h" +#include "mkrfcmsg.h" +#include "postemail.h" +#include "scan.h" + + +extern int do_quiet; +extern int net_out; +extern int net_bad; +extern int echo_in; +extern int email_out; +extern int echo_out; +extern int email_imp; +extern int email_bad; +extern int most_debug; +int scanned; + +#define MAXSEEN 70 + + +/* + * Internal prototypes + */ +void ScanFull(void); +void ScanOne(char *, unsigned long); +void ExportEcho(sysconnect, unsigned long, fa_list **); +void ExportNews( unsigned long, fa_list **); +void ExportNet(unsigned long, int); +void ExportEmail(unsigned long); + + + +/* + * Scan for outgoing mail. If using the files $MBSE_ROOT/tmp/echomail.jam + * or netmail.jam not all mail is scanned a full mailscan will be + * performed. + */ +void ScanMail(int DoAll) +{ + int DoFull = FALSE, i = 0; + unsigned long msg; + char *Fname = NULL, *temp, *path; + FILE *fp; + + if (DoAll) { + DoFull = TRUE; + } else { + scanned = 0; + Fname = calloc(128, sizeof(char)); + temp = calloc(128, sizeof(char)); + + sprintf(Fname, "%s/tmp/echomail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(Fname, "r")) != NULL) { + while ((fgets(temp, 128, fp)) != NULL) { + path = strtok(temp, " "); + msg = atol(strtok(NULL, "\n")); + Syslog('+', "Export message %lu from %s", msg, path); + ScanOne(path, msg); + i++; + } + fclose(fp); + unlink(Fname); + } + + sprintf(Fname, "%s/tmp/netmail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(Fname, "r")) != NULL) { + while ((fgets(temp, 128, fp)) != NULL) { + path = strtok(temp, " "); + msg = atol(strtok(NULL, "\n")); + Syslog('+', "Export message %lu from %s", msg, path); + ScanOne(path, msg); + i++; + } + fclose(fp); + unlink(Fname); + } + + if ((i != scanned) || (i == 0)) { + Syslog('+', "Not all messages exported, forcing full mail scan"); + Syslog('+', "i=%d scanned=%d", i, scanned); + DoFull = TRUE; + } + free(Fname); + free(temp); + } + + if (DoFull) + ScanFull(); + + if (echo_out || net_out) + packmail(); + RemoveSema((char *)"mailout"); +} + + + +void ScanFull() +{ + char sAreas[81], sbe[128]; + FILE *pAreas; + long arearec = 0, sysstart, nextstart; + unsigned long Total, Number; + int i; + sysconnect Link; + fa_list *sbl = NULL; + + Syslog('+', "Full mailscan"); + IsDoing("Scanning mail"); + + if (!do_quiet) { + colour(9, 0); + printf("Scanning mail\n"); + colour(3, 0); + fflush(stdout); + } + + sprintf(sAreas, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(sAreas, "r")) != NULL) { + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pAreas); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, pAreas) == 1) { + if (usrconfig.Email && strlen(usrconfig.Name)) { + if (!do_quiet) { + colour(3, 0); + printf("\r%8s %-40s", usrconfig.Name, usrconfig.sUserName); + colour(13, 0); + fflush(stdout); + } + + sprintf(sAreas, "%s/%s/mailbox", CFG.bbs_usersdir, usrconfig.Name); + if (Msg_Open(sAreas)) { + if ((Total = Msg_Number()) != 0L) { + Number = Msg_Lowest(); + + do { + if (CFG.slow_util && do_quiet) + usleep(1); + + if (((Number % 10) == 0) && (!do_quiet)) { + printf("%6lu\b\b\b\b\b\b", Number); + fflush(stdout); + } + + Msg_ReadHeader(Number); + if (Msg.Local) { + if (Msg_Lock(15L)) { + Syslog('m', "Export %lu email from %s", Number, usrconfig.Name); + ExportEmail(Number); + Msg.Local = FALSE; + Msg.Arrived = time(NULL); + Msg_WriteHeader(Number); + Msg_UnLock(); + } + } + + } while (Msg_Next(&Number) == TRUE); + } + Msg_Close(); + if (!do_quiet) { + printf(" \b\b\b\b\b\b"); + fflush(stdout); + } + } + } + } + fclose(pAreas); + } + + sprintf(sAreas, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, pAreas); + + while (fread(&msgs, msgshdr.recsize, 1, pAreas) == 1) { + sysstart = ftell(pAreas); + fseek(pAreas, msgshdr.syssize, SEEK_CUR); + nextstart = ftell(pAreas); + arearec++; + + if ((msgs.Active) && (msgs.Type == ECHOMAIL || msgs.Type == NETMAIL || msgs.Type == NEWS)) { + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", arearec, msgs.Name); + colour(13, 0); + fflush(stdout); + } + + if (Msg_Open(msgs.Base)) { + if ((Total = Msg_Number()) != 0L) { + Number = Msg_Lowest(); + + do { + if (CFG.slow_util && do_quiet) + usleep(1); + + if (((Number % 10) == 0) && (!do_quiet)) { + printf("%6lu\b\b\b\b\b\b", Number); + fflush(stdout); + } + + Msg_ReadHeader(Number); + if (Msg.Local) { + if (Msg_Lock(15L)) { + Syslog('m', "Export %lu from area %ld", Number, arearec); + + /* + * Setup SEEN-BY lines + */ + if ((msgs.Type == ECHOMAIL) || (msgs.Type == NEWS)) { + echo_in++; + fill_list(&sbl, aka2str(msgs.Aka), NULL, FALSE); + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && + (msgs.Aka.zone == CFG.aka[i].zone) && + !((msgs.Aka.net == CFG.aka[i].net) && + (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, + CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + fseek(pAreas, sysstart, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&Link, sizeof(sysconnect), 1, pAreas); + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause)) { + fill_list(&sbl, aka2str(Link.aka), NULL, FALSE); + } + } + uniq_list(&sbl); + sort_list(&sbl); + + fseek(pAreas, sysstart, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&Link, sizeof(sysconnect), 1, pAreas); + if (Link.aka.zone) + ExportEcho(Link, Number, &sbl); + } + if (strlen(msgs.Newsgroup)) + ExportNews(Number, &sbl); + + tidy_falist(&sbl); + } + if (msgs.Type == NETMAIL) { + ExportNet(Number, FALSE); + most_debug = FALSE; + } + Msg.Local = FALSE; + Msg.Arrived = time(NULL); + Msg_WriteHeader(Number); + Msg_UnLock(); + } + } + + } while (Msg_Next(&Number) == TRUE); + } + + Msg_Close(); + + if (!do_quiet) { + printf(" \b\b\b\b\b\b"); + fflush(stdout); + } + } + + /* + * Make sure to start at the next area. + */ + fseek(pAreas, nextstart, SEEK_SET); + } + } + + fclose(pAreas); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } +} + + + +void ScanOne(char *path, unsigned long MsgNum) +{ + char sAreas[81], sbe[128]; + FILE *pAreas; + long sysstart; + unsigned long Total, Area = 0; + int i; + sysconnect Link; + fa_list *sbl = NULL; + + IsDoing("Scanning mail"); + + if (!do_quiet) { + colour(9, 0); + printf("Scanning mail\n"); + colour(3, 0); + fflush(stdout); + } + + if (strncmp(CFG.bbs_usersdir, path, strlen(CFG.bbs_usersdir)) == 0) { + if (Msg_Open(path)) { + if (((Total = Msg_Number()) != 0L) && (Msg_ReadHeader(MsgNum)) && Msg.Local) { + if (Msg_Lock(15L)) { + scanned++; + ExportEmail(MsgNum); + Msg.Local = FALSE; + Msg.Arrived = time(NULL); + Msg_WriteHeader(MsgNum); + Msg_UnLock(); + } + + } + Msg_Close(); + } else { + WriteError("Can't open %s", path); + } + return; + } + + sprintf(sAreas, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, pAreas); + + /* + * Seek the path we want + */ + while (TRUE) { + if (fread(&msgs, msgshdr.recsize, 1, pAreas) != 1) { + fclose(pAreas); + Syslog('m', "ScanOne() reached end of areas"); + return; + } + Area++; + sysstart = ftell(pAreas); + fseek(pAreas, msgshdr.syssize, SEEK_CUR); + if (strcmp(msgs.Base, path) == 0) + break; + } + + if ((msgs.Active) && (msgs.Type == ECHOMAIL || msgs.Type == NETMAIL || msgs.Type == NEWS)) { + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", Area, msgs.Name); + colour(13, 0); + fflush(stdout); + } + + if (Msg_Open(msgs.Base)) { + if ((Total = Msg_Number()) != 0L) { + if (Msg_ReadHeader(MsgNum)) { + if (Msg.Local) { + if (Msg_Lock(15L)) { + scanned++; + /* + * Setup SEEN-BY lines + */ + if (msgs.Type == ECHOMAIL || msgs.Type == NEWS) { + echo_in++; + fill_list(&sbl, aka2str(msgs.Aka), NULL, FALSE); + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && + (msgs.Aka.zone == CFG.aka[i].zone) && + !((msgs.Aka.net == CFG.aka[i].net) && + (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, + CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + fseek(pAreas, sysstart, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&Link, sizeof(sysconnect), 1, pAreas); + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause)) { + fill_list(&sbl, aka2str(Link.aka), NULL, FALSE); + } + } + uniq_list(&sbl); + sort_list(&sbl); + + fseek(pAreas, sysstart, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&Link, sizeof(sysconnect), 1, pAreas); + if (Link.aka.zone) { + ExportEcho(Link, MsgNum, &sbl); + } + } + if (strlen(msgs.Newsgroup)) + ExportNews(MsgNum, &sbl); + + tidy_falist(&sbl); + } + if (msgs.Type == NETMAIL) { + ExportNet(MsgNum, FALSE); + most_debug = FALSE; + } + + Msg.Local = FALSE; + Msg.Arrived = time(NULL); + Msg_WriteHeader(MsgNum); + Msg_UnLock(); + } + } + + } + } + + Msg_Close(); + } + } else { + WriteError("Config error: area %d not active or not Echo/Netmail area", Area); + } + + fclose(pAreas); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } +} + + + +int RescanOne(faddr *L, char *marea, unsigned long Num) +// Return: 0 -> Ok +// 1 -> Unknown area +// 2 -> Node cant rescan this area +{ + unsigned long Total, MsgNum, Area = 0; + fa_list *sbl = NULL; + fidoaddr *l; + int First, Found; + unsigned long rescanned; + sysconnect Link; + + IsDoing("ReScan mail"); + + if (!do_quiet) { + colour(9, 0); + printf("ReScan mail\n"); + colour(3, 0); + fflush(stdout); + } + + l = faddr2fido( L ); + rescanned = 0L; + if (!SearchMsgs(marea)) { + syslog('+',"ReScan of unknown echo area %s", marea); + return 1; + } + + First = TRUE; + Found = FALSE; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((l->zone == Link.aka.zone) && + (l->net == Link.aka.net) && + (l->node == Link.aka.node) && + (l->point == Link.aka.point)) { + Found = TRUE; + break; + } + } + if (!Found) { + Syslog('+',"Node %s can't Rescan area %s", L, marea); + return 2; + } + + if ((msgs.Active) && (msgs.Type == ECHOMAIL)) { + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", Area, msgs.Name); + colour(13, 0); + fflush(stdout); + } + + if (Msg_Open(msgs.Base)) { + Total = Msg_Number(); + MsgNum = 1; + if (Num!=0 && Numaddr->net - 1; + for (tmpl = *sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(qp, "\rSEEN-BY:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(qp, "%s", sbe); + } + fprintf(qp, "\r\001PATH: %u/%u\r", msgs.Aka.net, msgs.Aka.node); + putc(0, qp); + fclose(qp); + + echo_out++; +} + + + +/* + * Export message to the newsserver. The messagebase is locked. + */ +void ExportNews(unsigned long MsgNum, fa_list **sbl) +{ + char *p; + int seenlen, oldnet, flags = 0; + char sbe[16]; + fa_list *tmpl; + FILE *qp; + faddr *from, *dest; + int is_pid = FALSE, kludges = TRUE; + + qp = tmpfile(); + + Syslog('m', "Msg.From %s", Msg.From); + Syslog('m', "Msg.FromAddress %s", Msg.FromAddress); + Syslog('m', "Msg.To %s", Msg.To); + Syslog('m', "Msg.ToAdrress", Msg.ToAddress); + + flags |= (Msg.Private) ? M_PVT : 0; + from = fido2faddr(msgs.Aka); + + /* + * Add name with echo to news gate. + */ + from->name = xstrcpy(Msg.From); + Syslog('m', "from %s", ascinode(from, 0xff)); + dest = NULL; + + fprintf(qp, "AREA:%s\n", msgs.Tag); + Syslog('m', "AREA:%s", msgs.Tag); + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (kludges) { + if (p[0] != '\001') { + /* + * After the first kludges, send RFC headers + */ + kludges = FALSE; + fprintf(qp, "Subject: %s\n", Msg.Subject); + Syslog('m', "Subject: %s", Msg.Subject); + fprintf(qp, "\n"); + Syslog('m', "\n"); + fprintf(qp, "%s\n", p); + Syslog('m', "%s", p); + } else { + fprintf(qp, "%s\n", p+1); + Syslog('m', "%s", p+1); + } + } else { + if ((strncmp(p, " * Origin:", 10) == 0) && !is_pid) { + /* + * If there was no PID kludge, insert the TID + * kludge anyway. + */ + fprintf(qp, "\001TID: MBSE-FIDO %s\n", VERSION); + Syslog('m', "\\001TID: MBSE-FIDO %s", VERSION); + } + fprintf(qp, "%s", p); + Syslog('m', "%s", printable(p, 0)); + if (strncmp(p, " * Origin:", 10) == 0) + break; + + /* + * Only append NL if not the last line + */ + fprintf(qp, "\n"); + + /* + * Append ^aTID line + */ + if (strncmp(p, "\001PID", 4) == 0) { + fprintf(qp, "\001TID: MBSE-FIDO %s\n", VERSION); + Syslog('m', "\\001TID: MBSE-FIDO %s", VERSION); + is_pid = TRUE; + } + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + seenlen = MAXSEEN + 1; + /* + * Ensure that it will not match the first entry. + */ + oldnet = (*sbl)->addr->net - 1; + for (tmpl = *sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(qp, "\nSEEN-BY:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(qp, "%s", sbe); + } + fprintf(qp, "\n\001PATH: %u/%u\n", msgs.Aka.net, msgs.Aka.node); + Syslog('m', "\\001PATH: %u/%u", msgs.Aka.net, msgs.Aka.node); + + rewind(qp); + most_debug = TRUE; + mkrfcmsg(from, dest, NULL, NULL, Msg.Written + (gmt_offset((time_t)0) * 60), flags, qp, 0L, FALSE); + most_debug = FALSE; + tidy_faddr(from); + fclose(qp); +} + + + +/* + * Export Netmail message, the messagebase is locked. + */ +void ExportNet(unsigned long MsgNum, int UUCPgate) +{ + char *p, *q, ext[4], fromname[37]; + int i, rc, flags = 0, first; + FILE *qp, *fp; + fidoaddr Dest, Route, *dest; + time_t now; + struct tm *tm; + char flavor; + faddr *from, *too, *ta; + int is_fmpt = FALSE, is_topt = FALSE, is_intl = FALSE; + unsigned short point; + char MailFrom[128], MailTo[128]; + + Syslog('m', "Export netmail to %s of %s (%s) %s mode", Msg.To, Msg.ToAddress, + (Msg.Crash || Msg.Direct || Msg.FileAttach) ? "Direct" : "Routed", UUCPgate ? "UUCP" : "Netmail"); + + /* + * Check if this a netmail to our own local UUCP gate. + */ + if ((!strcmp(Msg.To, "UUCP")) && (is_local(parsefnode(Msg.ToAddress)))) { + most_debug = TRUE; + Syslog('m', "We are the UUCP gate"); + Syslog('m', "From %s FromAddress %s", Msg.From, Msg.FromAddress); + if ((fp = tmpfile()) == NULL) { + WriteError("$Can't open tempfile"); + return; + } + from = fido2faddr(msgs.Aka); + sprintf(fromname, "%s", Msg.From); + for (i = 0; i < strlen(fromname); i++) + if (fromname[i] == ' ') + fromname[i] = '_'; + sprintf(MailFrom, "%s@%s", fromname, ascinode(from, 0x2f)); + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (strncmp(p, "To: ", 4) == 0) { + q = strtok(p, "<"); + q = strtok(NULL, ">"); + sprintf(MailTo, "%s", q); + break; + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + /* + * First send all headers + */ + fprintf(fp, "Date: %s\n", rfcdate(Msg.Written)); + fprintf(fp, "From: %s@%s\n", fromname, ascinode(from, 0x2f)); + tidy_faddr(from); + fprintf(fp, "Subject: %s\n", Msg.Subject); + fprintf(fp, "MIME-Version: 1.0\n"); + fprintf(fp, "Content-Type: text/plain\n"); + fprintf(fp, "Content-Transfer-Encoding: 8bit\n"); + fprintf(fp, "X-Mailreader: MBSE BBS %s\r\n", VERSION); + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (p[0] == '\001') { + if (strncmp(p, "\001INTL", 5) == 0) + fprintf(fp, "X-FTN-INTL: %s\n", p+4); + else + fprintf(fp, "X-FTN-%s\n", p+1); + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (p[0] != '\001') { + fprintf(fp, "%s\n", p); + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + postemail(fp, MailFrom, MailTo); + fclose(fp); + return; + } + + if (UUCPgate) { + memcpy(&Dest, &CFG.UUCPgate, sizeof(fidoaddr)); + memset(&msgs, 0, sizeof(msgs)); + memcpy(&msgs.Aka, &CFG.EmailFidoAka, sizeof(fidoaddr)); + } else { + ta = parsefnode(Msg.ToAddress); + dest = faddr2fido(ta); + tidy_faddr(ta); + memcpy(&Dest, dest, sizeof(fidoaddr)); + } + Dest.domain[0] = '\0'; + + if (!(Msg.Crash || Msg.Immediate || Msg.Direct || Msg.FileAttach)) { + if (!TrackMail(Dest, &Route)) { + Syslog('!', "No route to %s, message orphaned", Msg.ToAddress); + Msg.Orphan = TRUE; + net_bad++; + return; + } + } + + Msg.Sent = TRUE; + if (Msg.KillSent) + Msg.Deleted = TRUE; + + if (Msg.Crash || Msg.Direct || Msg.FileAttach || Msg.Immediate) { + memset(&ext, 0, sizeof(ext)); + if (Msg.Immediate) + sprintf(ext, (char *)"iii"); + else if (Msg.Crash) + sprintf(ext, (char *)"ccc"); + else + sprintf(ext, (char *)"nnn"); + point = Dest.point; + Dest.point = 0; + if (point) + Syslog('+', "Routing via Boss %s", aka2str(Dest)); + if ((qp = OpenPkt(msgs.Aka, Dest, (char *)ext)) == NULL) { + net_bad++; + return; + } + Dest.point = point; + + } else { + Syslog('m', "Route via %s", aka2str(Route)); + if (!SearchNode(Route)) { + WriteError("Routing node %s not in setup, aborting", aka2str(Route)); + return; + } + + /* + * Note that even if the exported netmail is not crash, that if + * the routing node has crash status, this netmail will be send + * crash. + */ + memset(&ext, 0, sizeof(ext)); + if (nodes.PackNetmail) + sprintf(ext, (char *)"qqq"); + else if (nodes.Crash) + sprintf(ext, (char *)"ccc"); + else if (nodes.Hold) + sprintf(ext, (char *)"hhh"); + else + sprintf(ext, (char *)"nnn"); + if ((qp = OpenPkt(msgs.Aka, Route, (char *)ext)) == NULL) { + net_bad++; + return; + } + } + + flags |= (Msg.Private) ? M_PVT : 0; + flags |= (Msg.Crash) ? M_CRASH : 0; + flags |= (Msg.Hold) ? M_HOLD : 0; + flags |= (Msg.Immediate) ? M_CRASH : 0; + flags |= (Msg.FileRequest) ? M_REQ : 0; + flags |= (Msg.FileAttach) ? M_FILE : 0; + flags |= (Msg.ReceiptRequest) ? M_RRQ : 0; + flags |= (Msg.ConfirmRequest) ? M_AUDIT : 0; + + too = fido2faddr(Dest); + from = fido2faddr(msgs.Aka); + if (UUCPgate) { + Syslog('m', "AddMsgHdr(%s, %s, %s)", (char *)"UUCP", Msg.From, Msg.Subject); + rc = AddMsgHdr(qp, from, too, flags, 0, Msg.Written, (char *)"UUCP", Msg.From, Msg.Subject); + } else { + rc = AddMsgHdr(qp, from, too, flags, 0, Msg.Written, Msg.To, Msg.From, Msg.Subject); + } + tidy_faddr(from); + tidy_faddr(too); + + if (rc) { + WriteError("Create message failed"); + return; + } + + /* + * Analyze this message if it contains INTL, FMPT and TOPT kludges + * and check if we need them. If they are missing they are inserted. + * GoldED doesn't insert them but MBSE does. + */ + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (strncmp(p, "\001FMPT", 5) == 0) + is_fmpt = TRUE; + if (strncmp(p, "\001TOPT", 5) == 0) + is_topt = TRUE; + if (strncmp(p, "\001INTL", 5) == 0) + is_intl = TRUE; + if (strncmp(p, "--- ", 4) == 0) + break; + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + if (msgs.Aka.point && !is_fmpt) + fprintf(qp, "\001FMPT %d\r", msgs.Aka.point); + if (Dest.point && !is_topt) + fprintf(qp, "\001TOPT %d\r", Dest.point); + if (!is_intl) + fprintf(qp, "\001INTL %d:%d/%d %d:%d/%d\r", Dest.zone, Dest.net, Dest.node, + msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node); + + if (Msg_Read(MsgNum, 78)) { + first = TRUE; + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (UUCPgate && first && (p[0] != '\001')) { + /* + * Past the kludges at the message start. + * Add the To: name@dom.com and a blank line. + */ + fprintf(qp, "To: %s\r", Msg.To); + fprintf(qp, "\r"); + first = FALSE; + } + fprintf(qp, "%s\r", p); + if (strncmp(p, "--- ", 4) == 0) + break; + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + now = time(NULL); + tm = gmtime(&now); + fprintf(qp, "\001Via %s @%d%02d%02d.%02d%02d%02d.01.UTC MBSE BBS %s\r", + aka2str(msgs.Aka), tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, VERSION); + + putc(0, qp); + fclose(qp); + + if (Msg.FileAttach) { + if (Msg.Crash) + flavor = 'c'; + else + flavor = 'f'; + + ta = parsefnode(Msg.ToAddress); + if (strlen(CFG.dospath)) { + rc = attach(*ta, Dos2Unix(Msg.Subject), LEAVE, flavor); + Syslog('+', "FileAttach %s %s", Dos2Unix(Msg.Subject), rc ? "Success":"Failed"); + } else { + rc = attach(*ta, Msg.Subject, LEAVE, flavor); + Syslog('+', "FileAttach %s %s", Msg.Subject, rc ? "Success":"Failed"); + } + tidy_faddr(ta); + } + + net_out++; +} + + + +/* + * Export Email message, the messagebase is locked. + */ +void ExportEmail(unsigned long MsgNum) +{ + char *p; + FILE *qp; + int retval, flags = 0; + faddr *from, *too; + int kludges = TRUE; + + Syslog('m', "Export email to %s", Msg.To); + Msg.Sent = TRUE; + if (Msg.KillSent) + Msg.Deleted = TRUE; + + /* + * For local scanned messages both addresses are the same. + */ + from = fido2faddr(CFG.EmailFidoAka); + too = fido2faddr(CFG.EmailFidoAka); + qp = tmpfile(); + + flags |= (Msg.Private) ? M_PVT : 0; + flags |= (Msg.Crash) ? M_CRASH : 0; + flags |= (Msg.Hold) ? M_HOLD : 0; + flags |= (Msg.Immediate) ? M_CRASH : 0; + flags |= (Msg.FileRequest) ? M_REQ : 0; + flags |= (Msg.FileAttach) ? M_FILE : 0; + flags |= (Msg.ReceiptRequest) ? M_RRQ : 0; + flags |= (Msg.ConfirmRequest) ? M_AUDIT : 0; + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (p[0] == '\001') { + fprintf(qp, "%s\n", p+1); + if (!strncmp(p, "\001PID:", 5)) { + fprintf(qp, "TID: MBSE-FIDO %s\n", VERSION); + } + } else { + if (kludges) { + kludges = FALSE; + fprintf(qp, "\n"); + } + fprintf(qp, "%s\n", p); + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + rewind(qp); + most_debug = TRUE; + retval = mkrfcmsg(from, too, Msg.Subject, NULL, Msg.Written, flags, qp, 0L, TRUE); + most_debug = FALSE; + Syslog('m', "mkrfcmsg rc=%d", retval); + email_out++; +} + diff --git a/mbfido/scan.h b/mbfido/scan.h new file mode 100644 index 00000000..4a655674 --- /dev/null +++ b/mbfido/scan.h @@ -0,0 +1,10 @@ +#ifndef _SCAN_H +#define _SCAN_H + + +void ScanMail(int); +int RescanOne(faddr *, char *, unsigned long); + + +#endif + diff --git a/mbfido/scannews.c b/mbfido/scannews.c new file mode 100644 index 00000000..c7fe85d8 --- /dev/null +++ b/mbfido/scannews.c @@ -0,0 +1,1437 @@ +/***************************************************************************** + * + * File ..................: mbfido/scannews.c + * Purpose ...............: Scan for new News + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "../lib/dbdupe.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "mkftnhdr.h" +#include "hash.h" +#include "echoout.h" +#include "rollover.h" +#include "pack.h" +#include "scannews.h" + + +#define MAXHDRSIZE 2048 +#define MAXSEEN 70 +#define MAXPATH 73 + + +/* + * Global variables + */ +POverview xoverview = NULL; +int marker = 0; +static int ftnorigin; +static int removemime; +static int removemsgid; +static int removeref; +static int removeinreply; +static int removesupersedes; +static int removeapproved; +static int removereplyto; +static int removereturnto; +static int dirtyoutcode = CHRS_NOTSET; + + + +/* + * External variables + */ +extern int do_quiet; +extern int do_learn; +extern int most_debug; +extern int news_in; +extern int news_imp; +extern int news_dupe; +extern int echo_out; +extern int echo_in; +extern char *replyaddr; + +extern char *toname; /* To user */ +extern char *fromname; /* From user */ +extern char *subj; /* Message subject */ + + +/* + * Internal functions + */ +int do_one_group(List **, char *, char *); +int get_xover(char *, long, long, List **); +int get_xoverview(void); +void tidy_artlist(List **); +void fill_artlist(List **, char *, long, int); +void Marker(void); +int get_article(char *, char *); +int needputrfc(rfcmsg *); + + +void tidy_artlist(List **fdp) +{ + List *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add article to the list + */ +void fill_artlist(List **fdp, char *id, long nr, int dupe) +{ + List **tmp; + + Syslog('N', "Fill %s %ld %s", id, nr, dupe ? "Dupe":"New msg"); + + for (tmp = fdp; *tmp; tmp = &((*tmp)->next)); + *tmp = (List *)malloc(sizeof(List)); + (*tmp)->next = NULL; + sprintf((*tmp)->msgid, "%s", id); + (*tmp)->nr = nr; + (*tmp)->isdupe = dupe; +} + + + +/* + * write an arbitrary line to message body, + * if a line starts with three dashes, insert a dash and a blank + */ +int charwrite(char *, FILE *); +int charwrite(char *s, FILE *fp) +{ + if ((strlen(s) >= 3) && (strncmp(s,"---",3) == 0) && (s[3] != '-')) { + putc('-',fp); + putc(' ',fp); + } + while (*s) { + putc(*s, fp); + s++; + } + return 0; +} + + + +/* + * write (multiline) header to kluge: change \n to ' ' and end line with \n + */ +int kludgewrite(char *, FILE *); +int kludgewrite(char *s, FILE *fp) +{ + while (*s) { + if (*s == '\r') + putc('\n', fp); + else { + if (*s != '\n') + putc(*s, fp); + else if (*(s+1)) + putc(' ',fp); + } + s++; + } + putc('\n',fp); + return 0; +} + + + +void Marker(void) +{ + if (do_quiet) + return; + + switch (marker) { + case 0: printf(">---"); + break; + + case 1: printf(">>--"); + break; + + case 2: printf(">>>-"); + break; + + case 3: printf(">>>>"); + break; + + case 4: printf("<>>>"); + break; + + case 5: printf("<<>>"); + break; + + case 6: printf("<<<>"); + break; + + case 7: printf("<<<<"); + break; + + case 8: printf("-<<<"); + break; + + case 9: printf("--<<"); + break; + + case 10:printf("---<"); + break; + + case 11:printf("----"); + break; + } + printf("\b\b\b\b"); + fflush(stdout); + + if (marker < 11) + marker++; + else + marker = 0; +} + + + +/* + * Scan for new news available at the nntp server. + */ +void ScanNews(void) +{ + List *art = NULL; + POverview tmp, old; + FILE *pAreas; + char *sAreas; + struct msgareashdr Msgshdr; + struct msgareas Msgs; + + IsDoing((char *)"Scan News"); + if (nntp_connect() == -1) { + WriteError("Can't connect to newsserver"); + return; + } + if (get_xoverview()) + return; + + if (!do_quiet) { + colour(10, 0); + printf("Scan for new news articles\n"); + } + + sAreas = calloc(PATH_MAX, sizeof(char)); + sprintf(sAreas, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if(( pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open Messages Areas File."); + return; + } + fread(&Msgshdr, sizeof(Msgshdr), 1, pAreas); + + while (fread(&Msgs, Msgshdr.recsize, 1, pAreas) == 1) { + fseek(pAreas, Msgshdr.syssize, SEEK_CUR); + if ((Msgs.Active) && strlen(Msgs.Newsgroup)) { + if (IsSema((char *)"upsalarm")) { + Syslog('+', "Detected upsalarm semafore, aborting newsscan"); + break; + } + Syslog('n', "Scan newsgroup: %s", Msgs.Newsgroup); + if (!do_quiet) { + colour(3, 0); + printf("\r%-40s", Msgs.Newsgroup); + fflush(stdout); + } + Nopper(); + if (do_one_group(&art, Msgs.Newsgroup, Msgs.Tag) == RETVAL_ERROR) + break; + } + } + fclose(pAreas); + free(sAreas); + + for (tmp = xoverview; tmp; tmp = old) { + old = tmp->next; + if (tmp->header) + free(tmp->header); + if (tmp->field) + free(tmp->field); + free(tmp); + } + packmail(); + + if (!do_quiet) + printf("\r \r"); +} + + + +int do_one_group(List **art, char *grpname, char *ftntag) +{ + List *tmp; + char temp[128], *resp; + int retval; + long total, start, end; + + Syslog('N', "do_one_group(%s, %s)", grpname, ftntag); + IsDoing((char *)"Scan %s", grpname); + sprintf(temp, "GROUP %s\r\n", grpname); + nntp_send(temp); + resp = nntp_receive(); + retval = atoi(strtok(resp, " ")); + if (retval != 211) { + if (retval == 411) + WriteError("No such newsgroup: %s", grpname); + else + WriteError("Unknown response %d to GROUP command", retval); + return RETVAL_ERROR; + } + + total = atol(strtok(NULL, " ")); + start = atol(strtok(NULL, " ")); + end = atol(strtok(NULL, " '\0'")); + if (!total) { + Syslog('N', "No articles"); + return RETVAL_OK; + } + + retval = get_xover(grpname, start, end, art); + if (retval != RETVAL_OK) { + tidy_artlist(art); + return retval; + } + + if (!do_learn) { + for (tmp = *art; tmp; tmp = tmp->next) { + if (!tmp->isdupe) { + /* + * If the message isn't a dupe, it must be new for us. + */ + most_debug = TRUE; + get_article(tmp->msgid, ftntag); + most_debug = FALSE; + } + } + } + + tidy_artlist(art); + return RETVAL_OK; +} + + + +int get_article(char *msgid, char *ftntag) +{ + char cmd[81], *resp; + int retval, done = FALSE; + FILE *fp = NULL; + + Syslog('n', "Get article %s, %s", msgid, ftntag); + if (!SearchMsgs(ftntag)) { + WriteError("Search message area %s failed", ftntag); + return RETVAL_ERROR; + } + IsDoing("Article %d", (news_in + 1)); + sprintf(cmd, "ARTICLE %s\r\n", msgid); + nntp_send(cmd); + resp = nntp_receive(); + retval = atoi(strtok(resp, " ")); + switch (retval) { + case 412: WriteError("No newsgroup selected"); + return RETVAL_UNEXPECTEDANS; + case 420: WriteError("No current article has been selected"); + return RETVAL_UNEXPECTEDANS; + case 423: WriteError("No such article in this group"); + return RETVAL_UNEXPECTEDANS; + case 430: WriteError("No such article found"); + return RETVAL_UNEXPECTEDANS; + case 220: if ((fp = tmpfile()) == NULL) { + WriteError("$Can't open tmpfile"); + return RETVAL_UNEXPECTEDANS; + } + while (done == FALSE) { + resp = nntp_receive(); + if ((strlen(resp) == 1) && (strcmp(resp, ".") == 0)) { + done = TRUE; + } else { + fwrite(resp, strlen(resp), 1, fp); + fputc('\n', fp); + } + } + break; + } + + news_in++; + IsDoing("Article %d", (news_in)); + retval = do_article(fp); + fclose(fp); + return retval; +} + + + +int do_article(FILE *fp) +{ + char sbe[16], *p, *q, *temp; + int i, incode, outcode, pgpsigned; + int First = TRUE, seenlen, oldnet; + sysconnect Link; + rfcmsg *msg = NULL, *tmsg, *tmp; + ftnmsg *fmsg = NULL; + FILE *ofp; + fa_list *sbl = NULL, *ptl = NULL, *tmpl; + faddr *ta, *From; + unsigned long svmsgid, svreply; + int sot_kludge = FALSE, eot_kludge = FALSE, qp_or_base64 = FALSE, tinyorigin = FALSE; + int needsplit, hdrsize, datasize, splitpart, forbidsplit, rfcheaders; + char newsubj[4 * (MAXSUBJ+1)], *oldsubj, *acup_a = NULL; + unsigned long acup_n = 0, crc2; + int html_message = FALSE; + time_t Now; + + rewind(fp); + msg = parsrfc(fp); + incode = outcode = CHRS_NOTSET; + pgpsigned = FALSE; + + p = hdr((char *)"Content-Type",msg); + if (p) + incode=readcharset(p); + if (incode == CHRS_NOTSET) { + p = hdr((char *)"X-FTN-CHRS",msg); + if (p == NULL) + p = hdr((char *)"X-FTN-CHARSET", msg); + if (p == NULL) + p = hdr((char *)"X-FTN-CODEPAGE", msg); + if (p) + incode = readchrs(p); + } + + if ((p = hdr((char *)"Content-Type",msg)) && ((strcasestr(p,(char *)"multipart/signed")) || + (strcasestr(p,(char *)"application/pgp")))) { + pgpsigned = TRUE; + outcode = incode; + } else if ((p = hdr((char *)"X-FTN-ORIGCHRS", msg))) + outcode = readchrs(p); + else if (dirtyoutcode != CHRS_NOTSET) + outcode = dirtyoutcode; + else + outcode = getoutcode(incode); + for (tmsg = msg; tmsg; tmsg = tmsg->next) + if (strcasecmp(tmsg->key, "X-FTN-SEEN-BY") == 0) + fill_list(&sbl, tmsg->val, NULL, TRUE); + + if (!CFG.allowcontrol) { + if (hdr((char *)"Control",msg)) { + Syslog('n', "skipping news message"); + tidy_falist(&sbl); + tidyrfc(msg); + return RETVAL_OK; + } + } + + if ((fmsg = mkftnhdr(msg, incode, outcode, TRUE)) == NULL) { + WriteError("Unable to create FTN headers from RFC ones, aborting"); + tidy_falist(&sbl); + tidyrfc(msg); + return RETVAL_ERROR; + } + + /* + * Setup PATH line + */ + sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node); + fill_path(&ptl, sbe); + fmsg->area = xstrcpy(msgs.Tag); + svmsgid = fmsg->msgid_n; + svreply = fmsg->reply_n; + if ((p = hdr((char *)"Message-ID",msg))) { + ftnmsgid(p, &fmsg->msgid_a, &fmsg->msgid_n, fmsg->area); + hash_update_s(&fmsg->msgid_n, fmsg->area); + } + + if ((p = hdr((char *)"References",msg))) { + p = strrchr(p,' '); + ftnmsgid(p,&fmsg->reply_a, &fmsg->reply_n,fmsg->area); + if (!chkftnmsgid(p)) { + hash_update_s(&fmsg->reply_n, fmsg->area); + } + } else if ((p = hdr((char *)"In-Reply-To",msg))) { + ftnmsgid(p,&fmsg->reply_a, &fmsg->reply_n,fmsg->area); + if (!chkftnmsgid(p)) { + hash_update_s(&fmsg->reply_n, fmsg->area); + } + } + + if (incode == CHRS_NOTSET) + incode = msgs.Rfccode; + if (outcode == CHRS_NOTSET) + outcode = msgs.Ftncode; + if ((incode == CHRS_NOTSET) && (hdr((char *)"Message-ID",msg))) { + if (chkftnmsgid(hdr((char *)"Message-ID",msg))) + incode = CHRS_DEFAULT_FTN; + else + incode = CHRS_DEFAULT_RFC; + } + temp = calloc(4096, sizeof(char)); + removemime = FALSE; + removemsgid = FALSE; + removeref = FALSE; + removeinreply = FALSE; + removesupersedes = FALSE; + removeapproved = FALSE; + removereplyto = TRUE; + removereturnto = TRUE; + ftnorigin = fmsg->ftnorigin; + if ((hdr((char *)"X-PGP-Signed",msg))) + pgpsigned = TRUE; + if (pgpsigned) + Syslog('n', "pgpsigned = %s", pgpsigned ? "True":"False"); + + q = hdr((char *)"Content-Transfer-Encoding",msg); + if (q) + while (*q && isspace(*q)) + q++; + if (!(q)) + q = (char *)"8bit"; + if ((p = hdr((char *)"Content-Type",msg))) { + while (*p && isspace(*p)) + p++; + + /* + * turn the quoted-printable decode mode on; remember FTN is virtually 8-bit clean + */ + if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "quoted-printable", 16) == 0)) + qp_or_base64 = 1; + /* + * turn the base64 decode mode on + */ + else if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "base64", 6) == 0)) + qp_or_base64 = 2; + + /* + * text/html support from FSC-HTML 001 proposal of Odinn Sorensen (2:236/77) + */ + if (strncasecmp(p, "text/html", 9) == 0) + html_message = TRUE; + for (tmp = msg; tmp; tmp = tmp->next) + if (((strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0) && (strcasecmp(tmp->val,"FSCHTML") == 0)) || + (strcasecmp(tmp->key,"X-FTN-HTML") == 0)) + html_message = FALSE; + + if ((readcharset(p) != CHRS_NOTSET ) && ((q == NULL) || (strncasecmp(q,"7bit",4) == 0) || + ((!pgpsigned) && (qp_or_base64==1)) || ((!pgpsigned) && (qp_or_base64==2)) || (strncasecmp(q,"8bit",4) == 0))) + removemime=1; /* no need in MIME headers */ + /* + * some old MUA puts "text" instead of "text/plain; charset=..." + */ + else if ((strcasecmp(p,"text\n") == 0)) + removemime = TRUE; + } + if (removemime || qp_or_base64 || html_message) + Syslog('n', "removemime=%s, qp_or_base64 = %d, html_message=%s", removemime ? "True":"False", qp_or_base64, + html_message ? "True":"False"); + + if ((p = hdr((char *)"Message-ID",msg))) { + if (!removemsgid) + removemsgid = chkftnmsgid(p); + } + Syslog('n', "removemsgid = %s", removemsgid ? "True":"False"); + + if ((!removeref) && (p = hdr((char *)"References",msg))) { + p = xstrcpy(p); + q = strtok(p," \t\n"); + if ((q) && (strtok(NULL," \t\n") == NULL)) + removeref = chkftnmsgid(q); + free(p); + } + if (removeref) + Syslog('n', "removeref = %s", removeref ? "True":"False"); + + if ((p = hdr((char *)"Supersedes",msg))) + removesupersedes = chkftnmsgid(p); + if (removesupersedes) + Syslog('n', "removesupersedes = %s", removesupersedes ? "True":"False"); + + if ((p = hdr((char *)"Approved",msg))) { + while (*p && isspace(*p)) + p++; + if ((q = strchr(p,'\n'))) + *q='\0'; + if (strlen(msgs.Moderator) && (strcasestr(msgs.Moderator,p))) + removeapproved = TRUE; + if (q) + *q='\n'; + } + if (removeapproved) + Syslog('n', "removeapproved = %s", removeapproved ? "True":"False"); + + if ((p = hdr((char *)"Reply-To",msg))) { + removereplyto = FALSE; + if ((q = hdr((char *)"From",msg))) { + char *r; + r = xstrcpy(p); + p = r; + while(*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereplyto = TRUE; + free(r); + } + } + Syslog('n', "removereplyto = %s", removereplyto ? "True":"False"); + + if ((p = hdr((char *)"Return-Receipt-To",msg))) { + removereturnto = FALSE; + if ((q = hdr((char *)"From",msg))) { + char *r; + + r = xstrcpy(p); + p = r; + while (*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereturnto = TRUE; +// free(r); + } + } + if (!removereturnto) + Syslog('n', "removereturnto = %s", removereturnto ? "True":"False"); + + p = ascfnode(fmsg->from,0x1f); + i = 79-11-3-strlen(p); + if (ftnorigin && fmsg->origin && (strlen(fmsg->origin) > i)) { + /* This is a kludge... I don't like it too much. But well, + if this is a message of FTN origin, the original origin (:) + line MUST have been short enough to fit in 79 chars... + So we give it a try. Probably it would be better to keep + the information about the address format from the origin + line in a special X-FTN-... header, but this seems even + less elegant. Any _good_ ideas, anyone? */ + + /* OK, I am keeping this, though if should never be used + al long as X-FTN-Origin is used now */ + + p = ascfnode(fmsg->from,0x0f); + Syslog('n', "checkorigin 3"); + i = 79-11-3-strlen(p); + tinyorigin = TRUE; + } + if (tinyorigin) + Syslog('n', "tinyorigin = %s", tinyorigin ? "True":"False"); + + if ((fmsg->origin) && (strlen(fmsg->origin) > i)) + fmsg->origin[i]='\0'; + forbidsplit = (ftnorigin || (hdr((char *)"X-FTN-Split",msg))); + needsplit = 0; + splitpart = 0; + hdrsize = 20; + hdrsize += (fmsg->subj)?strlen(fmsg->subj):0; + if (fmsg->from) + hdrsize += (fmsg->from->name)?strlen(fmsg->from->name):0; + if (fmsg->to) + hdrsize += (fmsg->to->name)?strlen(fmsg->to->name):0; + do { + Syslog('n', "split loop, splitpart = %d", splitpart); + datasize = 0; + + if (splitpart) { + sprintf(newsubj,"[part %d] ",splitpart+1); + strncat(newsubj,fmsg->subj,MAXSUBJ-strlen(newsubj)); + } else { + strncpy(newsubj,fmsg->subj,MAXSUBJ); + } + strcpy(newsubj, hdrnconv(newsubj, incode, outcode, MAXSUBJ)); + newsubj[MAXSUBJ]='\0'; + + if (splitpart) { + hash_update_n(&fmsg->msgid_n,splitpart); + } + oldsubj = fmsg->subj; + fmsg->subj = newsubj; + + /* + * Create a new temp message in FTN style format + */ + if ((ofp = tmpfile()) == NULL) { + WriteError("$Can't open second tmpfile"); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidyrfc(msg); + return RETVAL_ERROR; + } + fprintf(ofp, "AREA:%s\n", msgs.Tag); + fprintf(ofp, "\001MSGID: %s %08lx\n", MBSE_SS(fmsg->msgid_a),fmsg->msgid_n); + if (fmsg->reply_s) + fprintf(ofp, "\1REPLY: %s\n", fmsg->reply_s); + else if (fmsg->reply_a) + fprintf(ofp, "\1REPLY: %s %08lx\n", fmsg->reply_a, fmsg->reply_n); + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + fprintf(ofp, "\001TZUTC: %s\n", gmtoffset(Now)); + fmsg->subj = oldsubj; + if ((p = hdr((char *)"X-FTN-REPLYADDR",msg))) { + Syslog('n', "replyaddr 1 %s", p); + hdrsize += 10+strlen(p); + fprintf(ofp,"\1REPLYADDR:"); + kludgewrite(p,ofp); + } else if (replyaddr) { + Syslog('n', "replyaddr 2"); + hdrsize += 10+strlen(replyaddr); + fprintf(ofp,"\1REPLYADDR: "); + kludgewrite(replyaddr,ofp); + } + if ((p = hdr((char *)"X-FTN-REPLYTO",msg))) { + hdrsize += 8+strlen(p); + fprintf(ofp,"\1REPLYTO:"); + kludgewrite(p,ofp); + } else if (replyaddr) { + hdrsize += 15; + fprintf(ofp,"\1REPLYTO: %s UUCP\n", aka2str(msgs.Aka)); + } else if ((p = hdr((char *)"Reply-To",msg))) { + if ((ta = parsefaddr(p))) { + if ((q = hdr((char *)"From",msg))) { + if (!strcasestr(q,p)) { + fprintf(ofp,"\1REPLYTO: %s %s\n", ascfnode(ta,0x1f), ta->name); + } + tidy_faddr(ta); + } + } + } + if ((p=strip_flags(hdr((char *)"X-FTN-FLAGS",msg)))) { + hdrsize += 15; + fprintf(ofp,"\1FLAGS:%s\n",p); + free(p); + } + if (!hdr((char *)"X-FTN-PID", msg)) { + p = hdr((char *)"User-Agent", msg); + if (p == NULL) + p = hdr((char *)"X-Newsreader", msg); + if (p == NULL) + p = hdr((char *)"X-Mailer", msg); + if (p) { + hdrsize += 4 + strlen(p); + fprintf(ofp, "\1PID:"); + kludgewrite(p, ofp); + } else { + fprintf(ofp, "\001PID: MBSE-FIDO %s\n", VERSION); + } + } + + hdrsize += 8 + strlen(getchrs(outcode)); + fprintf(ofp, "\001CHRS: %s\n", getchrs(outcode)); + if (html_message) { + hdrsize += 9; + fprintf(ofp, "\1HTML: 5\n"); + } + + if (CFG.allowcontrol && (!hdr((char *)"X-FTN-ACUPDATE",msg)) && (p=hdr((char *)"Control",msg))) { + if (strstr(p,"cancel")) { + ftnmsgid(p,&acup_a,&acup_n,fmsg->area); + if (acup_a) { + hash_update_s(&acup_n,fmsg->area); + hdrsize += 26 + strlen(acup_a); + fprintf(ofp,"\1ACUPDATE: DELETE %s %08lx\n", acup_a,acup_n); + } + } + } + if ((!hdr((char *)"X-FTN-ACUPDATE",msg)) && (p=hdr((char *)"Supersedes",msg))) { + ftnmsgid(p,&acup_a,&acup_n,fmsg->area); + if (acup_a) { + hash_update_s(&acup_n,fmsg->area); + hdrsize += 26 + strlen(acup_a); + fprintf(ofp,"\1ACUPDATE: MODIFY %s %08lx\n", acup_a,acup_n); + } + } +#ifdef FSC_0070 + /* FSC-0070 */ + if((p = hdr((char *)"Message-ID", msg)) && !(hdr((char *)"X-FTN-RFCID", msg))) { + q = strdup(p); + fprintf(ofp,"\1RFCID:"); + if ((l = strrchr(q, '<')) && (r = strchr(q, '>')) && (l < r)) { + *l++ = ' '; + while(*l && isspace(*l)) + l++; + l--; /* leading ' ' */ + *r-- = '\0'; + while(*r && isspace(*r)) + *r-- = '\0'; + } else + l = q; + kludgewrite(l, ofp); + hdrsize += 6 + strlen(l); + free(q); + } +#endif /* FSC_0070 */ + + if (!(hdr((char *)"X-FTN-Tearline", msg)) && !(hdr((char *)"X-FTN-TID", msg))) { + sprintf(temp, " MBSE-FIDO %s", VERSION); + hdrsize += 4 + strlen(temp); + fprintf(ofp, "\1TID:"); + kludgewrite(temp, ofp); + } + if ((splitpart == 0) || (hdrsize < MAXHDRSIZE)) { + for (tmp = msg; tmp; tmp = tmp->next) { + if ((!strncmp(tmp->key,"X-Fsc-",6)) || + (!strncmp(tmp->key,"X-FTN-",6) && + strcasecmp(tmp->key,"X-FTN-Tearline") && + strcasecmp(tmp->key,"X-FTN-Origin") && + strcasecmp(tmp->key,"X-FTN-Sender") && + strcasecmp(tmp->key,"X-FTN-Split") && + strcasecmp(tmp->key,"X-FTN-FLAGS") && + strcasecmp(tmp->key,"X-FTN-AREA") && + strcasecmp(tmp->key,"X-FTN-MSGID") && + strcasecmp(tmp->key,"X-FTN-REPLY") && + strcasecmp(tmp->key,"X-FTN-SEEN-BY") && + strcasecmp(tmp->key,"X-FTN-PATH") && + strcasecmp(tmp->key,"X-FTN-REPLYADDR") && + strcasecmp(tmp->key,"X-FTN-REPLYTO") && + strcasecmp(tmp->key,"X-FTN-To") && + strcasecmp(tmp->key,"X-FTN-From") && + strcasecmp(tmp->key,"X-FTN-CHARSET") && + strcasecmp(tmp->key,"X-FTN-CHRS") && + strcasecmp(tmp->key,"X-FTN-CODEPAGE") && + strcasecmp(tmp->key,"X-FTN-ORIGCHRS") && + strcasecmp(tmp->key,"X-FTN-SOT") && + strcasecmp(tmp->key,"X-FTN-EOT") && + strcasecmp(tmp->key,"X-FTN-Via"))) { + if ((strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0)) { + if (!strcasecmp(tmp->val," SOT:\n")) + sot_kludge = TRUE; + else if (!strcasecmp(tmp->val," EOT:\n")) + eot_kludge = TRUE; + else { + hdrsize += strlen(tmp->val); + fprintf(ofp,"\1"); + /* we should have restored the original string here... */ + kludgewrite((tmp->val)+1,ofp); + } + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1%s:",tmp->key+6); + kludgewrite(tmp->val,ofp); + } + } + } + /* ZConnect are X-ZC-*: in usenet, \1ZC-*: in FTN */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,"X-ZC-",5))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1%s:",tmp->key+2); + kludgewrite(tmp->val,ofp); + } + + /* mondo.org gateway uses ".MSGID: ..." in usenet */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,".",1)) && (strcasecmp(tmp->key,".MSGID"))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1%s:",tmp->key+1); + kludgewrite(tmp->val,ofp); + } + rfcheaders=0; + for (tmp = msg; tmp; tmp = tmp->next) { + if ((needputrfc(tmp) == 1)) { + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(ofp,"\1RFC-Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1RFC-%s:",tmp->key); + } + kludgewrite(hdrconv(tmp->val, incode, outcode),ofp); + } + } + + for (tmp=msg;tmp;tmp=tmp->next) { + if ((needputrfc(tmp) > 1)) { + rfcheaders++; + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(ofp,"Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"%s:",tmp->key); + } + charwrite(hdrconv(tmp->val, incode, outcode),ofp); + } + } + if (rfcheaders) + charwrite((char *)"\n",ofp); + if ((hdr((char *)"X-FTN-SOT",msg)) || (sot_kludge)) + fprintf(ofp,"\1SOT:\n"); + if ((splitpart == 0) && (hdr((char *)"X-PGP-Signed",msg))) + fprintf(ofp,PGP_SIGNED_BEGIN"\n"); + } + if (replyaddr) { +// free(replyaddr); /* Gives SIGSEGV */ + replyaddr = NULL; + } + if (needsplit) { + fprintf(ofp," * Continuation %d of a split message *\n\n", splitpart); + needsplit = FALSE; + } else if ((p=hdr((char *)"X-Body-Start",msg))) { + datasize += strlen(p); + if (qp_or_base64==1) + charwrite(strkconv(qp_decode(p), incode, outcode), ofp); + else if (qp_or_base64==2) + charwrite(strkconv(b64_decode(p), incode, outcode), ofp); + else + charwrite(strkconv(p, incode, outcode), ofp); + } + while (!(needsplit=(!forbidsplit) && (((splitpart && (datasize > (CFG.new_split * 1024))) || + (!splitpart && ((datasize+hdrsize) > (CFG.new_split * 1024)))))) && (bgets(temp,4096-1,fp))) { + datasize += strlen(temp); + if (qp_or_base64==1) + charwrite(strkconv(qp_decode(temp), incode, outcode), ofp); + else if (qp_or_base64==2) + charwrite(strkconv(b64_decode(temp), incode, outcode), ofp); + else + charwrite(strkconv(temp, incode, outcode), ofp); + } + if (needsplit) { + fprintf(ofp,"\n * Message split, to be continued *\n"); + splitpart++; + } else if ((p=hdr((char *)"X-PGP-Signed",msg))) { + fprintf(ofp,PGP_SIG_BEGIN"\n"); + if ((q=hdr((char *)"X-PGP-Version",msg))) { + fprintf(ofp,"Version:"); + charwrite(q,ofp); + } + if ((q=hdr((char *)"X-PGP-Charset",msg))) { + fprintf(ofp,"Charset:"); + charwrite(q,ofp); + } + if ((q=hdr((char *)"X-PGP-Comment",msg))) { + fprintf(ofp,"Comment:"); + charwrite(q,ofp); + } + fprintf(ofp,"\n"); + p=xstrcpy(p); + q=strtok(p," \t\n"); + fprintf(ofp,"%s\n",q); + while ((q=(strtok(NULL," \t\n")))) + fprintf(ofp,"%s\n",q); + fprintf(ofp,PGP_SIG_END"\n"); + } + if ((p=hdr((char *)"X-FTN-EOT",msg)) || (eot_kludge)) + fprintf(ofp,"\1EOT:\n"); + + if ((p=hdr((char *)"X-FTN-Tearline",msg))) { + fprintf(ofp,"---"); + if (strcasecmp(p," (none)\n") == 0) + charwrite((char *)"\n",ofp); + else + charwrite(p,ofp); + } else + fprintf(ofp,"--- MBSE BBSv.%s\n",VERSION); + + if ((p = hdr((char *)"X-FTN-Origin",msg))) { + if (*(q=p+strlen(p)-1) == '\n') + *q='\0'; + fprintf(ofp," * Origin:"); + charwrite(hdrconv(p, incode, outcode),ofp); + } else { + fprintf(ofp," * Origin: "); /* strlen=11 */ + if (fmsg->origin) + charwrite(hdrconv(fmsg->origin, incode, outcode), ofp); + else + charwrite(CFG.origin, ofp); + fprintf(ofp," (%s)", + ascfnode(fmsg->from,tinyorigin?0x0f:0x1f)); + } + /* + * Setup SEEN-BY lines + */ + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (msgs.Aka.zone == CFG.aka[i].zone) && + !((msgs.Aka.net == CFG.aka[i].net) && (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node); + First = TRUE; + /* + * Count downlinks, if there are none then no more SEEN-BY entries will be added. + */ + i = 0; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) { + sprintf(sbe, "%u/%u", Link.aka.net, Link.aka.node); + fill_list(&sbl, sbe, NULL, FALSE); + i++; + } + } + uniq_list(&sbl); + sort_list(&sbl); + seenlen=MAXSEEN+1; + if (i) { + /* ensure it will not match for the first entry */ + oldnet = sbl->addr->net-1; + for (tmpl = sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe," %u",tmpl->addr->node); + else + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(ofp,"\nSEEN-BY:"); + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(ofp,"%s",sbe); + } + } else { + fprintf(ofp,"\nSEEN-BY: %s",sbe); + } + + for (tmp = msg; tmp; tmp = tmp->next) { + if (!strcasecmp(tmp->key,"X-FTN-PATH")) { + fill_path(&ptl,tmp->val); + } + } + sprintf(sbe,"%u/%u",msgs.Aka.net, msgs.Aka.node); + fill_path(&ptl,sbe); + uniq_list(&ptl); + seenlen = MAXPATH+1; + /* ensure it will not match for the first entry */ + oldnet = ptl->addr->net-1; + for (tmpl = ptl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe," %u",tmpl->addr->node); + else + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXPATH) { + seenlen = 0; + fprintf(ofp,"\n\1PATH:"); + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(ofp,"%s",sbe); + } + fprintf(ofp,"\n"); + + tidy_falist(&ptl); + fflush(ofp); + rewind(ofp); + Syslog('n', "========== Fido start"); + while (fgets(temp, 4096, ofp) != NULL) { + /* + * Only log kludges, skip the body + */ + if ((temp[0] == '\001') || !strncmp(temp, "AREA:", 5) || !strncmp(temp, "SEEN-BY", 7)) { + Striplf(temp); + Syslogp('n', printable(temp, 0)); + } + } + Syslog('n', "========== Fido end"); + + rewind(ofp); + Msg_New(); + + if ((fmsg->to != NULL) && (fmsg->to->name != NULL)) + strcpy(Msg.To, fmsg->to->name); + else + sprintf(Msg.To, "All"); + Syslog('n', "Msg.To: %s", printable(Msg.To, 0)); + toname = xstrcpy(Msg.To); + + if ((fmsg->from != NULL) && (fmsg->from->name != NULL)) { + strcpy(Msg.From, fmsg->from->name); + Syslog('n', "Msg.From: %s", printable(Msg.From, 0)); + fromname = xstrcpy(Msg.From); + } else { + Syslog('n', "Warning: no Msg.From name found"); + } + + strcpy(Msg.Subject, fmsg->subj); + subj = xstrcpy(Msg.Subject); + Msg.Echomail = TRUE; + Msg.Written = fmsg->date; + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + sprintf(Msg.FromAddress, "%s", aka2str(msgs.Aka)); + /* + * These are the only usefull flags in echomail + */ + if ((fmsg->flags & M_PVT) && ((msgs.MsgKinds == BOTH) || (msgs.MsgKinds == PRIVATE))) + Msg.Private = TRUE; + if (fmsg->flags & M_FILE) + Msg.FileAttach = TRUE; + + /* + * Set MSGID and REPLYID crc. + */ + if (fmsg->msgid_a != NULL) { + crc2 = -1; + Msg.MsgIdCRC = upd_crc32(fmsg->msgid_a, crc2, strlen(fmsg->msgid_a)); + } + if (fmsg->reply_a != NULL) { + crc2 = -1; + Msg.ReplyCRC = upd_crc32(fmsg->reply_a, crc2, strlen(fmsg->reply_a)); + } + + if (Msg_Open(msgs.Base)) { + if (Msg_Lock(30L)) { + rewind(ofp); + fgets(temp, 2048, ofp); /* "Eat" the first line AREA:... */ + Msg_Write(ofp); + Msg_AddMsg(); + Msg_UnLock(); + echo_in++; + Syslog('+', "Newsgate %s => %s msg %ld", msgs.Newsgroup, msgs.Tag, Msg.Id); + } + Msg_Close(); + StatAdd(&msgs.Received, 1); + time(&msgs.LastRcvd); + StatAdd(&mgroup.MsgsRcvd, 1); + time(&mgroup.LastDate); + } + + /* + * Now start exporting this echomail. + */ + First = TRUE; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) { + if (SearchNode(Link.aka)) { + StatAdd(&nodes.MailSent, 1L); + UpdateNode(); + SearchNode(Link.aka); + } + echo_out++; + Syslog('n', "Export to %s", aka2str(Link.aka)); + From = fido2faddr(msgs.Aka); + EchoOut(From, Link.aka, ofp, fmsg->flags, 0, fmsg->date); + tidy_faddr(From); + } + } + + free(fromname); + free(toname); + free(subj); + fclose(ofp); + } while (needsplit); + tidy_falist(&sbl); + tidy_falist(&ptl); + free(temp); + news_imp++; + tidyrfc(msg); + tidy_ftnmsg(fmsg); + UpdateMsgs(); + + return RETVAL_OK; +} + + + +int get_xover(char *grpname, long startnr, long endnr, List **art) +{ + char cmd[81], *ptr, *ptr2, *resp, *p; + int retval, dupe, done = FALSE; + long nr; + unsigned long crc; + POverview pov; + + sprintf(cmd, "XOVER %ld-%ld\r\n", startnr, endnr); + if ((retval = nntp_cmd(cmd, 224))) { + switch (retval) { + case 412: + WriteError("No newsgroup selected"); + return RETVAL_NOXOVER; + case 502: + WriteError("Permission denied"); + return RETVAL_NOXOVER; + case 420: + Syslog('n', "No articles in group %s", grpname); + return RETVAL_OK; + } + } + + while (done == FALSE) { + resp = nntp_receive(); + if ((strlen(resp) == 1) && (strcmp(resp, ".") == 0)) { + done = TRUE; + } else { + Marker(); + pov = xoverview; + ptr = resp; + ptr2 = ptr; + + /* + * First item is the message number. + */ + while (*ptr2 != '\0' && *ptr2 != '\t') + ptr2++; + if (*ptr2 != '\0') + *(ptr2) = '\0'; + nr = atol(ptr); + ptr = ptr2; + ptr++; + + /* + * Search the message-id + */ + while (*ptr != '\0' && pov != NULL && strcmp(pov->header, "Message-ID:") != 0) { + /* + * goto the next field, past the tab. + */ + pov = pov->next; + + while (*ptr != '\t' && *ptr != '\0') + ptr++; + if (*ptr != '\0') + ptr++; + } + if (*ptr != '\0' && pov != NULL) { + /* + * Found it, now find start of msgid + */ + while (*ptr != '\0' && *ptr != '<') + ptr++; + if(ptr != '\0') { + ptr2 = ptr; + while(*ptr2 != '\0' && *ptr2 != '>') + ptr2++; + if (*ptr2 != '\0') { + *(ptr2+1) = '\0'; + p = xstrcpy(ptr); + p = xstrcat(p, grpname); + crc = str_crc32(p); + dupe = CheckDupe(crc, D_NEWS, CFG.nntpdupes); + fill_artlist(art, ptr, nr, dupe); + free(p); + if (CFG.slow_util && do_quiet) + usleep(1); + } + } + } + } + } + + return RETVAL_OK; +} + + + +int get_xoverview(void) +{ + int retval, len, full, done = FALSE; + char *resp; + POverview tmp, curptr = NULL; + + Syslog('n', "Getting overview format list"); + if ((retval = nntp_cmd((char *)"LIST overview.fmt\r\n", 215)) == 0) { + while (done == FALSE) { + resp = nntp_receive(); + if ((strcmp(resp, ".") == 0) && (strlen(resp) == 1)) { + done = TRUE; + } else { + len = strlen(resp); + /* + * Check for the full flag, which means the field name + * is in the xover string. + */ + full = (strstr(resp, ":full") == NULL) ? FALSE : TRUE; + /* + * Now get rid of everything back to : + */ + while (resp[len] != ':') + resp[len--] = '\0'; + len++; + + tmp = malloc(sizeof(Overview)); + tmp->header = calloc(len + 1, sizeof(char)); + strncpy(tmp->header, resp, len); + tmp->header[len] = '\0'; + tmp->next = NULL; + tmp->field = NULL; + tmp->fieldlen = 0; + tmp->full = full; + + if (curptr == NULL) { + /* at head of list */ + curptr = tmp; + xoverview = tmp; + } else { + /* add to linked list */ + curptr->next = tmp; + curptr = tmp; + } + } + } + + if ((tmp = xoverview) != NULL) { + Syslog('N', "--Xoverview.fmt list"); + while (tmp != NULL) { + if (tmp->header != NULL) { + Syslog('N', "item = %s -- full = %s", tmp->header, tmp->full ? "True":"False"); + } + tmp = tmp->next; + } + } + } else { + return 1; + } + return 0; +} + + + +int needputrfc(rfcmsg *msg) +{ + faddr *ta; + + /* 0-junk, 1-kludge, 2-pass */ + +// Syslog('M', "needputrfc(%s)", printable(msg->key,0)); + if ((msg->key == NULL) || (strlen(msg->key) == 0)) return 0; + + if (!strcasecmp(msg->key,"X-UUCP-From")) return -1; + if (!strcasecmp(msg->key,"X-Body-Start")) return -1; + if (!strncasecmp(msg->key,".",1)) return 0; + if (!strncasecmp(msg->key,"X-FTN-",6)) return 0; + if (!strncasecmp(msg->key,"X-Fsc-",6)) return 0; + if (!strncasecmp(msg->key,"X-ZC-",5)) return 0; + if (!strcasecmp(msg->key,"X-Gateway")) return 0; + if (!strcasecmp(msg->key,"Path")) return 0; + if (!strcasecmp(msg->key,"Newsgroups")) { + if ((hdr((char *)"X-Origin-Newsgroups",msg))) + return 0; + else if (strstr(msg->val,",")) + return 1; + else + return 0; + } + + if (!strcasecmp(msg->key,"X-Origin-Newsgroups")) { + if (strstr(msg->val,",")) + return 1; + else + return 0; + } + + if (!strcasecmp(msg->key,"Control")) { + if (CFG.allowcontrol) { + if (strstr(msg->val,"cancel")) + return 1; + else + return 0; + } else + return 0; + } + if (!strcasecmp(msg->key,"Return-Path")) return 1; + if (!strcasecmp(msg->key,"Xref")) return 0; + if (!strcasecmp(msg->key,"Approved")) return removeapproved ? -1:2; + if (!strcasecmp(msg->key,"X-URL")) return 0; + if (!strcasecmp(msg->key,"Return-Receipt-To")) return removereturnto? 0:1; + if (!strcasecmp(msg->key,"Notice-Requested-Upon-Delivery-To")) return 0; + if (!strcasecmp(msg->key,"Received")) return 0; + if (!strcasecmp(msg->key,"From")) { + if ((ta = parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else { + return 2; + } + } + if (!strcasecmp(msg->key,"To")) { + return 0; + } + if (!strcasecmp(msg->key,"Cc")) return 2; + if (!strcasecmp(msg->key,"Bcc")) return 0; + if (!strcasecmp(msg->key,"Reply-To")) { + if ((ta = parsefaddr(msg->val))) { + tidy_faddr(ta); + return -1; + } else + return removereplyto ?0:4; + } + if (!strcasecmp(msg->key,"Lines")) return 0; + if (!strcasecmp(msg->key,"Date")) return 0; + if (!strcasecmp(msg->key,"Subject")) { + if ((msg->val) && (strlen(msg->val) > MAXSUBJ)) + return 2; + else + return 0; + } + if (!strcasecmp(msg->key,"Organization")) return 1; + if (!strcasecmp(msg->key,"Comment-To")) return 0; + if (!strcasecmp(msg->key,"X-Comment-To")) return 0; + if (!strcasecmp(msg->key,"X-Apparently-To")) return 0; + if (!strcasecmp(msg->key,"Apparently-To")) return 0; + if (!strcasecmp(msg->key,"X-Fidonet-Comment-To")) return 0; + if (!strcasecmp(msg->key,"Keywords")) return 2; + if (!strcasecmp(msg->key,"Summary")) return 2; + if (!strcasecmp(msg->key,"MIME-Version")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Type")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Length")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Transfer-Encoding")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Name")) return 2; + if (!strcasecmp(msg->key,"Content-Description")) return 2; + if (!strcasecmp(msg->key,"Message-ID")) return removemsgid ?0:1; + if (!strcasecmp(msg->key,"References")) return removeref ?0:1; + if (!strcasecmp(msg->key,"Supersedes")) return removesupersedes ?0:1; + if (!strcasecmp(msg->key,"Distribution")) return ftnorigin ?0:0; + if (!strcasecmp(msg->key,"X-Newsreader")) return 0; + if (!strcasecmp(msg->key,"X-Mailer")) return 0; + if (!strcasecmp(msg->key,"User-Agent")) return 0; + if (!strncasecmp(msg->key,"NNTP-",5)) return 0; + if (!strncasecmp(msg->key,"X-Trace",7)) return 0; + if (!strncasecmp(msg->key,"X-Complaints",12)) return 0; + if (!strncasecmp(msg->key,"X-MSMail",9)) return 0; + if (!strncasecmp(msg->key,"X-MimeOLE",9)) return 0; + if (!strncasecmp(msg->key,"X-MIME-Autoconverted",20)) return 0; + if (!strcasecmp(msg->key,"X-Origin-Date")) return 0; + if (!strncasecmp(msg->key,"X-PGP-",6)) return 0; + if (!strncasecmp(msg->key,"Resent-",7)) return 0; + if (!strcasecmp(msg->key,"X-Mailing-List")) return 0; + if (!strcasecmp(msg->key,"X-Loop")) return 0; + if (!strcasecmp(msg->key,"Precedence")) return 0; + /*if (!strcasecmp(msg->key,"")) return ;*/ + return 1; +} + + diff --git a/mbfido/scannews.h b/mbfido/scannews.h new file mode 100644 index 00000000..739a8fba --- /dev/null +++ b/mbfido/scannews.h @@ -0,0 +1,39 @@ +#ifndef _SCANNEWS_H +#define _SCANNEWS_H + +#define MAX_MSGID_LEN 196 +#define MAX_GRP_LEN 128 + +/* + * Linked list for list overview.fmt + */ +typedef struct XOVERVIEW { + struct XOVERVIEW *next; + char *header; /* dynamically alloced */ + char *field; + int fieldlen; + int full; +} Overview, *POverview; + + + +/* + * Linked list structure one for each article + */ +typedef struct LinkList { + struct LinkList *next; + char msgid[MAX_MSGID_LEN]; + long nr; + int isdupe; +} List, *PList; + +enum { RETVAL_ERROR = -1, RETVAL_OK = 0, RETVAL_NOARTICLES, RETVAL_UNEXPECTEDANS, RETVAL_VERNR, \ + RETVAL_NOAUTH, RETVAL_EMPTYKILL, RETVAL_NOXOVER }; + + +void ScanNews(void); +int do_article(FILE *); + + +#endif + diff --git a/mbfido/sendmail.c b/mbfido/sendmail.c new file mode 100644 index 00000000..a0ba3008 --- /dev/null +++ b/mbfido/sendmail.c @@ -0,0 +1,149 @@ +/***************************************************************************** + * + * File ..................: tosser/sendmail.c + * Purpose ...............: Output a netmail to one of our links. + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "../lib/clcomm.h" +#include "../lib/dbmsgs.h" +#include "addpkt.h" +#include "rollover.h" +#include "sendmail.h" + + + +/* + * Start a netmail to one of our nodes in the setup. + * Return a file descriptor if success else NULL. + * Later the pack routine will add these mails to the outbound. + */ +FILE *SendMgrMail(faddr *t, int Keep, int FileAttach, char *bymgr, char *subj, char *reply) +{ + FILE *qp; + time_t Now; + fidoaddr Orig, Dest; + faddr From; + unsigned flags = M_PVT; + char ext[4]; + + From = *bestaka_s(t); + memset(&Orig, 0, sizeof(Orig)); + Orig.zone = From.zone; + Orig.net = From.net; + Orig.node = From.node; + Orig.point = From.point; + sprintf(Orig.domain, "%s", From.domain); + + memset(&Dest, 0, sizeof(Dest)); + Dest.zone = t->zone; + Dest.net = t->net; + Dest.node = t->node; + Dest.point = t->point; + sprintf(Dest.domain, "%s", t->domain); + + if (!SearchNode(Dest)) { + Syslog('m', "Can't find node %s", aka2str(Dest)); + return NULL; + } + + Syslog('-', " Netmail from %s to %s", aka2str(Orig), ascfnode(t, 0x1f)); + + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + flags |= (nodes.Crash) ? M_CRASH : 0; + flags |= (FileAttach) ? M_FILE : 0; + flags |= (!Keep) ? M_KILLSENT : 0; + flags |= (nodes.Hold) ? M_HOLD : 0; + + /* + * Increase counters, update record and reload. + */ + StatAdd(&nodes.MailSent, 1L); + UpdateNode(); + SearchNode(Dest); + + memset(&ext, 0, sizeof(ext)); + if (nodes.PackNetmail) + sprintf(ext, (char *)"qqq"); + else if (nodes.Crash) + sprintf(ext, (char *)"ccc"); + else if (nodes.Hold) + sprintf(ext, (char *)"hhh"); + else + sprintf(ext, (char *)"nnn"); + + if ((qp = OpenPkt(Orig, Dest, (char *)ext)) == NULL) + return NULL; + + if (AddMsgHdr(qp, &From, t, flags, 0, Now, nodes.Sysop, tlcap(bymgr), subj)) { + fclose(qp); + return NULL; + } + + if (Dest.point) + fprintf(qp, "\001TOPT %d\r", Dest.point); + if (Orig.point) + fprintf(qp, "\001FMPT %d\r", Orig.point); + + fprintf(qp, "\001INTL %d:%d/%d %d:%d/%d\r", Dest.zone, Dest.net, Dest.node, Orig.zone, Orig.net, Orig.node); + + /* + * Add MSGID, REPLY and PID + */ + fprintf(qp, "\001MSGID: %s %08lx\r", aka2str(Orig), sequencer()); + if (reply != NULL) + fprintf(qp, "\001REPLY: %s\r", reply); + fprintf(qp, "\001PID: MBSE-FIDO %s\r", VERSION); + fprintf(qp, "\001TZUTC: %s\r", gmtoffset(Now)); + return qp; +} + + + +void CloseMail(FILE *qp, faddr *t) +{ + time_t Now; + struct tm *tm; + + putc('\r', qp); + Now = time(NULL); + tm = gmtime(&Now); + fprintf(qp, "\001Via %s @%d%02d%02d.%02d%02d%02d.02.UTC %s\r", + ascfnode(bestaka_s(t), 0x1f), tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, VERSION); + + putc(0, qp); + fclose(qp); +} + + + diff --git a/mbfido/sendmail.h b/mbfido/sendmail.h new file mode 100644 index 00000000..16d2e401 --- /dev/null +++ b/mbfido/sendmail.h @@ -0,0 +1,10 @@ +#ifndef _SENDMAIL_H +#define _SENDMAIL_H + + +FILE *SendMgrMail(faddr *, int, int, char *, char *, char *); +void CloseMail(FILE *, faddr*); + + +#endif + diff --git a/mbfido/tic.c b/mbfido/tic.c new file mode 100644 index 00000000..422e70e8 --- /dev/null +++ b/mbfido/tic.c @@ -0,0 +1,451 @@ +/***************************************************************************** + * + * File ..................: mbfido/tic.c + * Purpose ...............: Process .tic files + * Last modification date : 08-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbftn.h" +#include "../lib/clcomm.h" +#include "ulock.h" +#include "ptic.h" +#include "fsort.h" +#include "pack.h" +#include "tic.h" + +#define UNPACK_FACTOR 300 + +int tic_in = 0; /* .tic files received */ +int tic_imp = 0; /* imported .tic files */ +int tic_out = 0; /* .tic files sent */ +int tic_bad = 0; /* bad .tic files */ +int tic_dup = 0; /* dupe .tic files */ + + +extern int do_unprot; +extern int do_quiet; +extern int tic_in; + + +/* + * returns: -1 = Errors. + * 0 = No files processed + * 1 = Processed file(s) + */ +int Tic() +{ + char *inbound, *fname; + DIR *dp; + struct dirent *de; + struct stat sbuf; + int i, rc = 0; + fd_list *fdl = NULL; + + IsDoing("Process .tic files"); + CompileNL = FALSE; + + if (do_unprot) { + inbound = xstrcpy(CFG.inbound); + } else { + inbound = xstrcpy(CFG.pinbound); + } + Syslog('+', "Pass: process ticfiles (%s)", inbound); + + if (!diskfree(CFG.freespace)) { + free(inbound); + return -1; + } + + if (chdir(inbound) == -1) { + WriteError("$Can't chdir(%s)", inbound); + free(inbound); + return -1; + } + + if ((dp = opendir(inbound)) == NULL) { + WriteError("$Can't opendir(%s)", inbound); + free(inbound); + return -1; + } + + while ((de = readdir(dp))) + if ((strlen(de->d_name) == 12) && + (strncasecmp(de->d_name+11, "c", 1) == 0)) { + if ((strncasecmp(de->d_name+8, ".a", 2) == 0) || + (strncasecmp(de->d_name+8, ".c", 2) == 0) || + (strncasecmp(de->d_name+8, ".z", 2) == 0) || + (strncasecmp(de->d_name+8, ".l", 2) == 0) || + (strncasecmp(de->d_name+8, ".r", 2) == 0) || + (strncasecmp(de->d_name+8, ".0", 2) == 0)) { + if (checkspace(inbound, de->d_name, UNPACK_FACTOR)) { + if ((unpack(de->d_name)) != 0) { + WriteError("Error unpacking %s", de->d_name); + } + } else + Syslog('+', "Insufficient space to unpack file %s", de->d_name); + } + } + + rewinddir(dp); + while ((de = readdir(dp))) + if ((strlen(de->d_name) == 12) && (strncasecmp(de->d_name+8, ".tic", 4) == 0)) { + stat(de->d_name, &sbuf); + fill_fdlist(&fdl, de->d_name, sbuf.st_mtime); + } + + closedir(dp); + sort_fdlist(&fdl); + + while ((fname = pull_fdlist(&fdl)) != NULL) { + if (LoadTic(inbound, fname) == 0) + rc = 1; + if (IsSema((char *)"upsalarm")) { + rc = 0; + Syslog('+', "Detected upsalarm semafore, aborting tic processing"); + break; + } + if (!diskfree(CFG.freespace)) { + rc = 0; + break; + } + } + + if (!do_quiet) { + printf("\r"); + for (i = 0; i < 79; i++) + printf(" "); + printf("\r"); + fflush(stdout); + } + + if (rc) + packmail(); + + if (CompileNL) + CreateSema((char *)"mbindex"); + + free(inbound); + return rc; +} + + + +/* + * Returns 1 if error, 0 if ok. + */ +int LoadTic(char *inb, char *tfn) +{ + FILE *tfp; + char *Temp, *Buf, *Log = NULL, *Realname; + int i, j, rc; + fa_list *sbl = NULL; + int Kwd, DescCnt = FALSE; + + if (CFG.slow_util && do_quiet) + usleep(1); + + memset(&TIC, 0, sizeof(TIC)); + memset(&T_File, 0, sizeof(T_File)); + + sprintf(TIC.Inbound, "%s/", inb); + sprintf(TIC.FilePath, "%s/", inb); + strcpy(TIC.TicName, tfn); + + chdir(inb); + if ((tfp = fopen(tfn, "r")) == NULL) { + WriteError("$Cannot open %s", tfn); + return 1; + } + + Temp = calloc(256, sizeof(char)); + Buf = calloc(256, sizeof(char)); + Realname = calloc(PATH_MAX, sizeof(char)); + + while ((fgets(Buf, 256, tfp)) != NULL) { + + /* + * Remove all garbage from the .TIC file. + */ + Temp[0] = '\0'; + j = 0; + for (i = 0; i < strlen(Buf); i++) + if ((Buf[i] >= ' ') || (Buf[i] < 0)) { + Temp[j] = Buf[i]; + j++; + } + Temp[j] = '\0'; + + Kwd = FALSE; + + if (strncasecmp(Temp, "hatch", 5) == 0) + Kwd = TIC.Hatch = TRUE; + + if (TIC.Hatch) { + if (strncasecmp(Temp, "pth ", 4) == 0) { + sprintf(TIC.FilePath, "%s/", Temp+4); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "nomove", 6) == 0) + Kwd = TIC.NoMove = TRUE; + + if (strncasecmp(Temp, "hatchnew", 8) == 0) + Kwd = TIC.HatchNew = TRUE; + } + + if (strncasecmp(Temp, "area ", 5) == 0) { + strcpy(TIC.TicIn.Area, Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "origin ", 7) == 0) { + strcpy(TIC.TicIn.Origin, Temp+7); + strcpy(T_File.Origin, Temp+7); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "from ", 5) == 0) { + strcpy(TIC.TicIn.From, Temp+5); + strcpy(T_File.From, Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "file ", 5) == 0) { + if (TIC.Hatch) + strcpy(TIC.TicIn.OrgName, Temp+5); + else + strcpy(TIC.TicIn.OrgName, tl(Temp+5)); + sprintf(Realname, "%s", Temp+5); + strcpy(TIC.NewName, TIC.TicIn.OrgName); + strcpy(T_File.Name, TIC.TicIn.OrgName); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "fullname", 8) == 0) { + strcpy(TIC.TicIn.LName, Temp+8); + Syslog('f', "Long filename: %s", TIC.TicIn.LName); + } + + if (strncasecmp(Temp, "created ", 8) == 0) { + strcpy(TIC.TicIn.Created, Temp+8); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "magic ", 6) == 0) { + strcpy(TIC.TicIn.Magic, Temp+6); + strcpy(T_File.Magic, Temp+6); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "crc ", 4) == 0) { + TIC.Crc_Int = strtoul(Temp+4, (char **)NULL, 16); + sprintf(TIC.TicIn.Crc, "%08lX", TIC.Crc_Int); + strcpy(T_File.Crc, TIC.TicIn.Crc); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "pw ", 3) == 0) { + strcpy(TIC.TicIn.Pw, Temp+3); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "replaces ", 9) == 0) { + strcpy(TIC.TicIn.Replace, Temp+9); + strcpy(T_File.Replace, Temp+9); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "desc ", 5) == 0) { + if (!DescCnt) { + strcpy(TIC.TicIn.Desc, Temp+5); + strcpy(T_File.Desc, TIC.TicIn.Desc); + Kwd = TRUE; + DescCnt = TRUE; + } else { + Syslog('!', "More than one \"Desc\" line"); + } + } + + if (strncasecmp(Temp, "path ", 5) == 0) { + strcpy(TIC.TicIn.Path[TIC.TicIn.TotPath], Temp+5); + TIC.TicIn.TotPath++; + TIC.Aka.zone = atoi(strtok(Temp+5, ":")); + TIC.Aka.net = atoi(strtok(NULL, "/")); + TIC.Aka.node = atoi(strtok(NULL, "\0")); + for (i = 0; i < 40; i++) + if ((CFG.akavalid[i]) && + (CFG.aka[i].zone == TIC.Aka.zone) && + (CFG.aka[i].net == TIC.Aka.net) && + (CFG.aka[i].node == TIC.Aka.node) && + (!CFG.aka[i].point)) + TIC.PathErr = TRUE; + Kwd = TRUE; + } + + if (strncasecmp(Temp, "seenby ", 7) == 0) { + fill_list(&sbl, Temp+7, NULL, FALSE); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "areadesc ", 9) == 0) { + strcpy(TIC.TicIn.AreaDesc, Temp+9); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "to ", 3) == 0) { + /* + * Drop this one + */ + Kwd = TRUE; + } + + if (strncasecmp(Temp, "size ", 5) == 0) { + TIC.TicIn.Size = atoi(Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "date ", 5) == 0) { + Syslog('f', "Date: %s", Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "cost ", 5) == 0) { + TIC.TicIn.UplinkCost = atoi(Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "ldesc ", 6) == 0) { + if (TIC.TicIn.TotLDesc < 25) { + Temp[86] = '\0'; + strcpy(TIC.TicIn.LDesc[TIC.TicIn.TotLDesc], Temp+6); + TIC.TicIn.TotLDesc++; + } + Kwd = TRUE; + } + + /* + * If we didn't find a matching keyword it is a line we + * will just remember and forward if there are downlinks. + */ + if (!Kwd) { + /* + * Consider Destination keyword not as a passthru + * line and drop it. + */ + if (strncasecmp(Temp, "destination ", 12) != 0) { + if (TIC.TicIn.Unknowns < 25) { + strcpy(TIC.TicIn.Unknown[TIC.TicIn.Unknowns], Temp); + TIC.TicIn.Unknowns++; + } + } + } + } + + fclose(tfp); + + if (TIC.TicIn.TotLDesc) { + /* + * First check for a bug in Harald Harms Allfix program that + * lets Allfix forward dummy Ldesc lines with the contents: + * "Long description not available" + */ + if (strstr(TIC.TicIn.LDesc[0], "ion not avail") != NULL) { + Syslog('!', "Killing invalid Ldesc line(s)"); + TIC.TicIn.TotLDesc = 0; + } + } + if (TIC.TicIn.TotLDesc) { + T_File.TotLdesc = TIC.TicIn.TotLDesc; + for (i = 0; i <= TIC.TicIn.TotLDesc; i++) + strcpy(T_File.LDesc[i], TIC.TicIn.LDesc[i]); + } + + /* + * Show on screen what we are doing + */ + if (!do_quiet) { + colour(3, 0); + printf("\r"); + for (i = 0; i < 79; i++) + printf(" "); + printf("\rTic: %12s File: %-14s Area: %-12s ", TIC.TicName, TIC.TicIn.OrgName, TIC.TicIn.Area); + fflush(stdout); + } + + /* + * Show in logfile what we are doing + */ + Syslog('+', "Processing %s, %s area %s from %s", TIC.TicName, TIC.TicIn.OrgName, TIC.TicIn.Area, TIC.TicIn.From); + Syslog('+', "+- %s", TIC.TicIn.Created); + Log = NULL; + + if (strlen(TIC.TicIn.Replace)) { + Log = xstrcpy((char *)"Replace "); + Log = xstrcat(Log, TIC.TicIn.Replace); + } + if (strlen(TIC.TicIn.Magic)) { + if (Log != NULL) + Log = xstrcat(Log, (char *)", Magic "); + else + Log = xstrcpy((char *)"Magic "); + Log = xstrcat(Log, TIC.TicIn.Magic); + } + if (Log != NULL) { + Syslog('+', "%s", Log); + free(Log); + Log = NULL; + } + + sprintf(Temp, "%s", TIC.TicIn.From); + TIC.Aka.zone = atoi(strtok(Temp, ":")); + TIC.Aka.net = atoi(strtok(NULL, "/")); + TIC.Aka.node = atoi(strtok(NULL, "@\0")); + if (SearchFidonet(TIC.Aka.zone)) + strcpy(TIC.Aka.domain, fidonet.domain); + sprintf(Temp, "%s", TIC.TicIn.Origin); + TIC.OrgAka.zone = atoi(strtok(Temp, ":")); + TIC.OrgAka.net = atoi(strtok(NULL, "/")); + TIC.OrgAka.node = atoi(strtok(NULL, "@\0")); + if (SearchFidonet(TIC.OrgAka.zone)) + strcpy(TIC.OrgAka.domain, fidonet.domain); + free(Temp); + free(Buf); + + tic_in++; + rc = ProcessTic(sbl, Realname); + tidy_falist(&sbl); + free(Realname); + + return rc; +} + + + diff --git a/mbfido/tic.h b/mbfido/tic.h new file mode 100644 index 00000000..1b943a20 --- /dev/null +++ b/mbfido/tic.h @@ -0,0 +1,72 @@ +#ifndef _TIC_H +#define _TIC_H + + +typedef struct _tic_in { + char Area[21]; /* Area name */ + char Origin[81]; /* Origin address */ + char From[81]; /* From name */ + char OrgName[81]; /* Original filename */ + char LName[81]; /* Long filename */ + char Replace[81]; /* File to replace */ + char Created[81]; /* Created text */ + char Path[25][81]; /* Travelled path */ + int TotPath; /* Nr of pathlines */ + char Desc[256]; /* Short description */ + char Magic[21]; /* Magic alias */ + char Crc[9]; /* CRC of file */ + char Pw[21]; /* Password */ + char AreaDesc[61]; /* Area description */ + char Date[61]; /* Date field */ + long UplinkCost; /* Uplink cost */ + off_t Size; /* Size of file */ + char LDesc[25][81]; /* Long description */ + int TotLDesc; /* Total lines */ + char Unknown[25][128]; /* Unknown (passthru) lines */ + int Unknowns; /* Total of above */ + int MultiSeen; /* Multi Seenby Lines */ +} Tic_in; + + +typedef struct _TICrec { + char Inbound[PATH_MAX]; /* Inbound directory */ + char TicName[13]; /* Name of .TIC file */ + Tic_in TicIn; /* Original TIC record */ + fidoaddr OrgAka; /* Origin address */ + fidoaddr Aka; /* An address ? */ + char NewName[81]; /* New name of file */ + char File_Id[25][49]; /* Description */ + int File_Id_Ct; /* Nr of lines */ + unsigned long Crc_Int; /* Crc value */ + int KeepNum; /* Keep number of files */ + off_t FileSize; /* Size of file */ + time_t FileDate; /* Date of file */ + time_t UpLoadDate; /* Upload date of file */ + char FilePath[PATH_MAX]; /* Path to the file */ + unsigned PathErr : 1; /* If path error */ + unsigned OtherPath : 1; /* If otherpath is true */ + unsigned Hatch : 1; /* If internal hatched */ + unsigned NoMove : 1; /* No move magic */ + unsigned HatchNew : 1; /* Hatch in new areas */ + unsigned SendOrg : 1; /* Send original file */ + unsigned Charge : 1; /* Charge for this file */ + unsigned PassThru : 1; /* PassThru file */ + unsigned NewAlias : 1; /* New alias is set */ + long FileCost; /* Cost for this file */ + char BBSpath[PATH_MAX]; /* Path to import in */ + char BBSdesc[55]; /* Area description */ +} TICrec; + + +TICrec TIC; /* Global .tic record */ +struct _filerecord T_File; /* Global file handling rec.*/ + +int CompileNL; + + +int Tic(void); +int LoadTic(char *, char *); + + +#endif + diff --git a/mbfido/toberep.c b/mbfido/toberep.c new file mode 100644 index 00000000..6b4fd33f --- /dev/null +++ b/mbfido/toberep.c @@ -0,0 +1,79 @@ +/***************************************************************************** + * + * File ..................: mbfido/toberep.c + * Purpose ...............: Add a file to the To-Be-Reported database + * Last modification date : 19-Mar-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tic.h" + + +#include "toberep.h" + + +/* + * Add a file whos data is in T_File to the toberep.data file. + * The newfiles announce option will later remove these records. + */ +void Add_ToBeRep() +{ + char fname[128]; + struct _filerecord Temp; + FILE *tbr; + int Found = FALSE; + + sprintf(fname, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + if ((tbr = fopen(fname, "a+")) == NULL) { + WriteError("$Can't create %s", fname); + return; + } + + fseek(tbr, 0, SEEK_SET); + while (fread(&Temp, sizeof(Temp), 1, tbr) == 1) { + if ((strcmp(Temp.Name, T_File.Name) == 0) && + (Temp.Fdate == T_File.Fdate) && + (strcmp(Temp.Echo, T_File.Echo) == 0)) + Found = TRUE; + } + + if (Found) { + Syslog('!', "File %s already in toberep.data", T_File.Name); + fclose(tbr); + return; + } + + fwrite(&T_File, sizeof(T_File), 1, tbr); + fclose(tbr); +} + + + diff --git a/mbfido/toberep.h b/mbfido/toberep.h new file mode 100644 index 00000000..e5f3cac7 --- /dev/null +++ b/mbfido/toberep.h @@ -0,0 +1,9 @@ +#ifndef _TOBEREP_H +#define _TOBEREP_H + + +void Add_ToBeRep(void); + + +#endif + diff --git a/mbfido/tosspkt.c b/mbfido/tosspkt.c new file mode 100644 index 00000000..ef9c36b6 --- /dev/null +++ b/mbfido/tosspkt.c @@ -0,0 +1,400 @@ +/***************************************************************************** + * + * File ..................: tosser/tosspkt.c + * Purpose ...............: Toss a single *.pkt file + * Last modification date : 03-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "importmsg.h" +#include "tosspkt.h" + + + +/* + * External declarations + */ +extern int do_quiet; + + + +/* + * Global variables + */ +int net_in = 0; /* Netmails received */ +int net_imp = 0; /* Netmails imported */ +int net_out = 0; /* Netmails forwarded */ +int net_bad = 0; /* Bad netmails (tracking errors */ +int echo_in = 0; /* Echomail received */ +int echo_imp = 0; /* Echomail imported */ +int echo_out = 0; /* Echomail forwarded */ +int echo_bad = 0; /* Bad echomail */ +int echo_dupe = 0; /* Dupe echomail */ +int news_in = 0; /* News received */ +int news_imp = 0; /* News imported */ +int news_out = 0; /* News posted */ +int news_bad = 0; /* Bad news */ +int news_dupe = 0; /* Dupe articles */ +int email_in = 0; /* Email received */ +int email_imp = 0; /* Email imported */ +int email_out = 0; /* Email forwarded */ +int email_bad = 0; /* Bad email */ +char *toname = NULL; /* To user */ +char *fromname = NULL; /* From user */ +char *subj = NULL; /* Message subject */ +extern char *msgid; + + +static int at_zero = 0; + +char *aread(char *, int, FILE *); +char *aread(char *s, int count, FILE *fp) +{ + int i,c,next; + + if (feof(fp)) + return(NULL); + if (s == NULL) + return NULL; + if (at_zero) + { + at_zero=0; + return NULL; + } + + for (i = 0,next = 1; (i < count-1) && next;) + switch (c=getc(fp)) { + case '\n': break; + + case '\r': s[i]='\n'; + i++; + next=0; + break; + + case 0x8d: s[i]=' '; + i++; + break; + + case '\0': at_zero=1; + next=0; + break; + + default: s[i]=c; + i++; + break; + } + s[i]='\0'; + return s; +} + + + +/* + * Toss one packet. + * + * 0 - + * 1 - Cannot open packet + * 2 - Bad packet header + * 3 - Packet is not for us + * 4 - Bad password + */ +int TossPkt(char *fn) +{ + int rc, count = 0; + static int maxrc = 0; + static faddr from, to; + FILE *pkt; + + if (!do_quiet) { + colour(10, 0); + printf("Tossing packet %s\n", fn); + } + + if ((pkt = fopen(fn, "r")) == 0) { + WriteError("$Cannot open %s", fn); + return 1; + } + + memset(&from, 0, sizeof(faddr)); + memset(&to, 0, sizeof(faddr)); + + if (((rc = getheader(&from, &to, pkt, fn)) != 0)) { + WriteError("%s, aborting", + (rc == 1)?"wrong header type": + (rc == 2)?"bad packet header": + (rc == 3)?"packet is not for us": + (rc == 4)?"bad password": + "bad packet"); + return(rc); + } + + while ((rc = getmessage(pkt, &from, &to)) == 1) { + count++; + } + Syslog('+', "Messages : %d", count); + + maxrc = rc; + if (!do_quiet) + printf("\r \r"); + + if (rc) + Syslog('+', "End, rc=%d", maxrc); + + fclose(pkt); + return maxrc; +} + + + +/* + * Process one message from message packet. + * + * 0 - no more messages + * 1 - more messages + * 2 - bad file + * 3 - bad message header + * 4 - unable to open temp file + * 5 - unexpected end of packet + * >10 - import error + */ +int getmessage(FILE *pkt, faddr *p_from, faddr *p_to) +{ + char buf[2048]; + char *orig = NULL; + char *p, *l, *r; + int tmp, rc, maxrc = 0; + static faddr f, t; + faddr *o; + int result, flags, cost; + time_t mdate = 0L; + FILE *fp; + unsigned char buffer[0x0e]; + off_t orig_off; + + subj = NULL; + toname = NULL; + fromname = NULL; + result = fread(&buffer, 1, sizeof(buffer), pkt); + if (result == 0) { + Syslog('m', "Zero bytes message, assume end of pkt"); + return 0; + } + + switch(tmp = (buffer[0x01] << 8) + buffer[0x00]) { + case 0: + if (result == 2) + return 0; + else { + Syslog('!', "Junk after logical end of packet, skipped"); + return 5; + + } + case 2: + break; + + default: + Syslog('!', "bad message type: 0x%04x",tmp); + return 2; + } + + if (result != 14) { + Syslog('!', "Unexpected end of packet"); + return 5; + } + + memset(&f, 0, sizeof(f)); + memset(&t, 0, sizeof(t)); + f.node = (buffer[0x03] << 8) + buffer[0x02]; + t.node = (buffer[0x05] << 8) + buffer[0x04]; + f.net = (buffer[0x07] << 8) + buffer[0x06]; + t.net = (buffer[0x09] << 8) + buffer[0x08]; + flags = (buffer[0x0b] << 8) + buffer[0x0a]; + cost = (buffer[0x0d] << 8) + buffer[0x0c]; + + /* + * Read the DateTime, toUserName, fromUserName and subject fields + * from the packed message. The stringlength is +1 for the right + * check. This is different then in ifmail's original code. + */ + if (aread(buf, sizeof(buf)-1, pkt)) { + if (strlen(buf) > 20) + Syslog('!', "date too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); + mdate = parsefdate(buf, NULL); + if (aread(buf, sizeof(buf)-1, pkt)) { + Syslog('!', "date not null-terminated: \"%s\"",buf); + return 3; + } + } + + if (aread(buf, sizeof(buf)-1, pkt)) { + if (strlen(buf) > 36) + Syslog('!', "to name too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); + t.name = xstrcpy(buf); + toname = xstrcpy(buf); + if (aread(buf, sizeof(buf)-1, pkt)) { + if (*(p=t.name+strlen(t.name)-1) == '\n') + *p = '\0'; + Syslog('!', "to name not null-terminated: \"%s\"",buf); + return 3; + } + } + + if (aread(buf, sizeof(buf)-1, pkt)) { + if (strlen(buf) > 36) + Syslog('!', "from name too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); + f.name = xstrcpy(buf); + fromname = xstrcpy(buf); + if (aread(buf, sizeof(buf)-1, pkt)) { + if (*(p=f.name+strlen(f.name)-1) == '\n') + *p = '\0'; + Syslog('!', "from name not null-terminated: \"%s\"",buf); + return 3; + } + } + + if (aread(buf, sizeof(buf)-1, pkt)) { + if (strlen(buf) > 72) + Syslog('!', "subject too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); + subj = xstrcpy(buf); + if (aread(buf, sizeof(buf)-1, pkt)) { + if (*(p=subj+strlen(subj)-1) == '\n') + *p = '\0'; + subj = xstrcat(subj,(char *)"\\n"); + subj = xstrcat(subj,buf); + Syslog('!', "subj not null-terminated: \"%s\"",buf); + return 3; + } + } + + if (feof(pkt) || ferror(pkt)) { + Syslog('!', "Could not read message header, aborting"); + return 3; + } + + f.zone = p_from->zone; + t.zone = p_to->zone; + + if ((fp = tmpfile()) == NULL) { + WriteError("$unable to open temporary file"); + return 4; + } + orig_off = 0L; + + /* + * Read the text from the .pkt file + */ + while (aread(buf,sizeof(buf)-1,pkt)) { + + fputs(buf, fp); + + /* + * Extract info from Origin line if found. + */ + if (!strncmp(buf," * Origin:",10)) { + orig_off = ftell(fp); + p=buf+10; + while (*p == ' ') p++; + if ((l=strrchr(p,'(')) && (r=strrchr(p,')')) && (l < r)) { + *l = '\0'; + *r = '\0'; + l++; + if ((o = parsefnode(l))) { + f.point = o->point; + f.node = o->node; + f.net = o->net; + f.zone = o->zone; + if (o->domain) + f.domain=o->domain; + o->domain=NULL; + tidy_faddr(o); + } + } else + if (*(l=p+strlen(p)-1) == '\n') + *l='\0'; + for (l=p+strlen(p)-1;*l == ' ';l--) + *l='\0'; + orig = xstrcpy(p); + } + } + + rc = importmsg(p_from, &f,&t,orig,mdate,flags,cost,fp,orig_off); + if (rc) + rc+=10; + if (rc > maxrc) + maxrc = rc; + + fclose(fp); + + if(f.name) + free(f.name); + f.name=NULL; + + if(t.name) + free(t.name); + t.name=NULL; + + if(f.domain) + free(f.domain); + f.domain=NULL; + + if(t.domain) + free(t.domain); + t.domain=NULL; + + if (fromname) + free(fromname); + fromname = NULL; + + if (toname) + free(toname); + toname = NULL; + + if (subj) + free(subj); + subj = NULL; + + if (orig) + free(orig); + orig = NULL; + + if (msgid) + free(msgid); + msgid = NULL; + + if (feof(pkt) || ferror(pkt)) { + WriteError("Unexpected end of packet"); + return 5; + } + return 1; +} + + diff --git a/mbfido/tosspkt.h b/mbfido/tosspkt.h new file mode 100644 index 00000000..bd59ef48 --- /dev/null +++ b/mbfido/tosspkt.h @@ -0,0 +1,9 @@ +#ifndef _TOSSPKT_H +#define _TOSSPKT_H + + +int TossPkt(char *); +int getmessage(FILE *, faddr *, faddr *); + +#endif + diff --git a/mbfido/tracker.c b/mbfido/tracker.c new file mode 100644 index 00000000..d64cace1 --- /dev/null +++ b/mbfido/tracker.c @@ -0,0 +1,518 @@ +/***************************************************************************** + * + * File ..................: tosser/tracker.c + * Purpose ...............: Netmail tracker / router + * Last modification date : 12-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "tracker.h" + + +extern char nodes_fil[81]; +extern long nodes_pos; + +/* + * Netmail tracker. Return TRUE if we found a valid route. + * If we did find a route, it is returned in the route pointer. + * If not, return FALSE. The calling program must bounce the + * original message. + */ +int TrackMail(fidoaddr too, fidoaddr *route) +{ + int rc, i; + + Syslog('r', "Tracking destination %s", aka2str(too)); + + rc = GetRoute(aka2str(too) , route); + if (rc == R_NOROUTE) { + WriteError("No route to %s, not parsed", aka2str(too)); + return R_NOROUTE; + } + if (rc == R_UNLISTED) { + WriteError("No route to %s, unlisted node", aka2str(too)); + return R_UNLISTED; + } + + /* + * If local aka + */ + if (rc == R_LOCAL) + return R_LOCAL; + + /* + * Now look again if from the routing result we find a + * direct link. If so, maybe adjust something. + */ + if (SearchNode(*route)) { + Syslog('r', "Known node: %s", aka2str(nodes.Aka[0])); + Syslog('r', "Check \"too\" %s", aka2str(too)); + + if (nodes.RouteVia.zone) { + route->zone = nodes.RouteVia.zone; + route->net = nodes.RouteVia.net; + route->node = nodes.RouteVia.node; + route->point = nodes.RouteVia.point; + sprintf(route->domain, "%s", nodes.RouteVia.domain); + return R_ROUTE; + } else { + for (i = 0; i < 20; i++) + if (route->zone == nodes.Aka[i].zone) + break; + route->zone = nodes.Aka[i].zone; + route->net = nodes.Aka[i].net; + route->node = nodes.Aka[i].node; + route->point = nodes.Aka[i].point; + sprintf(route->domain, "%s", nodes.Aka[i].domain); + return R_ROUTE; + } + } + + return rc; +} + + + +int AreWeHost(faddr *); +int AreWeHost(faddr *dest) +{ + int i, j; + + /* + * First a fast run in our own zone. + */ + for (i = 0; i < 40; i++) + if (CFG.akavalid[i] && (CFG.aka[i].zone == dest->zone)) + if (CFG.aka[i].node == 0) + return i; + + for (i = 0; i < 40; i++) + if (CFG.akavalid[i]) + if (SearchFidonet(dest->zone)) + for (j = 0; j < 6; j++) + if (CFG.aka[i].zone == fidonet.zone[j]) + if (CFG.aka[i].node == 0) + return i; + + return -1; +} + + + +int AreWeHub(faddr *); +int AreWeHub(faddr *dest) +{ + int i, j; + node *nl; + faddr *fido; + + for (i = 0; i < 40; i++) + if (CFG.akavalid[i]) + if (CFG.aka[i].zone == dest->zone) { + fido = fido2faddr(CFG.aka[i]); + nl = getnlent(fido); + tidy_faddr(fido); + if (nl->addr.domain) + free(nl->addr.domain); + if (nl->type == NL_HUB) + return i; + } + + for (i = 0; i < 40; i++) + if (CFG.akavalid[i]) + if (SearchFidonet(dest->zone)) + for (j = 0; j < 6; j++) + if (CFG.aka[i].zone == fidonet.zone[j]) { + fido = fido2faddr(CFG.aka[i]); + nl = getnlent(fido); + tidy_faddr(fido); + if (nl->addr.domain) + free(nl->addr.domain); + if (nl->type == NL_HUB) + return i; + } + + return -1; +} + + + +/* + * Get routing information for specified netmail address. + */ +int GetRoute(char *ftn, fidoaddr *res) +{ + node *dnlent, *bnlent; + unsigned short myregion; + faddr *dest, *best, *maddr; + fidoaddr *fido; + int me_host = -1, me_hub = -1; + int i; + fidoaddr dir; + FILE *fil; + + memset(res, 0, sizeof(fidoaddr)); + dest = parsefnode(ftn); + if (SearchFidonet(dest->zone)) { + if (dest->domain) + free(dest->domain); + dest->domain = xstrcpy(fidonet.domain); + } + best = bestaka_s(dest); + Syslog('r', "Get route for: %s", ascfnode(dest, 0xff)); + + /* + * Check if the destination is ourself. + */ + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (CFG.aka[i].zone == dest->zone) && + (CFG.aka[i].net == dest->net) && (CFG.aka[i].node == dest->node)) { + if (dest->point == CFG.aka[i].point) { + Syslog('+', "R: %s => Loc %s", ascfnode(dest, 0x0f), aka2str(CFG.aka[i])); + memcpy(res, &CFG.aka[i], sizeof(fidoaddr)); + tidy_faddr(best); + tidy_faddr(dest); + return R_LOCAL; + } + if (dest->point && (!CFG.aka[i].point)) { + Syslog('+', "R: %s => My point", ascfnode(dest, 0xff)); + fido = faddr2fido(dest); + memcpy(res, fido, sizeof(fidoaddr)); + free(fido); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + + if (best->point) { + /* + * We are a point, so don't bother the rest of the tests, route + * to our boss. + */ + res->zone = best->zone; + res->net = best->net; + res->node = best->node; + res->point = 0; + Syslog('+', "R: %s => My boss %s", ascfnode(dest, 0x0f), aka2str(*res)); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + + /* + * Now test several possible setup matches. + */ + dir.zone = dest->zone; + dir.net = dest->net; + dir.node = dest->node; + dir.point = dest->point; + sprintf(dir.domain, "%s", dest->domain); + + /* + * First direct match + */ + if (SearchNode(dir)) { + for (i = 0; i < 20; i++) { + if ((dir.zone == nodes.Aka[i].zone) && + (dir.node == nodes.Aka[i].node) && + (dir.net == nodes.Aka[i].net) && + (dir.point == nodes.Aka[i].point)) { + memcpy(res, &nodes.Aka[i], sizeof(fidoaddr)); + Syslog('+', "R: %s => Dir link %s", ascfnode(dest, 0x0f), aka2str(*res)); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + + /* + * Again, but now for points + */ + dir.point = 0; + if (SearchNode(dir)) { + for (i = 0; i < 20; i++) { + if ((dir.zone == nodes.Aka[i].zone) && + (dir.node == nodes.Aka[i].node) && + (dir.net == nodes.Aka[i].net)) { + memcpy(res, &nodes.Aka[i], sizeof(fidoaddr)); + res->point = 0; + Syslog('+', "R: %s => Boss link %s", ascfnode(dest, 0x0f), aka2str(*res)); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + + /* + * Check if we know the uplink, but first check if the node is listed. + */ + dnlent = (node *)malloc(sizeof(node)); + memcpy(dnlent, getnlent(dest), sizeof(node)); + if (dnlent->addr.domain) + free(dnlent->addr.domain); + + if (!(dnlent->pflag & NL_DUMMY)) { + dir.node = dnlent->upnode; + dir.net = dnlent->upnet; + if (SearchNode(dir)) { + for (i = 0; i < 20; i++) { + if ((dir.zone == nodes.Aka[i].zone) && + (dir.node == nodes.Aka[i].node) && + (dir.net == nodes.Aka[i].net)) { + memcpy(res, &nodes.Aka[i], sizeof(fidoaddr)); + res->point = 0; + Syslog('+', "R: %s => Uplink %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + } + + /* + * We don't know the route from direct links. We will first see + * what we are, host, hub or node. + */ + me_host = AreWeHost(dest); + if (me_host == -1) + me_hub = AreWeHub(dest); + bnlent = getnlent(best); + myregion = bnlent->region; + + /* + * This is default routing for hosts: + * 1. Out of zone and region mail goes to the myzone:myregion/0 + * 2. Out of net mail goes to host myzone:destnet/0 + * 3. Nodes without hub are my downlinks, no route. + * 4. The rest goes to the hubs. + */ + if (me_host != -1) { + sprintf(res->domain, "%s", CFG.aka[me_host].domain); + if (((myregion != dnlent->region) && (!(dnlent->pflag & NL_DUMMY))) || + (CFG.aka[me_host].zone != dest->zone)) { + res->zone = CFG.aka[me_host].zone; + res->net = myregion; + Syslog('+', "R: %s => Region %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + if (CFG.aka[me_host].net != dest->net) { + res->zone = dest->zone; + res->net = dest->net; + Syslog('+', "R: %s => Host %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + if (dnlent->upnode == 0) { + res->zone = dest->zone; + res->net = dest->net; + res->node = dest->node; + Syslog('+', "R: %s => Dir link %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + res->zone = CFG.aka[me_host].zone; + res->net = dnlent->upnet; + res->node = dnlent->upnode; + Syslog('+', "R: %s => Hub %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + + /* + * This is the default routing for hubs. + * 1. If the nodes hub is our own hub, it's a downlink. + * 2. Kick everything else to the host. + */ + if (me_hub != -1) { + sprintf(res->domain, "%s", CFG.aka[me_hub].domain); + if ((dnlent->upnode == CFG.aka[me_hub].node) && + (dnlent->upnet == CFG.aka[me_hub].net) && + (dnlent->addr.zone == CFG.aka[me_hub].zone)) { + res->zone = dest->zone; + res->net = dest->net; + res->node = dest->node; + res->point = dest->point; + Syslog('+', "R: %s => Dir link %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } else { + res->zone = CFG.aka[me_hub].zone; + res->net = CFG.aka[me_hub].net; + Syslog('+', "R: %s => My host %s", ascfnode(dest, 0xff), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + } + free(dnlent); + + /* + * Routing for normal nodes, everything goes to the hub or host. + */ + if ((me_hub == -1) && (me_host == -1)) { + if (bnlent->pflag != NL_DUMMY) { + res->zone = bnlent->addr.zone; + res->net = bnlent->upnet; + res->node = bnlent->upnode; + sprintf(res->domain, "%s", bnlent->addr.domain); + Syslog('+', "R: %s => %s", ascfnode(dest, 0xff), aka2str(*res)); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + + if (bnlent->addr.domain) + free(bnlent->addr.domain); + + /* + * If the above failed, we are probably a new node without + * a nodelist entry. We will switch to plan B. + */ + if ((fil = fopen(nodes_fil, "r")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + nodes_pos = -1; + while (fread(&nodes, nodeshdr.recsize, 1, fil) == 1) { + fseek(fil, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + for (i = 0; i < 20; i++) { + if ((nodes.Aka[i].zone) && + (nodes.Aka[i].zone == best->zone) && + (nodes.Aka[i].net == best->net)) { + maddr = fido2faddr(nodes.Aka[i]); + bnlent = getnlent(maddr); + tidy_faddr(maddr); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + if ((bnlent->type == NL_HUB) || + (bnlent->type == NL_HOST)) { + fclose(fil); + memcpy(res, &nodes.Aka[i], sizeof(fidoaddr)); + Syslog('r', "R: %s => %s", ascfnode(dest, 0xff), aka2str(*res)); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + } + fclose(fil); + } + } + + WriteError("Routing parse error 2"); + tidy_faddr(best); + tidy_faddr(dest); + return R_NOROUTE; +} + + + +void TestRoute(char *dest) +{ + fidoaddr result; + int rc; + + + rc = GetRoute(dest, &result); + if (rc == R_NOROUTE) + printf("Route %d %23s => no route\n", rc, dest); + else if (rc == R_UNLISTED) + printf("Route %d %23s => unlisted node\n", rc, dest); + else + printf("Route %d %23s => %s\n", rc, dest, aka2str(result)); +} + + + +void TestTracker(void) +{ + colour(7, 0); + TestRoute((char *)"2:2801/16@fidonet"); + TestRoute((char *)"2:2801/16.1"); + TestRoute((char *)"2:2801/805.3"); + TestRoute((char *)"2:2801/899.1@fidonet"); + TestRoute((char *)"2:2801/890@fidonet"); + TestRoute((char *)"2:2801/1008"); + TestRoute((char *)"2:2801/21"); + TestRoute((char *)"2:2801/899@fidonet"); + TestRoute((char *)"2:2801/807"); + TestRoute((char *)"92:100/0@bibnet"); + TestRoute((char *)"92:100/5@bibnet"); + TestRoute((char *)"92:100/45"); + TestRoute((char *)"2:28/0"); + TestRoute((char *)"2:2801/1002@fidonet"); + TestRoute((char *)"2:2801/206"); + TestRoute((char *)"2:2/0@fidonet"); + TestRoute((char *)"2:2/3001"); + TestRoute((char *)"2:2801/28"); + TestRoute((char *)"2:2801/307.50"); + TestRoute((char *)"2:280/901"); + TestRoute((char *)"2:280/9"); + TestRoute((char *)"2:203/111"); + TestRoute((char *)"1:213/350"); + TestRoute((char *)"9:314/8@virnet"); + TestRoute((char *)"9:314/8.1@virnet"); +} + + diff --git a/mbfido/tracker.h b/mbfido/tracker.h new file mode 100644 index 00000000..225d34cd --- /dev/null +++ b/mbfido/tracker.h @@ -0,0 +1,16 @@ +#ifndef _TRACKER_H +#define _TRACKER_H + +#define R_NOROUTE 0 +#define R_LOCAL 1 +#define R_DIRECT 2 +#define R_ROUTE 3 +#define R_UNLISTED 4 + + +int TrackMail(fidoaddr, fidoaddr *); +int GetRoute(char *, fidoaddr *); +void TestTracker(void); + +#endif + diff --git a/mbfido/ulock.c b/mbfido/ulock.c new file mode 100644 index 00000000..bf737d74 --- /dev/null +++ b/mbfido/ulock.c @@ -0,0 +1,182 @@ +/***************************************************************************** + * + * File ..................: mbfido/ulock.c + * Purpose ...............: Lock mbfido processing. + * Last modification date : 10-May-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "flock.h" +#include "ulock.h" + +#define UNPACK_FACTOR 300 +#define TOSS_FACTOR 120 +#define TMPNAME "TMP." +#define LCKNAME "LOCKFILE" + + +static char lockfile[81]; + +extern int do_quiet; + + +/* + * Put a lock on this program. + */ +int lockunpack(void) +{ + char Tmpfile[81]; + FILE *fp; + pid_t oldpid; + + sprintf(Tmpfile, "%s/", CFG.inbound); + strcpy(lockfile, Tmpfile); + sprintf(Tmpfile + strlen(Tmpfile), "%s%u", TMPNAME, getpid()); + sprintf(lockfile + strlen(lockfile), "%s", LCKNAME); + + if ((fp = fopen(Tmpfile, "w")) == NULL) { + WriteError("$Can't create lockfile \"%s\"", Tmpfile); + return 1; + } + fprintf(fp, "%10u\n", getpid()); + fclose(fp); + + while (1) { + if (link(Tmpfile, lockfile) == 0) { + unlink(Tmpfile); + return 0; + } + if ((fp = fopen(lockfile, "r")) == NULL) { + WriteError("$Can't open lockfile \"%s\"", Tmpfile); + unlink(Tmpfile); + return 1; + } + if (fscanf(fp, "%u", &oldpid) != 1) { + WriteError("$Can't read old pid from \"%s\"", Tmpfile); + fclose(fp); + unlink(Tmpfile); + return 1; + } + fclose(fp); + if (kill(oldpid,0) == -1) { + if (errno == ESRCH) { + Syslog('+', "Stale lock found for pid %u", oldpid); + unlink(lockfile); + /* no return, try lock again */ + } else { + WriteError("$Kill for %u failed",oldpid); + unlink(Tmpfile); + return 1; + } + } else { + Syslog('+', "mbfido already running, pid=%u", oldpid); + unlink(Tmpfile); + return 1; + } + } +} + + + +void ulockunpack(void) +{ + if (lockfile) + (void)unlink(lockfile); +} + + + +int checkspace(char *dir, char *fn, int factor) +{ + struct stat st; + struct statfs sfs; + + if ((stat(fn,&st) != 0) || (statfs(dir,&sfs) != 0)) { + WriteError("Cannot stat \"%s\" or statfs \"%s\", assume enough space", fn, dir); + return 1; + } + + if ((((st.st_size / sfs.f_bsize +1) * factor) / 100L) > sfs.f_bfree) { + Syslog('!', "Only %lu %lu-byte blocks left on device where %s is located", + sfs.f_bfree,sfs.f_bsize,dir); + return 0; + } + return 1; +} + + + +/* + * Unpack archive + */ +int unpack(char *fn) +{ + char newname[16]; + char *cmd = NULL, *unarc; + int rc = 0, ld; + + if (!do_quiet) { + colour(11, 0); + printf("Unpacking file %s\n", fn); + } + + if ((unarc = unpacker(fn)) == NULL) + return 1; + + if (!getarchiver(unarc)) + return 1; + + cmd = xstrcpy(archiver.munarc); + + if ((cmd == NULL) || (cmd == "")) + return -1; + + if ((ld = f_lock(fn)) == -1) { + free(cmd); + return 1; + } + + rc = execute(cmd,fn,(char *)NULL,(char*)"/dev/null",(char*)"/dev/null",(char*)"/dev/null"); + if (rc == 0) + unlink(fn); + else { + strncpy(newname,fn,sizeof(newname)-1); + strcpy(newname+8,".bad"); + rename(fn,newname); + } + + free(cmd); + funlock(ld); + return rc; +} + + + diff --git a/mbfido/ulock.h b/mbfido/ulock.h new file mode 100644 index 00000000..b91f61ab --- /dev/null +++ b/mbfido/ulock.h @@ -0,0 +1,11 @@ +#ifndef _ULOCK_H +#define _ULOCK_H + +int checkspace(char *, char *, int); +int lockunpack(void); +void ulockunpack(void); +int unpack(char *); + +#endif + + diff --git a/mbfido/utic.c b/mbfido/utic.c new file mode 100644 index 00000000..5a5462c5 --- /dev/null +++ b/mbfido/utic.c @@ -0,0 +1,262 @@ +/***************************************************************************** + * + * File ..................: mbfido/utic.c + * Purpose ...............: Utilities for tic processing + * Last modification date : 26-May-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tic.h" +#include "mover.h" +#include "tic.h" +#include "utic.h" + + +extern int tic_bad; +extern int do_quiet; + + +char *MakeTicName() +{ + static char buf[13]; + + buf[12] = '\0'; + sprintf(buf, "%08lx.tic", sequencer()); + buf[0] = 'm'; + buf[1] = 'b'; + + return buf; +} + + + +/* + * Return day in the year, 0..365 + */ +int Day_Of_Year() +{ + time_t Now; + struct tm *Tm; + + Now = time(NULL); + Tm = localtime(&Now); + + return Tm->tm_yday; +} + + + +/* + * ReArc files in the current directory + */ +int Rearc(char *unarc) +{ + int i, j; + char temp[81], *cmd = NULL; + + Syslog('f', "Entering Rearc(%s)", unarc); + + i = 0; + while (TIC.NewName[i] != '.') + i++; + i++; + + j = 0; + for (; i < strlen(TIC.NewName); i++) { + if (TIC.NewName[i] > '9') + TIC.NewName[i] = tolower(unarc[j]); + j++; + } + + + Syslog('f' , "NewName = \"%s\"", TIC.NewName); + + if (!getarchiver(unarc)) { + return FALSE; + } + + cmd = xstrcpy(archiver.farc); + + if (cmd == NULL) { + WriteError("Rearc(): No arc command available"); + return FALSE; + } else { + sprintf(temp, "%s%s .", TIC.Inbound, TIC.NewName); + if (execute(cmd, temp, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) { + /* MUST SET TIC.FileDate to NEW ARCHIVE */ + return TRUE; + } + WriteError("Rearc(%s) Failed", unarc); + return FALSE; + } + free(cmd); +} + + + +void DeleteVirusWork() +{ + char *buf = NULL; + char temp[81]; + + getcwd(buf, 128); + sprintf(temp, "%s/tmp", getenv("MBSE_ROOT")); + + if (chdir(temp) == 0) { + Syslog('f', "DeleteVirusWork %s/arc", temp); + system("rm -r -f arc"); + system("mkdir arc"); + } else + WriteError("$Can't chdir to %s", temp); + + chdir(buf); +} + + + +void Bad(char *format, ...) +{ + char outstr[1024]; + va_list va_ptr; + + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + + WriteError(outstr); + MoveBad(); + tic_bad++; +} + + + +void ReCalcCrc(char *fn) +{ + TIC.Crc_Int = file_crc(fn, CFG.slow_util && do_quiet); + sprintf(TIC.TicIn.Crc, "%08lX", TIC.Crc_Int); + strcpy(T_File.Crc, TIC.TicIn.Crc); +} + + + +int Get_File_Id() +{ + char temp[81]; + char Desc[256]; + FILE *fp; + int i, j, lines = 0; + + sprintf(temp, "%s/tmp/FILE_ID.DIZ", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) + return FALSE; + + /* + * Read no more then 25 lines. + */ + while (((fgets(Desc, 255, fp)) != NULL) && (TIC.File_Id_Ct < 25)) { + lines++; + /* + * Check if the FILE_ID.DIZ is in a normal layout. + * The layout should be max. 10 lines of max. 48 characters. + * We check at 51 characters and if the lines are longer, + * we trash the FILE_ID.DIZ file. + */ + if (strlen(Desc) > 51) { + fclose(fp); + unlink(temp); + TIC.File_Id_Ct = 0; + Syslog('f', "FILE_ID.DIZ line %d is %d chars", lines, strlen(Desc)); + Syslog('!', "Trashing illegal formatted FILE_ID.DIZ"); + return FALSE; + } + + if (strlen(Desc) > 0) { + j = 0; + for (i = 0; i < strlen(Desc); i++) { + if ((Desc[i] >= ' ') || (Desc[i] < 0)) { + TIC.File_Id[TIC.File_Id_Ct][j] = Desc[i]; + j++; + } + } + + if (j >= 48) + TIC.File_Id[TIC.File_Id_Ct][48] = '\0'; + else + TIC.File_Id[TIC.File_Id_Ct][j] = '\0'; + + TIC.File_Id_Ct++; + } + } + fclose(fp); + unlink(temp); + + /* + * Strip empty lines at end of FILE_ID.DIZ + */ + while ((strlen(TIC.File_Id[TIC.File_Id_Ct-1]) == 0) && (TIC.File_Id_Ct)) + TIC.File_Id_Ct--; + + Syslog('f', "Got %d FILE_ID.DIZ lines", TIC.File_Id_Ct); + if (TIC.File_Id_Ct) + return TRUE; + else + return FALSE; +} + + + +void UpDateAlias(char *Alias) +{ + char *path; + FILE *fp; + + Syslog('f', "UpDateAlias(%s) with %s", Alias, TIC.NewName); + + if (!strlen(CFG.req_magic)) { + WriteError("No magic filename path configured"); + return; + } + + path = xstrcpy(CFG.req_magic); + path = xstrcat(path, (char *)"/"); + path = xstrcat(path, Alias); + + if ((fp = fopen(path, "w")) == NULL) { + WriteError("$Can't create %s", path); + return; + } + fprintf(fp, "%s\n", TIC.NewName); + fclose(fp); + free(path); +} + + + diff --git a/mbfido/utic.h b/mbfido/utic.h new file mode 100644 index 00000000..f514bae2 --- /dev/null +++ b/mbfido/utic.h @@ -0,0 +1,15 @@ +#ifndef _UTIC_H +#define _UTIC_H + + +char *MakeTicName(void); +int Day_Of_Year(void); +int Rearc(char *); +void DeleteVirusWork(void); +void Bad(char *, ...); +void ReCalcCrc(char *); +int Get_File_Id(void); +void UpDateAlias(char *); + + +#endif diff --git a/mbfido/viadate.c b/mbfido/viadate.c new file mode 100644 index 00000000..df36392c --- /dev/null +++ b/mbfido/viadate.c @@ -0,0 +1,68 @@ +/***************************************************************************** + * + * File ..................: mbfido/viadate.c + * Purpose ...............: Create a Via date + * Last modification date : 20-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "viadate.h" + + + +static char *months[] = { + (char *)"Jan", (char *)"Feb", (char *)"Mar", + (char *)"Apr", (char *)"May", (char *)"Jun", + (char *)"Jul", (char *)"Aug", (char *)"Sep", + (char *)"Oct", (char *)"Nov", (char *)"Dec" +}; + + + +static char *weekday[] = { + (char *)"Sun", (char *)"Mon", (char *)"Tue", + (char *)"Wed", (char *)"Thu", (char *)"Fri", + (char *)"Sat" +}; + + + +char *viadate(void) +{ + static char buf[64]; + time_t t; + struct tm *ptm; + + time(&t); + ptm = localtime(&t); + sprintf(buf,"%s %s %d %d at %02d:%02d", weekday[ptm->tm_wday],months[ptm->tm_mon], + ptm->tm_mday,ptm->tm_year+1900,ptm->tm_hour,ptm->tm_min); + return buf; +} + diff --git a/mbfido/viadate.h b/mbfido/viadate.h new file mode 100644 index 00000000..7dc0c2c0 --- /dev/null +++ b/mbfido/viadate.h @@ -0,0 +1,9 @@ +#ifndef _VIADATE_H +#define _VIADATE_H + + +char *viadate(void); + + +#endif + diff --git a/mbmon/Makefile.am b/mbmon/Makefile.am new file mode 100644 index 00000000..6009cdb4 --- /dev/null +++ b/mbmon/Makefile.am @@ -0,0 +1,11 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . +noinst_PROGRAMS = mbmon +mbmon_SOURCES = mutil.c mbmon.c common.c mutil.h mbmon.h common.h + +mbmon_LDADD = ../lib/libmemwatch.a + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbmon $(bindir) + diff --git a/mbmon/Makefile.in b/mbmon/Makefile.in new file mode 100644 index 00000000..9cceb016 --- /dev/null +++ b/mbmon/Makefile.in @@ -0,0 +1,353 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . +noinst_PROGRAMS = mbmon +mbmon_SOURCES = mutil.c mbmon.c common.c mutil.h mbmon.h common.h + +mbmon_LDADD = ../lib/libmemwatch.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbmon_OBJECTS = mutil.o mbmon.o common.o +mbmon_DEPENDENCIES = ../lib/libmemwatch.a +mbmon_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbmon_SOURCES) +OBJECTS = $(mbmon_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbmon/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbmon: $(mbmon_OBJECTS) $(mbmon_DEPENDENCIES) + @rm -f mbmon + $(LINK) $(mbmon_LDFLAGS) $(mbmon_OBJECTS) $(mbmon_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbmon + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +common.o: common.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h common.h +mbmon.o: mbmon.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h common.h mutil.h +mutil.o: mutil.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h common.h mutil.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbmon $(bindir) + +# 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/mbmon/common.c b/mbmon/common.c new file mode 100644 index 00000000..2c8d60f1 --- /dev/null +++ b/mbmon/common.c @@ -0,0 +1,918 @@ +/***************************************************************************** + * + * File ..................: mbmon/common.c + * Purpose ...............: Common utilities + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include +#include "common.h" + + +pid_t mypid; /* Original parent pid if child */ +unsigned long lcrc = 0, tcrc = 1; /* CRC value of logstring */ +int lcnt = 0; /* Same message counter */ +static char *pbuff = NULL; +static int sock = -1; /* TCP/IP socket */ + +struct sockaddr_un clntaddr; /* Client socket address */ +struct sockaddr_un servaddr; /* Server socket address */ +struct sockaddr_un from; /* From socket address */ +int fromlen; +static char spath[108]; /* Server socket path */ +static char cpath[108]; /* Client socket path */ + + + + +void InitClient(char *user) +{ + sprintf(cpath, "%s/tmp/mbmon%d", getenv("MBSE_ROOT"), getpid()); + sprintf(spath, "%s/tmp/mbtask", getenv("MBSE_ROOT")); + + /* + * Store my pid in case a child process is forked and wants to do + * some communications with the mbsed server. + */ + mypid = getpid(); + if (socket_connect(user) == -1) { + printf("PANIC: cannot access socket\n"); + exit(1); + } +} + + + +void ExitClient(int errcode) +{ + if (socket_shutdown(mypid) == -1) + printf("PANIC: unable to shutdown socket\n"); + fflush(stdout); + fflush(stdin); + + if (pbuff) + free(pbuff); + + unlink(cpath); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(errcode); +} + + + +void SockS(const char *format, ...) +{ + char *out; + va_list va_ptr; + + out = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(out, format, va_ptr); + va_end(va_ptr); + + if (socket_send(out) == 0) + socket_receive(); + + free(out); +} + + + +char *SockR(const char *format, ...) +{ + static char buf[SS_BUFSIZE]; + char *out; + va_list va_ptr; + + memset(&buf, 0, SS_BUFSIZE); + out = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(out, format, va_ptr); + va_end(va_ptr); + + if (socket_send(out) == 0) + sprintf(buf, "%s", socket_receive()); + + free(out); + return buf; +} + + + +void Syslog(int level, const char *format, ...) +{ + char *outstr; + va_list va_ptr; + int i; + + outstr = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + + for (i = 0; i < strlen(outstr); i++) + if (outstr[i] == '\r' || outstr[i] == '\n') + outstr[i] = ' '; + + tcrc = StringCRC32(outstr); + if (tcrc == lcrc) { + lcnt++; + free(outstr); + return; + } else { + lcrc = tcrc; + if (lcnt) { + lcnt++; + SockS("ALOG:5,mbmon.log,mbmon,%d,+,Last message repeated %d times;", mypid, lcnt); + } + lcnt = 0; + } + + SockS("ALOG:5,mbmon.log,mbmon,%d,+,%s;", mypid, outstr); + free(outstr); +} + + + +void IsDoing(const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(64, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + SockS("ADOI:2,%d,%s;", mypid, outputstr); + free(outputstr); +} + + + +static time_t nop = 0; + +/* + * This function can be called very often but will only send once a minute + * a NOP to the server. This is a simple solution to keep server trafic low. + */ +void Nopper(void) +{ + time_t now; + + now = time(NULL); + if (((time_t)now - (time_t)nop) > 60) { + nop = now; + SockS("GNOP:1,%d;", mypid); + } +} + + + +/************************************************************************ + * + * Connect to Unix Datagram socket, return -1 if error or socket no. + */ + +int socket_connect(char *user) +{ + int s; + static char buf[SS_BUFSIZE]; + char tty[18]; + + if ((s = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) { + perror("mbmon"); + printf("Unable to create Unix Datagram socket\n"); + return -1; + } + + memset(&clntaddr, 0, sizeof(clntaddr)); + clntaddr.sun_family = AF_UNIX; + strcpy(clntaddr.sun_path, cpath); + + if (bind(s, &clntaddr, sizeof(clntaddr)) < 0) { + close(s); + perror("mbmon"); + printf("Can't bind socket %s\n", cpath); + return -1; + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sun_family = AF_UNIX; + sprintf(servaddr.sun_path, "%s", (char *)spath); + + /* + * Now that we have an connection, we gather + * information to tell the server who we are. + */ + if (isatty(1) && (ttyname(1) != NULL)) { + strcpy(tty, ttyname(1)); + if (strchr(tty, 'p')) + strcpy(tty, index(tty, 'p')); + else if (strchr(tty, 't')) + strcpy(tty, index(tty, 't')); + else if (strchr(tty, 'c')) + strcpy(tty, index(tty, 'c')); + } else { + strcpy(tty, "-"); + } + sock = s; + + /* + * Send the information to the server. + */ + sprintf(buf, "AINI:5,%d,%s,%s,mbmon,localhost;", getpid(), tty, user); + if (socket_send(buf) != 0) { + sock = -1; + return -1; + } + + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:0;", 6) != 0) { + printf("AINI not acknowledged by the server\n"); + sock = -1; + return -1; + } + + return s; +} + + + +/* + * Send data via Unix Datagram socket + */ +int socket_send(char *buf) +{ + if (sock == -1) + return -1; + + if (sendto(sock, buf, strlen(buf), 0, (struct sockaddr *) & servaddr, sizeof(servaddr)) != strlen(buf)) { + printf("Socket send failed error %d\n", errno); + return -1; + } + + return 0; +} + + + +/* + * Return an empty buffer if somthing went wrong, else the complete + * dataline is returned. + */ +char *socket_receive(void) +{ + static char buf[SS_BUFSIZE]; + int rlen; + + memset((char *)&buf, 0, SS_BUFSIZE); + fromlen = sizeof(from); + rlen = recvfrom(sock, buf, SS_BUFSIZE, 0, &from, &fromlen); + if (rlen == -1) { + perror("recv"); + printf("Error reading socket\n"); + memset((char *)&buf, 0, SS_BUFSIZE); + return buf; + } + return buf; +} + + + +/*************************************************************************** + * + * Shutdown the socket, first send the server the close command so this + * application will be removed from the servers active clients list. + * There must be a parameter with the pid so that client applications + * where the shutdown will be done by a child process is able to give + * the parent pid as an identifier. + */ + +int socket_shutdown(pid_t pid) +{ + static char buf[SS_BUFSIZE]; + + if (sock == -1) + return 0; + + sprintf(buf, "ACLO:1,%d;", pid); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "107:0;", 6) != 0) { + printf("Shutdown not acknowledged by the server\n"); + printf("Got \"%s\"\n", buf); + } + } + + if (shutdown(sock, 1) == -1) { + perror("mbmon"); + printf("Cannot shutdown socket\n"); + return -1; + } + + sock = -1; + return 0; +} + + + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ +/* 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. */ + +unsigned long crc32tab[] = { /* 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 +}; + + + +/* Calculate the CRC of a string. */ + +unsigned long str_crc32(char *str) +{ + unsigned long crc; + + for (crc=0L; *str; str++) + crc = crc32tab[((int)crc^(*str)) & 0xff] ^ ((crc>>8) & 0x00ffffff); + return crc; +} + + + +unsigned long StringCRC32(char *str) +{ + unsigned long crc; + + for (crc = 0xffffffff; *str; str++) + crc = crc32tab[((int)crc^(*str)) & 0xff] ^ ((crc>>8) & 0x00ffffff); + return crc; +} + + + +int rawset = FALSE; + + +/* + * Sets raw mode and saves the terminal setup + */ +void Setraw() +{ + if (ioctl(ttyfd, TCGETA, &tbuf) == -1) { + perror("TCGETA Failed"); + exit(1); /* ERROR - could not set get tty ioctl */ + } + + tbufsav = tbuf; + tbuf.c_iflag &= ~(INLCR | ICRNL | IUCLC | ISTRIP | IXON ); + /* + * Map CRNL modes strip control characters and flow control + */ + tbuf.c_oflag &= ~OPOST; /* Don't do ouput character translation */ + tbuf.c_lflag &= ~(ICANON | ECHO); /* No canonical input and no echo */ + tbuf.c_cc[VMIN] = 1; /* Receive 1 character at a time */ + tbuf.c_cc[VTIME] = 0; /* No time limit per character */ + + if (ioctl(ttyfd, TCSETAF, &tbuf) == -1) { + perror("TCSETAF failed"); + exit(1); /* ERROR - could not set tty ioctl */ + } + + rawset = TRUE; +} + + + +/* + * Unsets raw mode and returns state of terminal + */ +void Unsetraw() +{ + /* + * Only unset the mode if it is set to raw mode + */ + if (rawset == TRUE) { + if (ioctl(ttyfd, TCSETAF, &tbufsav) == -1) { + perror("TCSETAF Normal Failed"); + exit(1); /* ERROR - could not save original tty ioctl */ + } + } + rawset = FALSE; +} + + + +/* + * Wait for a character for a maximum of wtime * 10 mSec. + */ +int Waitchar(unsigned char *ch, int wtime) +{ + int i, rc = -1; + + for (i = 0; i < wtime; i++) { + rc = read(ttyfd, ch, 1); + if (rc == 1) + return rc; + usleep(10000); + } + return rc; +} + + + +int Escapechar(unsigned char *ch) +{ + int rc; + unsigned char c; + + /* + * Escape character, if nothing follows within + * 50 mSec, the user really pressed . + */ + if ((rc = Waitchar(ch, 5)) == -1) + return rc; + + if (*ch == '[') { + /* + * Start of CSI sequence. If nothing follows, + * return immediatly. + */ + if ((rc = Waitchar(ch, 5)) == -1) + return rc; + + /* + * Test for the most important keys. Note + * that only the cursor movement keys are + * guaranteed to work with PC-clients. + */ + c = *ch; + if (c == 'A') + c = KEY_UP; + if (c == 'B') + c = KEY_DOWN; + if (c == 'C') + c = KEY_RIGHT; + if (c == 'D') + c = KEY_LEFT; + if ((c == '1') || (c == 'H') || (c == 0)) + c = KEY_HOME; + if ((c == '4') || (c == 'K') || (c == 101) || (c == 144)) + c = KEY_END; + if (c == '2') + c = KEY_INS; + if (c == '3') + c = KEY_DEL; + if (c == '5') + c = KEY_PGUP; + if (c == '6') + c = KEY_PGDN; + memcpy(ch, &c, sizeof(unsigned char)); + return rc; + } + return -1; +} + + + +/* + * Returns the offset from your location to UTC. So in the MET timezone + * this returns -60 (wintertime). People in the USA get positive results. + */ +long gmt_offset(time_t now) +{ + struct tm ptm; + struct tm gtm; + long offset; + + if (!now) + time(&now); + ptm = *localtime(&now); + + /* + * To get the timezone, compare localtime with GMT. + */ + gtm = *gmtime(&now); + + /* + * Assume we are never more than 24 hours away. + */ + offset = gtm.tm_yday - ptm.tm_yday; + if (offset > 1) + offset = -24; + else if (offset < -1) + offset = 24; + else + offset *= 24; + + /* + * Scale in the hours and minutes; ignore seconds. + */ + offset += gtm.tm_hour - ptm.tm_hour; + offset *= 60; + offset += gtm.tm_min - ptm.tm_min; + + return offset; +} + + + +/* + * Returns the TZUTC string, note that the sign is opposite from the + * function above. + */ +char *gmtoffset(time_t now) +{ + static char buf[6]="+0000"; + char sign; + int hr, min; + long offset; + + offset = gmt_offset(now); + + if (offset <= 0) { + sign = '+'; + offset = -offset; + } else + sign = '-'; + + hr = offset / 60L; + min = offset % 60L; + + if (sign == '-') + sprintf(buf, "%c%02d%02d", sign, hr, min); + else + sprintf(buf, "%02d%02d", hr, min); + + return(buf); +} + + + +char *str_time(time_t total) +{ + static char buf[10]; + int h, m; + + memset(&buf, 0, sizeof(buf)); + + /* + * 0 .. 59 seconds + */ + if (total < (time_t)60) { + sprintf(buf, "%2d.00s", (int)total); + return buf; + } + + /* + * 1:00 .. 59:59 minutes:seconds + */ + if (total < (time_t)3600) { + h = total / 60; + m = total % 60; + sprintf(buf, "%2d:%02d ", h, m); + return buf; + } + + /* + * 1:00 .. 23:59 hours:minutes + */ + if (total < (time_t)86400) { + h = (total / 60) / 60; + m = (total / 60) % 60; + sprintf(buf, "%2d:%02dm", h, m); + return buf; + } + + /* + * 1/00 .. 30/23 days/hours + */ + if (total < (time_t)2592000) { + h = (total / 3600) / 24; + m = (total / 3600) % 24; + sprintf(buf, "%2d/%02dh", h, m); + return buf; + } + + sprintf(buf, "N/A "); + return buf; +} + + + +char *t_elapsed(time_t start, time_t end) +{ + return str_time(end - start); +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = malloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = malloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + + + +char *padleft(char *str, int size, char pad) +{ + static char stri[256]; + static char temp[256]; + + strcpy(stri, str); + memset(temp, pad, (long)size); + temp[size] = '\0'; + if (strlen(stri) <= size) + memmove(temp, stri, (long)strlen(stri)); + else + memmove(temp, stri, (long)size); + return temp; +} + + + +void Striplf(char *String) +{ + int i; + + for(i = 0; i < strlen(String); i++) { + if(*(String + i) == '\0') + break; + if(*(String + i) == '\n') + *(String + i) = '\0'; + } +} + + + +/* + * Changes ansi background and foreground color + */ +void colour(int fg, int bg) +{ + int att=0, fore=37, back=40; + + if (fg<0 || fg>31 || bg<0 || bg>7) { + printf("ANSI: Illegal colour specified: %i, %i\n", fg, bg); + return; + } + + printf("["); + if ( fg > 15) { + printf("5;"); + fg-=16; + } + if (fg > 7) { + att=1; + fg=fg-8; + } + + if (fg==0) fore=30; + else if (fg==1) fore=34; + else if (fg==2) fore=32; + else if (fg==3) fore=36; + else if (fg==4) fore=31; + else if (fg==5) fore=35; + else if (fg==6) fore=33; + else fore=37; + + if (bg==1) back=44; + else if (bg==2) back=42; + else if (bg==3) back=46; + else if (bg==4) back=41; + else if (bg==5) back=45; + else if (bg==6) back=43; + else if (bg==7) back=47; + else back=40; + + printf("%d;%d;%dm", att, fore, back); +} + + + +void clear() +{ + colour(LIGHTGRAY, BLACK); + printf(ANSI_HOME); + printf(ANSI_CLEAR); +} + + + +/* + * Moves cursor to specified position + */ +void locate(int y, int x) +{ + if (y > LINES || x > COLS) { + printf("ANSI: Invalid screen coordinates: %i, %i\n", y, x); + return; + } + printf("\x1B[%i;%iH", y, x); +} + + + +/* + * curses compatible functions + */ +void mvprintw(int y, int x, const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + locate(y, x); + printf(outputstr); + free(outputstr); +} + + + +/* + * Signal handler signal names. + */ + +#ifdef __i386__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __PPC__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __sparc__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGLOST", "SIGUSR1", "SIGUSR2"}; +#endif + +#ifdef __alpha__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGINFO", "SIGUSR1", "SIGUSR2"}; + + +#endif + diff --git a/mbmon/common.h b/mbmon/common.h new file mode 100644 index 00000000..33a2d7b1 --- /dev/null +++ b/mbmon/common.h @@ -0,0 +1,97 @@ +#ifndef _COMMON_H +#define _COMMON_H + + +#pragma pack(1) + +#define MBSE_SS(x) (x)?(x):"(null)" +#define SS_BUFSIZE 2048 + + +/* + * Returned function keys + */ +#define KEY_BACKSPACE 8 +#define KEY_LINEFEED 10 +#define KEY_ENTER 13 +#define KEY_ESCAPE 27 +#define KEY_RUBOUT 127 +#define KEY_UP 200 +#define KEY_DOWN 201 +#define KEY_LEFT 202 +#define KEY_RIGHT 203 +#define KEY_HOME 204 +#define KEY_END 205 +#define KEY_INS 206 +#define KEY_DEL 207 +#define KEY_PGUP 208 +#define KEY_PGDN 209 + + +#define LINES 24 +#define COLS 80 + + +/* + * ANSI colors + */ +#define BLACK 0 +#define BLUE 1 +#define GREEN 2 +#define CYAN 3 +#define RED 4 +#define MAGENTA 5 +#define BROWN 6 +#define LIGHTGRAY 7 +#define DARKGRAY 8 +#define LIGHTBLUE 9 +#define LIGHTGREEN 10 +#define LIGHTCYAN 11 +#define LIGHTRED 12 +#define LIGHTMAGENTA 13 +#define YELLOW 14 +#define WHITE 15 + +#define ANSI_CLEAR "\x1B[2J" +#define ANSI_HOME "\x1B[H" + +extern char SigName[32][16]; + + + +int ttyfd; /* Filedescriptor for raw mode */ +struct termio tbuf, tbufsav; /* Structure for raw mode */ + + +void InitClient(char *); +void ExitClient(int); +void SockS(const char *, ...); +char *SockR(const char *, ...); +void Syslog(int, const char *, ...); +void IsDoing(const char *, ...); +void Nopper(void); +int socket_connect(char *); +int socket_send(char *); +char *socket_receive(void); +int socket_shutdown(pid_t); +unsigned long str_crc32(char *str); +unsigned long StringCRC32(char *); +long gmt_offset(time_t); +char *gmtoffset(time_t); +char *str_time(time_t); +char *t_elapsed(time_t, time_t); +void Setraw(void); /* Set raw mode */ +void Unsetraw(void); /* Unset raw mode */ +int Waitchar(unsigned char *, int); /* Wait n * 10mSec for char */ +int Escapechar(unsigned char *); /* Escape sequence test */ +char *xstrcpy(char *); +char *padleft(char *str, int size, char pad); +void Striplf(char *String); +void colour(int, int); +void clear(void); +void locate(int, int); +void mvprintw(int, int, const char *, ...); + + +#endif + diff --git a/mbmon/mbmon.c b/mbmon/mbmon.c new file mode 100644 index 00000000..ebb9dae8 --- /dev/null +++ b/mbmon/mbmon.c @@ -0,0 +1,451 @@ +/***************************************************************************** + * + * File ..................: mbmon/mbmon.c + * Purpose ...............: Monitor Program + * Last modification date : 29-Jun-2001 + * Todo ..................: Trace logfiles + * Chat with user via server + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "common.h" +#include "mutil.h" + + +extern char *version; +extern char *copyright; + + + +static void die(int onsig) +{ + signal(onsig, SIG_IGN); + screen_stop(); + if (onsig && (onsig <= NSIG)) + Syslog('?', "$Finished on signal %s", SigName[onsig]); + else + Syslog(' ', "Normally finished"); + ExitClient(0); +} + + + +void ShowSysinfo(void) +{ + int ch; + char buf[128], *cnt; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "5. SHOW BBS SYSTEM INFO"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Total calls"); + mvprintw( 8, 6, "2. Pots calls"); + mvprintw( 9, 6, "3. ISDN calls"); + mvprintw(10, 6, "4. Network calls"); + mvprintw(11, 6, "5. Local calls"); + mvprintw(12, 6, "6. Date started"); + mvprintw(13, 6, "7. Last caller"); + center_addstr(LINES - 4, (char *)"Press any key"); + IsDoing("View System Info"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + set_color(LIGHTGRAY, BLACK); + sprintf(buf, "GSYS:1,%d;", getpid()); + if (socket_send(buf) == 0) { + sprintf(buf, "%s", socket_receive()); + if (strncmp(buf, "100:7,", 6) == 0) { + cnt = strtok(buf, ","); + mvprintw( 7,26, "%s", strtok(NULL, ",")); + mvprintw( 8,26, "%s", strtok(NULL, ",")); + mvprintw( 9,26, "%s", strtok(NULL, ",")); + mvprintw(10,26, "%s", strtok(NULL, ",")); + mvprintw(11,26, "%s", strtok(NULL, ",")); + mvprintw(12,26, "%s", strtok(NULL, ",")); + mvprintw(13,26, "%s", strtok(NULL, ";")); + fflush(stdout); + } + } + ch = testkey(LINES - 4, COLS / 2 + 8); + } while (ch == '\0'); +} + + + +void ShowLastcaller(void) +{ + int records, ch, i, y, o; + char buf[128], *cnt; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 6, "6. SHOW BBS LASTCALLERS"); + set_color(YELLOW, RED); + mvprintw( 6, 1, "Nr Username Location Level Device Time Mins Calls Speed Actions"); + set_color(CYAN, BLACK); + center_addstr(LINES - 4, (char *)"Press any key"); + IsDoing("View Lastcallers"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + records = 0; + sprintf(buf, "GLCC:0;"); + if (socket_send(buf) == 0) { + sprintf(buf, "%s", socket_receive()); + if (strncmp(buf, "100:1,", 6) == 0) { + cnt = strtok(buf, ","); + records = atoi(strtok(NULL, ";")); + } + } + + if (records) { + y = 7; + if (records > 10) + o = records -10; + else + o = 1; + set_color(CYAN, BLACK); + for (i = o; i <= records; i++) { + sprintf(buf, "GLCR:1,%d;", i); + if (socket_send(buf) == 0) { + sprintf(buf, "%s", socket_receive()); + if (strncmp(buf, "100:9,", 6) == 0) { + cnt = strtok(buf, ","); + mvprintw(y, 1, "%2d", i); + mvprintw(y, 4, "%s", strtok(NULL, ",")); + mvprintw(y,19, "%s", strtok(NULL, ",")); + mvprintw(y,32, "%s", strtok(NULL, ",")); + mvprintw(y,38, "%s", strtok(NULL, ",")); + mvprintw(y,45, "%s", str_time(atoi(strtok(NULL, ",")))); + mvprintw(y,52, "%s", strtok(NULL, ",")); + mvprintw(y,57, "%s", strtok(NULL, ",")); + mvprintw(y,63, "%s", strtok(NULL, ",")); + mvprintw(y,73, "%s", strtok(NULL, ";")); + y++; + } + } + } + } + ch = testkey(LINES - 4, COLS / 2 + 8); + } while (ch == '\0'); +} + + + +void system_moni(void) +{ + int ch, y, eof; + char *cnt; + char buf[128]; + time_t start, now; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1. SERVER CLIENTS"); + set_color(YELLOW, RED); + mvprintw( 7, 1, "Pid tty user program city doing time "); + set_color(CYAN, BLACK); + center_addstr(LINES - 4, (char *)"Press any key"); + IsDoing("System Monitor"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + + eof = 0; + set_color(LIGHTGRAY, BLACK); + + for (y = 8; y <= LINES - 5; y++) { + if (y == 8) + sprintf(buf, "GMON:1,1;"); + else + sprintf(buf, "GMON:1,0;"); + if (eof == 0) { + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + locate(y, 1); + clrtoeol(); + if (strncmp(buf, "100:0;", 6) == 0) { + /* + * There's no more information + */ + eof = 1; + } else { + cnt = strtok(buf, ","); + mvprintw(y, 1, (char *)"%.5s", strtok(NULL, ",")); + mvprintw(y, 7, (char *)"%.6s", strtok(NULL, ",")); + mvprintw(y,14, (char *)"%.16s", strtok(NULL, ",")); + mvprintw(y,31, (char *)"%.8s", strtok(NULL, ",")); + mvprintw(y,40, (char *)"%.15s", strtok(NULL, ",")); + mvprintw(y,56, (char *)"%.18s", strtok(NULL, ",")); + start = atoi(strtok(NULL, ";")); + now = time(NULL); + mvprintw(y,75, (char *)"%s", t_elapsed(start, now)); + } + } + } else { + /* + * If no valid data, clear line + */ + locate(y, 1); + clrtoeol(); + } + } /* for () */ + + ch = testkey(LINES - 4, COLS / 2 + 8); + } while (ch == '\0'); +} + + + +void system_stat(void) +{ + int ch; + char buf[256]; + char *cnt; + time_t now; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "2. SERVER STATISTICS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "First date started"); + mvprintw( 7,62, "BBS Open"); + mvprintw( 8, 6, "Last date started"); + mvprintw( 8,62, "ZMH"); + mvprintw( 9, 6, "Total server starts"); + mvprintw( 9,62, "Internet"); + mvprintw(10, 6, "Connected clients"); + mvprintw(10,62, "Running"); + mvprintw(11,62, "Load avg"); + mvprintw(12,30, "Total Today"); + hor_lin(13,30,8); + hor_lin(13,45,8); + mvprintw(14, 6, "Client connects"); + mvprintw(15, 6, "Peak connections"); + mvprintw(16, 6, "Protocol syntax errors"); + mvprintw(17, 6, "Communication errors"); + mvprintw(19, 6, "Next sequence number"); + mvprintw(19,62, "Press any key"); + IsDoing("System Statistics"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + + sprintf(buf, "GSTA:1,%d;", getpid()); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + set_color(LIGHTGRAY, BLACK); + cnt = strtok(buf, ","); + now = atoi(strtok(NULL, ",")); + mvprintw(7, 30, "%s", ctime(&now)); + now = atoi(strtok(NULL, ",")); + mvprintw(8, 30, "%s", ctime(&now)); + cnt = strtok(NULL, ","); + mvprintw(9, 30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(10,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(14,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(15,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(16,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(17,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(14,45, (char *)"%s ", strtok(NULL, ",")); + mvprintw(15,45, (char *)"%s ", strtok(NULL, ",")); + mvprintw(16,45, (char *)"%s ", strtok(NULL, ",")); + mvprintw(17,45, (char *)"%s ", strtok(NULL, ",")); + mvprintw(7,72, "%s", atoi(strtok(NULL, ",")) == 1?"Yes":"No "); + mvprintw(8,72, "%s", atoi(strtok(NULL, ",")) == 1?"Yes":"No "); + mvprintw(9,72, "%s", atoi(strtok(NULL, ",")) == 1?"Yes":"No "); + mvprintw(10,72,"%s", atoi(strtok(NULL, ",")) == 1?"Yes":"No "); + mvprintw(11,72, "%s ", strtok(NULL, ",")); + mvprintw(19,30, (char *)"%s", strtok(NULL, ";")); + } + + ch = testkey(19,76); + } while (ch == '\0'); +} + + + +void disk_stat(void) +{ + int ch, i; + char buf[1024]; + char *cnt, *type, *fs, *p; + unsigned long last[10]; + unsigned long size, used, perc; + char sign; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "3. FILESYSTEM USAGE"); + set_color(YELLOW, RED); + mvprintw( 7, 1, " Size MB Used MB Perc. FS-Type Mountpoint "); + set_color(CYAN, BLACK); + mvprintw(LINES - 2, 6, "Press any key"); + IsDoing("Filesystem Usage"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + + sprintf(buf, "GDST:1,%d;", getpid()); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + set_color(LIGHTGRAY, BLACK); + cnt = strtok(buf, ":"); + cnt = strtok(NULL, ",;"); + if (atoi(cnt)) { + for (i = 0; i < atoi(cnt); i++) { + p = strtok(NULL, " "); + size = atoi(p); + p = strtok(NULL, " "); + used = size - atoi(p); + perc = (used * 100) / size; + sign = ' '; + fs = strtok(NULL, " "); + type = strtok(NULL, ",;"); + if (used > last[i]) + sign = '^'; + if (used < last[i]) + sign = 'v'; + if (last[i] == 0) + sign = ' '; + last[i] = used; + set_color(CYAN, BLACK); + mvprintw(i+8, 1, "%8lu %8lu ", + size, used); + set_color(WHITE, BLACK); + printf("%c ", sign); + set_color(CYAN, BLACK); + if (strstr(type, "iso") == NULL) { + if (perc >= 95) + set_color(LIGHTRED, BLACK); + else if (perc >= 80) + set_color(YELLOW, BLACK); + } + printf("%3lu", perc); + putchar('%'); + set_color(CYAN, BLACK); + printf(" %-8s %-40s", type, fs); + } + locate(i+8, 1); + clrtoeol(); + } + } + + ch = testkey(LINES - 2, 20); + } while (ch == '\0'); +} + + + +void soft_info(void) +{ + clr_index(); + set_color(YELLOW, BLACK); + center_addstr( 7, (char *)"MBSE BBS"); + set_color(WHITE, BLACK); + center_addstr( 9, (char *)"(c) Michiel Broek"); + set_color(YELLOW, BLACK); + center_addstr(11, (char *)"Made in the Netherlands"); + set_color(LIGHTGREEN, BLACK); + center_addstr(LINES -8, (char *)"This is free software; released under the terms of the GNU General"); + center_addstr(LINES -7, (char *)"Public License as published by the Free Software Foundation."); + set_color(CYAN, BLACK); + center_addstr(LINES -4, (char *)"Press any key"); + readkey(LINES - 4, COLS / 2 + 8, LIGHTGRAY, BLACK); +} + + + +int main(int argc, char *argv[]) +{ + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * Find out who is on the keyboard or automated the keyboard. + */ + pw = getpwuid(getuid()); + InitClient(pw->pw_name); + Syslog(' ', "Started by %s", pw->pw_name); + + /* + * Setup several signals so when the program terminate's it + * will properly close. + */ + signal(SIGINT, (void (*))die); + signal(SIGBUS, (void (*))die); + signal(SIGSEGV,(void (*))die); + signal(SIGTERM,(void (*))die); + signal(SIGKILL,(void (*))die); + + screen_start((char *)"MBmon"); + + for (;;) { + + IsDoing("Browsing Menu"); + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "0. MBSE BBS MONITOR"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. View Server Clients"); + mvprintw( 8, 6, "2. View Server Statistics"); + mvprintw( 9, 6, "3. View Filesystem Usage"); + mvprintw(10, 6, "4. View System Logfiles"); + mvprintw(11, 6, "5. View BBS System Information"); + mvprintw(12, 6, "6. View BBS Lastcallers List"); + mvprintw(13, 6, "7. View Software Information"); + + switch(select_menu(7)) { + case 0: + die(0); + break; + case 1: + system_moni(); + break; + case 2: + system_stat(); + break; + case 3: + disk_stat(); + break; + case 5: + ShowSysinfo(); + break; + case 6: + ShowLastcaller(); + break; + case 7: + soft_info(); + break; + } + } +} + diff --git a/mbmon/mbmon.h b/mbmon/mbmon.h new file mode 100644 index 00000000..596d9e24 --- /dev/null +++ b/mbmon/mbmon.h @@ -0,0 +1,14 @@ +#ifndef _MBMON_H +#define _MBMON_H + +static void die(int); +void ShowSysinfo(void); +void ShowLastcaller(void); +void system_moni(void); +void system_stat(void); +void disk_stat(void); +void soft_info(void); + + +#endif + diff --git a/mbmon/mutil.c b/mbmon/mutil.c new file mode 100644 index 00000000..bd578c67 --- /dev/null +++ b/mbmon/mutil.c @@ -0,0 +1,548 @@ +/***************************************************************************** + * + * File ..................: mutil.c + * Purpose ...............: Utilities + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "common.h" +#include "mutil.h" + + +unsigned char readkey(int y, int x, int fg, int bg) +{ + int rc = -1, i; + unsigned char ch = 0; + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 9"); + exit(1); + } + Setraw(); + + i = 0; + while (rc == -1) { + if ((i % 10) == 0) + show_date(fg, bg, 0, 0); + + locate(y, x); + fflush(stdout); + rc = Waitchar(&ch, 5); + if ((rc == 1) && (ch != KEY_ESCAPE)) + break; + + if ((rc == 1) && (ch == KEY_ESCAPE)) + rc = Escapechar(&ch); + + if (rc == 1) + break; + i++; + Nopper(); + } + + Unsetraw(); + close(ttyfd); + + return ch; +} + + + +unsigned char testkey(int y, int x) +{ + int rc; + unsigned char ch = 0; + + Nopper(); + locate(y, x); + fflush(stdout); + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 9"); + exit(1); + } + Setraw(); + + rc = Waitchar(&ch, 100); + if (rc == 1) { + if (ch == KEY_ESCAPE) + rc = Escapechar(&ch); + } + + Unsetraw(); + close(ttyfd); + + if (rc == 1) + return ch; + else + return '\0'; +} + + + +void show_field(int y, int x, char *str, int length, int fill) +{ + mvprintw(y, x, padleft(str, length, fill)); +} + + +int insertflag = 0; + +void newinsert(int i, int fg, int bg) +{ + insertflag = i; + set_color(YELLOW, RED); + if (insertflag != 0) { + mvprintw(2,36," INS "); + } else { + mvprintw(2,36," OVR "); + } + set_color(fg, bg); +} + + + + +char *edit_field(int y, int x, int w, int p, char *s_) +{ + int i, charok, first, curpos; + static char s[256]; + unsigned int ch; + + memset((char *)s, 0, 256); + sprintf(s, "%s", s_); + curpos = 0; + first = 1; + newinsert(1, YELLOW, BLUE); + + do { + set_color(YELLOW, BLUE); + show_field(y, x, s, w, '_'); + locate(y, x + curpos); + do { + ch = readkey(y, x + curpos, YELLOW, BLUE); + set_color(YELLOW, BLUE); + + /* + * Test if the pressed key is a valid key. + */ + charok = 0; + if ((ch >= ' ') && (ch <= '~')) { + switch(p) { + case '!': + ch = toupper(ch); + charok = 1; + break; + case 'X': + charok = 1; + break; + case '9': + if (ch == ' ' || ch == '-' || ch == ',' || + ch == '.' || isdigit(ch)) + charok = 1; + break; + case 'U': + ch = toupper(ch); + if (isupper(ch)) + charok = 1; + break; + default: + putchar(7); + break; + } + } + + } while (charok == 0 && ch != KEY_ENTER && ch != KEY_LINEFEED && + ch != KEY_DEL && ch != KEY_INS && ch != KEY_HOME && + ch != KEY_LEFT && ch != KEY_RIGHT && ch != KEY_ESCAPE && + ch != KEY_BACKSPACE && ch != KEY_RUBOUT && ch != KEY_END); + + + if (charok == 1) { + if (first == 1) { + first = 0; + memset((char *)s, 0, 256); + curpos = 0; + } + if (curpos < w) { + if (insertflag == 1) { + /* + * Insert mode + */ + if (strlen(s) < w) { + if (curpos < strlen(s)) { + for (i = strlen(s); i >= curpos; i--) + s[i+1] = s[i]; + } + s[curpos] = ch; + if (curpos < w) + curpos++; + } else { + putchar(7); + } + } else { + /* + * Overwrite mode + */ + s[curpos] = ch; + if (curpos < w) + curpos++; + } + } else { + /* + * The field is full + */ + putchar(7); + } + } /* if charok */ + + first = 0; + switch (ch) { + case KEY_HOME: + curpos = 0; + break; + case KEY_END: + curpos = strlen(s); + break; + case KEY_LEFT: + if (curpos > 0) + curpos--; + else + putchar(7); + break; + case KEY_RIGHT: + if (curpos < strlen(s)) + curpos++; + else + putchar(7); + break; + case KEY_INS: + if (insertflag == 1) + newinsert(0, YELLOW, BLUE); + else + newinsert(1, YELLOW, BLUE); + break; + case KEY_BACKSPACE: + if (strlen(s) > 0) { + if (curpos >= strlen(s)) { + curpos--; + s[curpos] = '\0'; + } else { + for (i = curpos; i < strlen(s); i++) + s[i] = s[i+1]; + s[i] = '\0'; + } + } else + putchar(7); + break; + case KEY_RUBOUT: + case KEY_DEL: + if (strlen(s) > 0) { + if ((curpos) == (strlen(s) -1)) { + s[curpos] = '\0'; + } else { + for (i = curpos; i < strlen(s); i++) + s[i] = s[i+1]; + s[i] = '\0'; + } + } else + putchar(7); + break; + } + } while ((ch != KEY_ENTER) && (ch != KEY_LINEFEED) && (ch != KEY_ESCAPE)); + + set_color(LIGHTGRAY, BLUE); + mvprintw(2,36, " "); + set_color(LIGHTGRAY, BLACK); + return s; +} + + + +/* + * Select menu, max is the highest item to pick. Returns zero if + * "-" (previous level) is selected. + */ +int select_menu(int max) +{ + static char *menu=(char *)"-"; + char help[80]; + int pick; + + sprintf(help, "Select menu item (1..%d) or ^\"-\"^ for previous level.", max); + showhelp(help); + + /* + * Loop forever until it's right. + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 3, '9', menu); + locate(LINES -3, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) + return 0; + + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + return pick; + + working(2, 0, 0); + working(0, 0, 0); + } +} + + + +void clrtoeol() +{ + int i; + + printf("\r"); + for (i = 0; i < COLS; i++) + putchar(' '); + printf("\r"); + fflush(stdout); +} + + + +void hor_lin(int y, int x, int len) +{ + int i; + + locate(y, x); + for (i = 0; i < len; i++) + putchar('-'); + fflush(stdout); +} + + + +static int old_f = -1; +static int old_b = -1; + +void set_color(int f, int b) +{ + if ((f != old_f) || (b != old_b)) { + old_f = f; + old_b = b; + colour(f, b); + fflush(stdout); + } +} + + + +static time_t lasttime; + +/* + * Show the current date & time in the second status row + */ +void show_date(int fg, int bg, int y, int x) +{ + time_t now; + char *p; + + time(&now); + if (now != lasttime) { + lasttime = now; + set_color(LIGHTGREEN, BLUE); + p = ctime(&now); + Striplf(p); + mvprintw(1, 44, (char *)"%s TZUTC %s", p, gmtoffset(now)); + p = asctime(gmtime(&now)); + Striplf(p); + mvprintw(2, 44, (char *)"%s UTC", p); + if (y && x) + locate(y, x); + set_color(fg, bg); + } +} + + + +void center_addstr(int y, char *s) +{ + mvprintw(y, (COLS / 2) - (strlen(s) / 2), s); +} + + + +/* + * Curses and screen initialisation. + */ +void screen_start(char *name) +{ + int i; + + /* + * Overwrite screen the first time, if user had it black on white + * it will change to white on black. clear() won't do the trick. + */ + set_color(LIGHTGRAY, BLUE); + locate(1, 1); + for (i = 0; i < LINES; i++) { + if (i == 3) + colour(LIGHTGRAY, BLACK); + clrtoeol(); + if (i < LINES) + printf("\n"); + } + fflush(stdout); + + set_color(WHITE, BLUE); + locate(1, 1); + printf((char *)"%s for MBSE BBS version %s", name, VERSION); + set_color(YELLOW, BLUE); + locate(2, 1); + printf((char *)"(c) Copyright Michiel Broek"); + set_color(LIGHTGRAY, BLACK); + show_date(LIGHTGRAY, BLACK, 0, 0); + fflush(stdout); +} + + + +/* + * Screen deinit + */ +void screen_stop() +{ + set_color(LIGHTGRAY, BLACK); + clear(); + fflush(stdout); +} + + + +/* + * Message at the upperright window about actions + */ +void working(int txno, int y, int x) +{ + int i; + + /* + * If txno not 0 there will be something written. The + * reversed attributes for mono, or white on red for + * color screens is set. The cursor is turned off and + * original cursor position is saved. + */ + show_date(LIGHTGRAY, BLACK, 0, 0); + + if (txno != 0) + set_color(YELLOW, RED); + else + set_color(LIGHTGRAY, BLACK); + + switch (txno) { + case 0: mvprintw(4, 66, (char *)" "); + break; + case 1: mvprintw(4, 66, (char *)"Working . . ."); + break; + case 2: mvprintw(4, 66, (char *)">>> ERROR <<<"); + for (i = 1; i <= 5; i++) { + putchar(7); + fflush(stdout); + usleep(150000); + } + usleep(550000); + break; + case 3: mvprintw(4, 66, (char *)"Form inserted"); + putchar(7); + fflush(stdout); + sleep(1); + break; + case 4: mvprintw(4, 66, (char *)"Form deleted "); + putchar(7); + fflush(stdout); + sleep(1); + break; + } + + show_date(LIGHTGRAY, BLACK, 0, 0); + set_color(LIGHTGRAY, BLACK); + if (y && x) + locate(y, x); + fflush(stdout); +} + + + +/* + * Clear the middle window + */ +void clr_index() +{ + int i; + + set_color(LIGHTGRAY, BLACK); + for (i = 3; i <= (LINES - 1); i++) { + locate(i, 1); + clrtoeol(); + } +} + + + +/* + * Show help at the bottom of the screen. + */ +void showhelp(char *T) +{ + int f, i, x, forlim; + + f = FALSE; + locate(LINES-1, 1); + set_color(WHITE, RED); + clrtoeol(); + x = 0; + forlim = strlen(T); + + for (i = 0; i < forlim; i++) { + if (T[i] == '^') { + if (f == FALSE) { + f = TRUE; + set_color(YELLOW, RED); + } else { + f = FALSE; + set_color(WHITE, RED); + } + } else { + putchar(T[i]); + x++; + } + } + set_color(LIGHTGRAY, BLACK); + fflush(stdout); +} + + diff --git a/mbmon/mutil.h b/mbmon/mutil.h new file mode 100644 index 00000000..2772d449 --- /dev/null +++ b/mbmon/mutil.h @@ -0,0 +1,22 @@ +#ifndef _MUTIL_H +#define _MUTIL_H + +unsigned char readkey(int, int, int, int); +unsigned char testkey(int, int); +void show_field(int, int, char *, int, int); +void newinsert(int, int, int); +char *edit_field(int, int, int, int, char *); +int select_menu(int); +void clrtoeol(void); +void hor_lin(int, int, int); +void set_color(int, int); +void show_date(int, int, int, int); +void center_addstr(int y, char *s); +void screen_start(char *); +void screen_stop(void); +void working(int, int, int); +void clr_index(void); +void showhelp(char *); + +#endif + diff --git a/mbsebbs/Makefile.am b/mbsebbs/Makefile.am new file mode 100644 index 00000000..8fec03e6 --- /dev/null +++ b/mbsebbs/Makefile.am @@ -0,0 +1,61 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . +noinst_PROGRAMS = mbsebbs mball mblang mbchat mbfbgen mbstat mbtoberep mbuser mbuseradd mbpasswd + +mbsebbs_SOURCES = bank.c bbslist.c chat.c file.c funcs.c funcs4.c mail.c menu.c \ +misc.c pinfo.c nextuser.c oneline.c page.c pwcheck.c fsedit.c \ +bye.c change.c mbsebbs.c safe.c timeout.c user.c timecheck.c \ +exitinfo.c filesub.c lineedit.c offline.c language.c msgutil.c \ +newuser.c pop3.c email.c \ +bank.h bbslist.h chat.h file.h funcs.h funcs4.h mail.h menu.h \ +misc.h pinfo.h nextuser.h oneline.h page.h pwcheck.h fsedit.h \ +bye.h change.h mbsebbs.h safe.h timeout.h user.h timecheck.h \ +exitinfo.h filesub.h lineedit.h offline.h language.h msgutil.h \ +newuser.h pop3.h email.h statetbl.h + +mball_SOURCES = mball.c mball.h + +mblang_SOURCES = mblang.c + +mbchat_SOURCES = mbchat.c + +mbfbgen_SOURCES = mbfbgen.c + +mbstat_SOURCES = mbstat.c mbstat.h + +mbtoberep_SOURCES = mbtoberep.c + +mbuser_SOURCES = mbuser.c mbuser.h + +mbuseradd_SOURCES = mbuseradd.c mbuseradd.h + +mbpasswd_SOURCES = mbpasswd.c commonio.c pwio.c shadowio.c sgetpwent.c \ +xmalloc.c myname.c rad64.c salt.c getdef.c encrypt.c \ +mbpasswd.h commonio.h pwio.h shadowio.h sgetpwent.h \ +xmalloc.h myname.h rad64.h salt.h getdef.h encrypt.h + +mbsebbs_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a ../lib/libmbinet.a +mball_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mblang_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbchat_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbfbgen_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbstat_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbtoberep_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbuser_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 6711 mbsebbs $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mball $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mblang $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbchat $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbfbgen $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbstat $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbtoberep $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbuser $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbuseradd $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbpasswd $(bindir) + diff --git a/mbsebbs/Makefile.in b/mbsebbs/Makefile.in new file mode 100644 index 00000000..5536c14f --- /dev/null +++ b/mbsebbs/Makefile.in @@ -0,0 +1,633 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . +noinst_PROGRAMS = mbsebbs mball mblang mbchat mbfbgen mbstat mbtoberep mbuser mbuseradd mbpasswd + +mbsebbs_SOURCES = bank.c bbslist.c chat.c file.c funcs.c funcs4.c mail.c menu.c misc.c pinfo.c nextuser.c oneline.c page.c pwcheck.c fsedit.c bye.c change.c mbsebbs.c safe.c timeout.c user.c timecheck.c exitinfo.c filesub.c lineedit.c offline.c language.c msgutil.c newuser.c pop3.c email.c bank.h bbslist.h chat.h file.h funcs.h funcs4.h mail.h menu.h misc.h pinfo.h nextuser.h oneline.h page.h pwcheck.h fsedit.h bye.h change.h mbsebbs.h safe.h timeout.h user.h timecheck.h exitinfo.h filesub.h lineedit.h offline.h language.h msgutil.h newuser.h pop3.h email.h statetbl.h + + +mball_SOURCES = mball.c mball.h + +mblang_SOURCES = mblang.c + +mbchat_SOURCES = mbchat.c + +mbfbgen_SOURCES = mbfbgen.c + +mbstat_SOURCES = mbstat.c mbstat.h + +mbtoberep_SOURCES = mbtoberep.c + +mbuser_SOURCES = mbuser.c mbuser.h + +mbuseradd_SOURCES = mbuseradd.c mbuseradd.h + +mbpasswd_SOURCES = mbpasswd.c commonio.c pwio.c shadowio.c sgetpwent.c xmalloc.c myname.c rad64.c salt.c getdef.c encrypt.c mbpasswd.h commonio.h pwio.h shadowio.h sgetpwent.h xmalloc.h myname.h rad64.h salt.h getdef.h encrypt.h + + +mbsebbs_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a ../lib/libmbinet.a +mball_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mblang_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbchat_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbfbgen_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbstat_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbtoberep_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbuser_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbsebbs_OBJECTS = bank.o bbslist.o chat.o file.o funcs.o funcs4.o \ +mail.o menu.o misc.o pinfo.o nextuser.o oneline.o page.o pwcheck.o \ +fsedit.o bye.o change.o mbsebbs.o safe.o timeout.o user.o timecheck.o \ +exitinfo.o filesub.o lineedit.o offline.o language.o msgutil.o \ +newuser.o pop3.o email.o +mbsebbs_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a \ +../lib/libmbinet.a +mbsebbs_LDFLAGS = +mball_OBJECTS = mball.o +mball_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mball_LDFLAGS = +mblang_OBJECTS = mblang.o +mblang_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mblang_LDFLAGS = +mbchat_OBJECTS = mbchat.o +mbchat_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbchat_LDFLAGS = +mbfbgen_OBJECTS = mbfbgen.o +mbfbgen_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbfbgen_LDFLAGS = +mbstat_OBJECTS = mbstat.o +mbstat_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbstat_LDFLAGS = +mbtoberep_OBJECTS = mbtoberep.o +mbtoberep_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbtoberep_LDFLAGS = +mbuser_OBJECTS = mbuser.o +mbuser_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbuser_LDFLAGS = +mbuseradd_OBJECTS = mbuseradd.o +mbuseradd_LDADD = $(LDADD) +mbuseradd_DEPENDENCIES = +mbuseradd_LDFLAGS = +mbpasswd_OBJECTS = mbpasswd.o commonio.o pwio.o shadowio.o sgetpwent.o \ +xmalloc.o myname.o rad64.o salt.o getdef.o encrypt.o +mbpasswd_LDADD = $(LDADD) +mbpasswd_DEPENDENCIES = +mbpasswd_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbsebbs_SOURCES) $(mball_SOURCES) $(mblang_SOURCES) $(mbchat_SOURCES) $(mbfbgen_SOURCES) $(mbstat_SOURCES) $(mbtoberep_SOURCES) $(mbuser_SOURCES) $(mbuseradd_SOURCES) $(mbpasswd_SOURCES) +OBJECTS = $(mbsebbs_OBJECTS) $(mball_OBJECTS) $(mblang_OBJECTS) $(mbchat_OBJECTS) $(mbfbgen_OBJECTS) $(mbstat_OBJECTS) $(mbtoberep_OBJECTS) $(mbuser_OBJECTS) $(mbuseradd_OBJECTS) $(mbpasswd_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbsebbs/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbsebbs: $(mbsebbs_OBJECTS) $(mbsebbs_DEPENDENCIES) + @rm -f mbsebbs + $(LINK) $(mbsebbs_LDFLAGS) $(mbsebbs_OBJECTS) $(mbsebbs_LDADD) $(LIBS) + +mball: $(mball_OBJECTS) $(mball_DEPENDENCIES) + @rm -f mball + $(LINK) $(mball_LDFLAGS) $(mball_OBJECTS) $(mball_LDADD) $(LIBS) + +mblang: $(mblang_OBJECTS) $(mblang_DEPENDENCIES) + @rm -f mblang + $(LINK) $(mblang_LDFLAGS) $(mblang_OBJECTS) $(mblang_LDADD) $(LIBS) + +mbchat: $(mbchat_OBJECTS) $(mbchat_DEPENDENCIES) + @rm -f mbchat + $(LINK) $(mbchat_LDFLAGS) $(mbchat_OBJECTS) $(mbchat_LDADD) $(LIBS) + +mbfbgen: $(mbfbgen_OBJECTS) $(mbfbgen_DEPENDENCIES) + @rm -f mbfbgen + $(LINK) $(mbfbgen_LDFLAGS) $(mbfbgen_OBJECTS) $(mbfbgen_LDADD) $(LIBS) + +mbstat: $(mbstat_OBJECTS) $(mbstat_DEPENDENCIES) + @rm -f mbstat + $(LINK) $(mbstat_LDFLAGS) $(mbstat_OBJECTS) $(mbstat_LDADD) $(LIBS) + +mbtoberep: $(mbtoberep_OBJECTS) $(mbtoberep_DEPENDENCIES) + @rm -f mbtoberep + $(LINK) $(mbtoberep_LDFLAGS) $(mbtoberep_OBJECTS) $(mbtoberep_LDADD) $(LIBS) + +mbuser: $(mbuser_OBJECTS) $(mbuser_DEPENDENCIES) + @rm -f mbuser + $(LINK) $(mbuser_LDFLAGS) $(mbuser_OBJECTS) $(mbuser_LDADD) $(LIBS) + +mbuseradd: $(mbuseradd_OBJECTS) $(mbuseradd_DEPENDENCIES) + @rm -f mbuseradd + $(LINK) $(mbuseradd_LDFLAGS) $(mbuseradd_OBJECTS) $(mbuseradd_LDADD) $(LIBS) + +mbpasswd: $(mbpasswd_OBJECTS) $(mbpasswd_DEPENDENCIES) + @rm -f mbpasswd + $(LINK) $(mbpasswd_LDFLAGS) $(mbpasswd_OBJECTS) $(mbpasswd_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbsebbs + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +bank.o: bank.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h bank.h funcs4.h language.h funcs.h timeout.h \ + timecheck.h exitinfo.h +bbslist.o: bbslist.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/clcomm.h ../lib/common.h bbslist.h \ + funcs.h funcs4.h language.h +bye.o: bye.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h funcs.h language.h bye.h +change.o: change.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h change.h \ + funcs.h funcs4.h language.h misc.h pwcheck.h timeout.h \ + exitinfo.h bye.h +chat.o: chat.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h chat.h funcs.h funcs4.h language.h misc.h \ + exitinfo.h +commonio.o: commonio.c ../config.h commonio.h +email.o: email.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/msgtext.h ../lib/msg.h ../lib/common.h \ + ../lib/clcomm.h ../lib/mbinet.h exitinfo.h language.h mail.h \ + timeout.h msgutil.h funcs4.h email.h +encrypt.o: encrypt.c ../config.h encrypt.h +exitinfo.o: exitinfo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h funcs.h \ + funcs4.h language.h oneline.h misc.h bye.h timeout.h \ + timecheck.h exitinfo.h +file.o: file.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h filesub.h file.h funcs.h funcs4.h language.h \ + misc.h timeout.h exitinfo.h change.h +filesub.o: filesub.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h filesub.h \ + funcs.h language.h funcs4.h misc.h timeout.h exitinfo.h \ + change.h +fsedit.o: fsedit.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/ansi.h ../lib/common.h ../lib/clcomm.h \ + mail.h funcs4.h language.h timeout.h pinfo.h fsedit.h +funcs.o: funcs.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/msgtext.h ../lib/msg.h \ + ../lib/clcomm.h funcs.h language.h funcs4.h oneline.h misc.h \ + bye.h timeout.h timecheck.h exitinfo.h mail.h email.h +funcs4.o: funcs4.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/clcomm.h ../lib/common.h ../lib/msg.h \ + funcs4.h misc.h timeout.h language.h +getdef.o: getdef.c ../config.h getdef.h +language.o: language.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h funcs4.h \ + language.h +lineedit.o: lineedit.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h mail.h \ + funcs4.h language.h timeout.h lineedit.h +mail.o: mail.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/msgtext.h ../lib/clcomm.h ../lib/msg.h mail.h funcs.h \ + funcs4.h language.h misc.h timeout.h oneline.h exitinfo.h \ + lineedit.h fsedit.h filesub.h msgutil.h pop3.h email.h +mball.o: mball.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/mbse.h \ + ../lib/records.h ../lib/common.h ../lib/dbcfg.h ../lib/clcomm.h \ + mball.h +mbchat.o: mbchat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h +mbfbgen.o: mbfbgen.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h +mblang.o: mblang.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h +mbpasswd.o: mbpasswd.c ../config.h encrypt.h rad64.h myname.h xmalloc.h \ + pwio.h shadowio.h mbpasswd.h +mbsebbs.o: mbsebbs.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h ../lib/msg.h \ + mbsebbs.h user.h funcs.h funcs4.h language.h menu.h misc.h \ + bye.h timeout.h +mbstat.o: mbstat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbstat.h +mbtoberep.o: mbtoberep.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h +mbuser.o: mbuser.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbuser.h +mbuseradd.o: mbuseradd.c ../config.h mbuseradd.h +menu.o: menu.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h oneline.h mail.h bbslist.h change.h bank.h \ + chat.h file.h funcs.h funcs4.h misc.h nextuser.h safe.h \ + timeout.h menu.h page.h pinfo.h bye.h timecheck.h exitinfo.h \ + language.h offline.h email.h +misc.o: misc.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h funcs.h funcs4.h language.h misc.h timeout.h \ + exitinfo.h +msgutil.o: msgutil.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h \ + ../lib/msgtext.h ../lib/msg.h oneline.h msgutil.h +myname.o: myname.c ../config.h +newuser.o: newuser.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/clcomm.h ../lib/common.h funcs4.h \ + pwcheck.h newuser.h language.h timeout.h change.h bye.h +nextuser.o: nextuser.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/ansi.h ../lib/clcomm.h ../lib/common.h \ + nextuser.h funcs.h funcs4.h language.h timeout.h +offline.o: offline.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/mbse.h \ + ../lib/records.h ../lib/bluewave.h ../lib/common.h \ + ../lib/clcomm.h ../lib/msgtext.h ../lib/msg.h mail.h funcs.h \ + funcs4.h language.h file.h filesub.h exitinfo.h timeout.h \ + msgutil.h pop3.h offline.h +oneline.o: oneline.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h oneline.h \ + funcs.h funcs4.h language.h +page.o: page.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h funcs.h funcs4.h chat.h page.h timeout.h mail.h \ + language.h +pinfo.o: pinfo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h funcs4.h +pop3.o: pop3.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h ../lib/mbinet.h ../lib/msgtext.h ../lib/msg.h \ + msgutil.h pop3.h +pwcheck.o: pwcheck.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h pwcheck.h \ + funcs4.h timeout.h +pwio.o: pwio.c ../config.h sgetpwent.h commonio.h pwio.h +rad64.o: rad64.c ../config.h rad64.h +safe.o: safe.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h exitinfo.h funcs.h funcs4.h misc.h safe.h \ + timeout.h language.h +salt.o: salt.c ../config.h rad64.h getdef.h +sgetpwent.o: sgetpwent.c ../config.h sgetpwent.h +shadowio.o: shadowio.c ../config.h commonio.h shadowio.h +timecheck.o: timecheck.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/clcomm.h ../lib/common.h timecheck.h \ + funcs.h funcs4.h misc.h bye.h exitinfo.h language.h +timeout.o: timeout.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h ../lib/msg.h \ + timeout.h funcs.h funcs4.h bye.h filesub.h language.h +user.o: user.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h timeout.h user.h pwcheck.h funcs.h funcs4.h \ + misc.h bye.h file.h mail.h change.h menu.h exitinfo.h \ + language.h offline.h statetbl.h email.h newuser.h +xmalloc.o: xmalloc.c ../config.h xmalloc.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 6711 mbsebbs $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mball $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mblang $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbchat $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbfbgen $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbstat $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbtoberep $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbuser $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbuseradd $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbpasswd $(bindir) + +# 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/mbsebbs/bank.c b/mbsebbs/bank.c new file mode 100644 index 00000000..75913214 --- /dev/null +++ b/mbsebbs/bank.c @@ -0,0 +1,576 @@ +/***************************************************************************** + * + * File ..................: bbs/bank.c + * Purpose ...............: Time/Bytes Bank + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "bank.h" +#include "funcs4.h" +#include "language.h" +#include "funcs.h" +#include "timeout.h" +#include "timecheck.h" +#include "exitinfo.h" + + +/* + * internal function prototypes + */ +int BankMenu(void); +void AddAccount(void); +void Deposit(void); +void Withdraw(void); +void DepositTime(void); +void WithdrawTime(void); + +void DepositBytes(void); +void WithdrawBytes(void); + +FILE *pBank; +int usernum = 0; +long bankset; + + + +/* + * Timebank, called from the menu system. + */ +void Bank() +{ + int FoundName = FALSE; + int Loop = TRUE; + char *temp, temp1[81]; + + DisplayFile((char *)"bank"); + temp = calloc(PATH_MAX, sizeof(char)); + + while(Loop) { + FoundName = FALSE; + usernum = 0; + WhosDoingWhat(TIMEBANK); + + sprintf(temp, "%s/etc/bank.data", getenv("MBSE_ROOT")); + if ((pBank = fopen(temp, "r+")) == NULL) { + /* Create a new database */ + pBank = fopen(temp, "a+"); + bankhdr.hdrsize = sizeof(bankhdr); + bankhdr.recsize = sizeof(bank); + fwrite(&bankhdr, sizeof(bankhdr), 1, pBank); + fclose(pBank); + Syslog('-', "Created %s", temp); + AddAccount(); + if ((pBank = fopen(temp, "r+")) == NULL) { + WriteError("Unable to open %s", temp); + free(temp); + return; + } + } + + fread(&bankhdr, sizeof(bankhdr), 1, pBank); + fseek(pBank, bankhdr.hdrsize, 0); + while (fread(&bank, bankhdr.recsize, 1, pBank) == 1) { + if((strcmp(bank.Name, exitinfo.sUserName)) == 0) { + FoundName = TRUE; + break; + } else + usernum++; + } /* End of while */ + + fclose(pBank); + + if(!FoundName) + AddAccount(); + + if ((pBank = fopen(temp, "r+")) == NULL) + AddAccount(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + if (fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fread(&bank, bankhdr.recsize, 1, pBank); + + sprintf(temp1, "%s", (char *) GetDateDMY()); + if ((strcmp(temp1, bank.Date)) != 0) { + bank.TimeWithdraw = 0; + bank.KByteWithdraw = 0; + bank.TimeDeposit = 0; + bank.KByteDeposit = 0; + sprintf(bank.Date, "%s", (char *) GetDateDMY()); + } + + Loop = BankMenu(); + } + free(temp); +} + + + +int BankMenu() +{ + int i; + + clear(); + /* MBSE BBS System Bank */ + language(4, 7, 11); + colour(15, 0); + sLine(); + /* Bank Account: */ + language(3, 0, 12); + poutCR(15, 0, bank.Name); + colour(15, 0); + sLine(); + + /* Time in account */ + language(10, 0, 13); + colour(15, 0); + printf("%d\n", bank.TimeBalance); + + /* Bytes in account */ + language(10, 0, 14); + colour(15, 0); + printf("%d\n", bank.KByteBalance); + + /* Time deposited today */ + language(10, 0, 15); + colour(15, 0); + printf("%d\n", bank.TimeDeposit); + + /* Bytes deposited today */ + language(10, 0, 16); + colour(15, 0); + printf("%d\n", bank.KByteDeposit); + + /* Time withdrawn today */ + language(10, 0, 17); + colour(15, 0); + printf("%d\n", bank.TimeWithdraw); + + /* Bytes withdrawn today */ + language(10, 0, 18); + colour(15, 0); + printf("%d\n", bank.KByteWithdraw); + + colour(15, 0); + sLine(); + TimeCheck(); + /* (D)eposit, (W)ithdraw, (Q)uit */ + language(12, 0, 19); + Enter(2); + + /* Bank > */ + language(15, 0, 20); + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(19, 0)) + Deposit(); + else + if (i == Keystroke(19, 1)) + Withdraw(); + else + if (i == Keystroke(19, 2)) + return FALSE; + + return TRUE; +} + + + +void AddAccount() +{ + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/bank.data", getenv("MBSE_ROOT")); + + if ((pBank = fopen(temp, "a+")) == NULL) + WriteError("Can't open %s for updating", temp); + else { + memset(&bank, 0, sizeof(bank)); + strcpy(bank.Name, exitinfo.sUserName); + sprintf(bank.Date, "%s", (char *) GetDateDMY()); + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + } + free(temp); +} + + + +void Deposit() +{ + int i; + + /* (T)ime, (B)ytes, (Q)uit : */ + language(3, 0, 21); + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(21, 0)) + DepositTime(); + else + if (i == Keystroke(21, 1)) + DepositBytes(); +} + + + +void Withdraw() +{ + int i; + + /* (T)ime, (B)ytes, (Q)uit : */ + language(3, 0, 21); + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(21, 0)) + WithdrawTime(); + else + if (i == Keystroke(21, 1)) + WithdrawBytes(); +} + + + +void DepositTime() +{ + int x; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + fflush(stdin); + + if(exitinfo.iTimeLeft <= 5) { + Enter(2); + /* You must have at least 5 minutes remaining to deposit */ + language(12, 0, 22); + Enter(2); + Pause(); + free(temp); + return; + } + + Enter(1); + /* How much time. Minutes available to you is */ + language(15, 0, 23); + printf("%d: ", exitinfo.iTimeLeft - 5); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) { + free(temp); + return; + } + + x = atoi(temp); + bank.TimeDeposit += x; + bank.TimeBalance += x; + + if(bank.TimeDeposit > CFG.iMaxTimeDeposit) { + colour(10, 0); + Enter(1); + /* You have tried to deposit more than the maximum limit today. */ + language(10, 0, 24); + Enter(1); + + /* Maximum allowed minutes to deposit per day: */ + language(12, 0, 25); + printf("%d.\n\n", CFG.iMaxTimeDeposit); + Pause(); + fclose(pBank); + free(temp); + return; + } + + if(bank.TimeBalance > CFG.iMaxTimeBalance) { + Enter(1); + /* You have exeeded your account balance. */ + language(10, 0, 26); + /* Maximum allowable minutes in bank account is: */ + language(12, 0, 27); + printf("%d\n", CFG.iMaxTimeBalance); + /* You are allowed to deposit: */ + language(14, 0, 28); + printf("%d\n\n", CFG.iMaxTimeBalance - (bank.TimeBalance - x) ); + Pause(); + fclose(pBank); + free(temp); + return; + } + + Time2Go -= (x * 60); + TimeCheck(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + if(fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + + free(temp); +} + + + +void WithdrawTime() +{ + char *temp; + int x; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + + /* How much time. Minutes available to you is */ + Enter(1); + language(15, 0, 23); + printf("%d: ", bank.TimeBalance); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) { + free(temp); + return; + } + + x = atoi(temp); + + bank.TimeWithdraw += x; + bank.TimeBalance -= x; + + if(bank.TimeWithdraw > CFG.iMaxTimeWithdraw) { + Enter(1); + /* You have tried to withdraw more than the maximum limit today. */ + language(10, 0, 29); + /* Maximum allowed to withdraw per day: */ + language(12, 0, 30); + printf("%d.\n\n", CFG.iMaxTimeWithdraw); + Pause(); + fclose(pBank); + free(temp); + return; + } + + if(x > bank.TimeBalance + x) { + Enter(1); + /* You have tried to withdraw more time than is in your bank account. */ + language(10, 0, 31); + /* Current bank balance: */ + language(10, 0, 32); + printf("%d.\n\n", bank.TimeBalance + x); + Pause(); + fclose(pBank); + free(temp); + return; + } + + Time2Go += (x * 60); + TimeCheck(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + + if(fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + free(temp); +} + + + +void DepositBytes() +{ + char *temp; + int x; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + + if(exitinfo.DownloadKToday <= 5) { + Enter(2); + /* You must have at least 5 bytes remaining to deposit */ + language(12, 0, 22); + Enter(2); + Pause(); + free(temp); + return; + } + + Enter(1); + /* Bytes available: */ + language(15, 0, 36); + printf("%lu: ", exitinfo.DownloadKToday); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) { + free(temp); + return; + } + + x = atoi(temp); + bank.KByteDeposit += x; + bank.KByteBalance += x; + + if(bank.KByteDeposit > CFG.iMaxByteDeposit * 1000) { + Enter(1); + /* You have tried to deposit more than the maximum limit today. */ + language(10, 0, 25); + Enter(1); + colour(12, 0); + /* Maximum allowed kilobytes to deposit per day: */ + language(12, 0, 33); + printf("%d.\n\n", CFG.iMaxByteDeposit); + Pause(); + fclose(pBank); + free(temp); + return; + } + + if(bank.KByteBalance > CFG.iMaxByteBalance * 1000) { + Enter(1); + /* You have exeeded your account balance. */ + language(10, 0, 34); + Enter(1); + /* Maximum allowable kilobytes in bank account is: */ + language(12, 0, 35); + printf("%d\n", CFG.iMaxByteBalance); + colour(14, 0); + /* You are allowed to deposit: */ + language(14, 0, 28); + printf("%d\n\n", CFG.iMaxByteBalance - (bank.KByteBalance - x) ); + Pause(); + fclose(pBank); + free(temp); + return; + } + + exitinfo.DownloadKToday -= x; + WriteExitinfo(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + + if(fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + free(temp); +} + + + +void WithdrawBytes() +{ + char *temp; + int x; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + + Enter(1); + /* How many bytes. Bytes available to you is */ + language(15, 0, 36); + printf("%d: ", bank.KByteBalance); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) { + free(temp); + return; + } + + x = atoi(temp); + bank.KByteWithdraw += x; + bank.KByteBalance -= x; + + if(bank.KByteWithdraw > CFG.iMaxByteWithdraw * 1000) { + Enter(1); + /* You have tried to withdraw more than the maximum limit today. */ + language(10, 0, 29); + Enter(1); + colour(12, 0); + /* Maximum allowed to withdraw per day: */ + language(12, 0, 30); + printf("%d bytes.\n\n", CFG.iMaxByteWithdraw); + Pause(); + fclose(pBank); + free(temp); + return; + } + + if(x > bank.KByteBalance + x) { + Enter(1); + /* You have tried to withdraw more time than is in your bank account. */ + language(10, 0, 31); + Enter(1); + colour(12, 0); + /* Current bank balance: */ + language(12, 0, 32); + printf("%d.\n\n", bank.KByteBalance + x); + Pause(); + fclose(pBank); + free(temp); + return; + } + + exitinfo.DownloadKToday += x; + WriteExitinfo(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + + if(fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + free(temp); +} + + diff --git a/mbsebbs/bank.h b/mbsebbs/bank.h new file mode 100644 index 00000000..2239fc91 --- /dev/null +++ b/mbsebbs/bank.h @@ -0,0 +1,7 @@ +#ifndef _BANK_H +#define _BANK_H + +void Bank(void); + +#endif + diff --git a/mbsebbs/bbslist.c b/mbsebbs/bbslist.c new file mode 100644 index 00000000..aaf27517 --- /dev/null +++ b/mbsebbs/bbslist.c @@ -0,0 +1,708 @@ +/***************************************************************************** + * + * File ..................: bbs/bbslist.c + * Purpose ...............: Handle BBS lists + * Last modification date : 28-Jun-2001 + * ToDo ..................: Add use of new fields + * Verify check at logon + * Intro New BBS at logon + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "bbslist.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" + + + +void BBS_Add(void) +{ + FILE *pBBSList; + char *sFileName; + char *temp; + + sFileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSList = fopen(sFileName, "a+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + free(temp); + free(sFileName); + return; + } + + if (ftell(pBBSList) == 0) { + /* + * The file looks new created, add header + */ + bbshdr.hdrsize = sizeof(bbshdr); + bbshdr.recsize = sizeof(bbs); + fwrite(&bbshdr, sizeof(bbshdr), 1, pBBSList); + } + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t\t%c%c", 177, 177); + colour(15, 0); + /* Adding BBS */ + printf(" %s", (char *) Language(300)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 219); + printf("\t\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219); + } else { + printf("\n\t\t\t\t+--------------+\n"); + /* Adding BBS */ + printf("\t\t\t\t| %s |\n", (char *) Language(300)); + printf("\t\t\t\t+--------------+\n\n"); + } + + memset(&bbs, 0, sizeof(bbs)); + + while (TRUE) { + /* BBS Name: */ + pout(15, 0, (char *) Language(301)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.BBSName, 40); + + if((strlen(bbs.BBSName)) > 3) + break; + else { + Enter(1); + pout(12, 0, (char *) Language(302)); + Enter(2); + Pause(); + free(temp); + free(sFileName); + return; + } + } + + while (TRUE) { + /* Phone Number: */ + pout(15, 0, (char *) Language(303)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Phone[0], 20); + + if((strlen(bbs.Phone[0])) > 3) + break; + } + + while (TRUE) { + /* Sysop Name: */ + pout(15, 0, (char *) Language(304)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getname(bbs.Sysop, 35); + + if((strlen(bbs.Sysop)) > 3) + break; + } + + while (TRUE) { + /* BBS Software: */ + pout(15, 0, (char *) Language(305)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Software, 19); + + if((strlen(bbs.Software)) >= 2) + break; + } + + while (TRUE) { + /* Storage (Gigabyte): */ + pout(15, 0, (char *) Language(306)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getnum(temp, 8); + + if ((strlen(temp)) > 0) { + bbs.Storage = atoi(temp); + break; + } + } + + while (TRUE) { + /* Speeds: */ + pout(15, 0, (char *) Language(307)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Speeds[0], 40); + + if((strlen(bbs.Speeds[0])) > 2) + break; + } + + Enter(1); + /* Would you like to add a extended discription? [Y/n]: */ + pout(15, 0, (char *) Language(308)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if ((toupper(temp[0]) == Keystroke(308, 0)) || (strcmp(temp, "") == 0)) { + colour(14, 0); + /* Please a enter discription for */ + printf("\n%s%s (2 Lines)\n", (char *) Language(309), bbs.BBSName); + pout(15, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Desc[0], 71); + pout(15, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Desc[1], 71); + } + + printf("\n"); + Syslog('+', "User added BBS to list"); + + sprintf(bbs.UserName,"%s", exitinfo.sUserName); + sprintf(bbs.DateOfEntry,"%02d-%02d-%04d",l_date->tm_mday,l_date->tm_mon+1,l_date->tm_year+1900); + sprintf(bbs.Verified,"%02d-%02d-%04d",l_date->tm_mday,l_date->tm_mon+1,l_date->tm_year+1900); + bbs.Available = TRUE; + + fwrite(&bbs, sizeof(bbs), 1, pBBSList); + fclose(pBBSList); + free(temp); + free(sFileName); +} + + + +void BBS_List(void) +{ + FILE *pBBSList; + int recno = 0; + char *sFileName; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSList = fopen(sFileName, "r+")) == NULL) { + WriteError("BBSList: Can't open file: %s", sFileName); + free(sFileName); + return; + } + + fread(&bbshdr, sizeof(bbshdr), 1, pBBSList); + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t\t%c%c", 177, 177); + colour(15, 0); + printf(" %s", (char *) Language(310)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 219); + printf("\t\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219); + } else { + printf("\n\t\t\t\t+---------------+\n"); + /* BBS Listing */ + printf("\t\t\t\t| %s |\n", (char *) Language(310)); + printf("\t\t\t\t+---------------+\n\n"); + } + + /* # BBS Name Number Software Gigabyte Speed*/ + colour(15, 0); + printf("%s\n", Language(311)); + colour(12, 0); + sLine(); + + while (fread(&bbs, bbshdr.recsize, 1, pBBSList) == 1) { + if ((bbs.Available)) { + colour(15, 0); + printf("%-5d", recno); + + colour(10, 0); + bbs.BBSName[22] = '\0'; + printf("%-23s", bbs.BBSName); + + colour(11, 0); + bbs.Phone[0][14] = '\0'; + printf("%-15s", bbs.Phone[0]); + + colour(14, 0); + bbs.Software[15] = '\0'; + printf("%-16s", bbs.Software); + + colour(13, 0); + printf("%-11d", bbs.Storage); + + colour(8, 0); + bbs.Speeds[0][9] = '\0'; + printf("%s\n", bbs.Speeds[0]); + } + recno++; + } + colour(12, 0); + sLine(); + fclose(pBBSList); + free(sFileName); + Pause(); +} + + + +void BBS_Search(void) +{ + FILE *pBBSList; + int recno = 0; + int iFoundBBS = FALSE; + char *sFileName; + char *Name; + char *sTemp; + long offset; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSList = fopen(sFileName, "r+")) == NULL) { + WriteError("BBSList: Can't open file: %s", sFileName); + free(sFileName); + return; + } + + fread(&bbshdr, sizeof(bbshdr), 1, pBBSList); + Name = calloc(30, sizeof(char)); + sTemp = calloc(81, sizeof(char)); + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t\t%c%c ", 177, 177); + colour(15, 0); + printf("%s", (char *) Language(312)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,219); + printf("\t\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220,219); + } else { + printf("\n\t\t\t\t+--------------------+\n"); + /* Search for a BBS */ + printf("\t\t\t\t | %s |\n", (char *) Language(312)); + printf("\t\t\t\t +--------------------+\n\n"); + } + + while (TRUE) { + /* Please enter 3 letters of BBS to search for: */ + pout(15, 0, (char *) Language(313)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(Name, 29); + + if((strcmp(Name,"")) == 0) { + fflush(stdin); + fclose(pBBSList); + free(sFileName); + free(sTemp); + free(Name); + return; + } + + if((strlen(Name)) > 2) + break; + else { + Enter(1); + /* I need at least 3 letters ...*/ + pout(12, 0, (char *) Language(314)); + Enter(2); + } + } + + while (fread(&bbs, bbshdr.recsize, 1, pBBSList) == 1) { + if((strstr(tl(bbs.BBSName), tl(Name)) != NULL)) { + tlf(bbs.BBSName); + colour(14, 0); + /* BBS Name: */ + printf("\n%s%s\n\n", (char *) Language(301), bbs.BBSName); + /* View this BBS? [Y/n]: */ + pout(15, 0, (char *) Language(315)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(sTemp, 80); + if ((toupper(sTemp[0]) == Keystroke(315, 0)) || (strcmp(sTemp,"") == 0)) { + iFoundBBS = TRUE; + break; + } else + recno++; + } else { + recno++; + } + } + + if(!iFoundBBS) { + Enter(1); + /* Could not find the BBS Listed ... */ + pout(12, 0, (char *) Language(316)); + Enter(2); + fclose(pBBSList); + Pause(); + free(sFileName); + free(Name); + free(sTemp); + return; + } + + offset = bbshdr.hdrsize + (recno * bbshdr.recsize); + if(fseek(pBBSList, offset, 0) != 0) + WriteError("Can't move pointer there. %s",sFileName); + + fread(&bbs, bbshdr.recsize, 1, pBBSList); + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t%c%c ", 177, 177); + colour(15, 0); + /* Search for a BBS */ + printf("%s", (char *) Language(312)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,219); + printf("\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220,219); + } else { + printf("\n\t\t\t+--------------------+\n"); + /* Search for a BBS */ + printf("\t\t\t| %s |\n", (char *) Language(312)); + printf("\t\t\t+--------------------+\n\n"); + } + + /* # BBS Name Number Software Storage Speed */ + colour(15, 0); + printf("%s\n", Language(311)); + + colour(12, 0); + sLine(); + + colour(15, 0); + printf("%-5d", recno); + + colour(10, 0); + bbs.BBSName[22] = '\0'; + printf("%-23s", bbs.BBSName); + + colour(11, 0); + bbs.Phone[0][14] = '\0'; + printf("%-15s", bbs.Phone[0]); + + colour(14, 0); + bbs.Software[15] = '\0'; + printf("%-16s", bbs.Software); + + colour(13, 0); + printf("%-11d", bbs.Storage); + + colour(8, 0); + bbs.Speeds[0][9] = '\0'; + printf("%s\n", bbs.Speeds[0]); + + colour(12, 0); + sLine(); + fclose(pBBSList); + Pause(); + free(sFileName); + free(sTemp); + free(Name); +} + + + +void BBS_Show(void) +{ + FILE *pBBSList; + int recno = 0; + int nrecno = 0; + long int offset; + char *sFileName; + char srecno[10]; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSList = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + free(sFileName); + return; + } + free(sFileName); + fread(&bbshdr, sizeof(bbshdr), 1, pBBSList); + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t%c%c ", 177, 177); + colour(15, 0); + /* Show a BBS */ + printf("%s", (char *) Language(317)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177,177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 219); + printf("\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220,219); + } else { + printf("\n\t\t\t+--------------+\n"); + /* Show a BBS */ + printf("\t\t\t| %s |\n", (char *) Language(317)); + printf("\t\t\t+--------------+\n\n"); + } + + Enter(1); + /* Please enter number to list: */ + pout(15, 0, (char *) Language(318)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(srecno, 9); + + if((strcmp(srecno,"")) == 0) + return; + + recno = atoi(srecno); + nrecno = recno; + recno = 0; + + while (fread(&bbs, bbshdr.recsize, 1, pBBSList) == 1) + recno++; + + if(nrecno >= recno) { + Enter(1); + /* Record does not exist */ + pout(12, 0, (char *) Language(319)); + Enter(2); + fclose(pBBSList); + Pause(); + return; + } else { + offset = bbshdr.hdrsize + (nrecno * bbshdr.recsize); + if(fseek(pBBSList, offset, 0) != 0) + WriteError("Can't move pointer there. %s",sFileName); + + fread(&bbs, bbshdr.recsize, 1, pBBSList); + + colour(12, 0); + sLine(); + + /* Record : */ + pout(15, 0, (char *) Language(320)); + colour(10, 0); + printf("%d\n", nrecno); + + /* BBS Name : */ + pout(15, 0, (char *) Language(321)); + colour(10, 0); + printf("%s\n", bbs.BBSName); + + /* Number : */ + pout(15, 0, (char *) Language(322)); + colour(10, 0); + printf("%s\n", bbs.Phone[0]); + + /* Software : */ + pout(15, 0, (char *) Language(323)); + colour(10, 0); + printf("%s\n", bbs.Software); + + /* Storage : */ + pout(15, 0, (char *) Language(324)); + colour(10, 0); + printf("%d\n", bbs.Storage); + + /* Speeds : */ + pout(15, 0, (char *) Language(325)); + colour(10, 0); + printf("%s\n", bbs.Speeds[0]); + + /* Sysop Name : */ + pout(15, 0, (char *) Language(326)); + colour(10, 0); + printf("%s\n", bbs.Sysop); + + if((strcmp(bbs.Desc[0],"")) != 0) { + pout(15, 0, (char *)" Description : "); + colour(13, 0); + bbs.Desc[0][62] = '\0'; + printf("%s\n", bbs.Desc[0]); + } + if((strcmp(bbs.Desc[1],"")) != 0) { + pout(15, 0, (char *)" : "); + colour(13, 0); + bbs.Desc[1][62] = '\0'; + printf("%s\n", bbs.Desc[1]); + } + + colour(12, 0); + sLine(); + + if((SYSOP == TRUE) || (exitinfo.Security.level >= CFG.sysop_access)) { + pout(15, 0, (char *)"Sysop extra information\n"); + colour(12, 0); + sLine(); + + /* Available : */ + pout(15, 0, (char *) Language(327)); + colour(10, 0); + printf("%d\n", bbs.Available); + + /* Date of Entry : */ + pout(15, 0, (char *) Language(328)); + colour(10, 0); + printf("%s\n", bbs.DateOfEntry); + + /* Entry Name : */ + pout(15, 0, (char *) Language(329)); + colour(10, 0); + printf("%s\n", bbs.UserName); + + colour(12, 0); + sLine(); + } + Pause(); + } + fclose(pBBSList); +} + + + +void BBS_Delete(void) +{ + FILE *pBBSLine; + int recno = 0; + long int offset; + int nrecno = 0; + char srecno[7]; + char *sFileName; + char stemp[50]; + char sUser[35]; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSLine = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + free(sFileName); + return; + } + free(sFileName); + fread(&bbshdr, sizeof(bbshdr),1 , pBBSLine); + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t\t%c%c", 177, 177); + colour(15, 0); + /* Delete BBS */ + printf(" %s", (char *) Language(330)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 219); + printf("\t\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219); + } else { + printf("\n\t\t\t\t+--------------+\n"); + /* Delete BBS */ + printf("\t\t\t\t| %s |\n", (char *) Language(330)); + printf("\t\t\t\t+--------------+\n\n"); + } + + Enter(1); + /* Please enter number to delete: */ + pout(15, 0, (char *) Language(331)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(srecno, 9); + + if((strcmp(srecno,"")) == 0) + return; + + recno = atoi(srecno); + nrecno = recno; + recno = 0; + + while (fread(&bbs, bbshdr.recsize, 1, pBBSLine) == 1) + recno++; + + if(nrecno >= recno) { + Enter(1); + /* Record does not exist */ + pout(12, 0, (char *) Language(319)); + Enter(2); + fclose(pBBSLine); + Pause(); + return; + } else { + offset = bbshdr.hdrsize + (nrecno * bbshdr.recsize); + if (fseek(pBBSLine, offset, 0) != 0) + WriteError("Can't move pointer there. %s",sFileName); + + fread(&bbs, sizeof(bbs), 1, pBBSLine); + + /* Convert Record Int to string, so we can print to logfiles */ + sprintf(stemp,"%d", nrecno); + + /* Print UserName to String, so we can compare for deletion */ + sprintf(sUser,"%s", exitinfo.sUserName); + + if((strcmp(sUser, bbs.UserName)) != 0) { + if((!SYSOP) && (exitinfo.Security.level < CFG.sysop_access)) { + /* Record */ /* does not belong to you.*/ + printf("\n%s%s %s\n\n", (char *) Language(332), stemp, (char *) Language(333)); + Syslog('!', "User tried to delete somebody else's bbslist record: %s", stemp); + return; + } + } + + if ((bbs.Available == FALSE)) { + colour(12, 0); + /* Record */ + printf("\n%s%d %s\n\n", (char *) Language(332), nrecno, (char *) Language(334)); + Syslog('!', "User tried to mark an already marked bbslist record: %s", stemp); + } else { + bbs.Available = FALSE; + colour(10, 0); + /* Record: */ + printf("\n%s%d %s\n\n", (char *) Language(332), nrecno, (char *) Language(335)); + Syslog('+', "User marked bbslist record for deletion: %s", stemp); + colour(15, 2); + /* The Sysop will purge the list once he has *//* seen you have marked a record for deletion. */ + printf("%s\n%s\n\n", (char *) Language(336), (char *) Language(337)); + Pause(); + } + + offset = bbshdr.hdrsize + (nrecno * bbshdr.recsize); + if(fseek(pBBSLine, offset, 0) != 0) + WriteError("Can't move pointer there. %s",sFileName); + fwrite(&bbs, sizeof(bbs), 1, pBBSLine); + } + + fclose(pBBSLine); +} + + diff --git a/mbsebbs/bbslist.h b/mbsebbs/bbslist.h new file mode 100644 index 00000000..fe80e356 --- /dev/null +++ b/mbsebbs/bbslist.h @@ -0,0 +1,11 @@ +#ifndef _BBSLIST_H +#define _BBSLIST_H + +void BBS_Add(void); +void BBS_List(void); +void BBS_Show(void); +void BBS_Delete(void); +void BBS_Search(void); + +#endif + diff --git a/mbsebbs/bye.c b/mbsebbs/bye.c new file mode 100644 index 00000000..7df8f496 --- /dev/null +++ b/mbsebbs/bye.c @@ -0,0 +1,164 @@ +/***************************************************************************** + * + * File ..................: bbs/bye.c + * Purpose ...............: Hangup functions + * Last modification date : 27-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "funcs.h" +#include "language.h" +#include "bye.h" + + +extern pid_t mypid; +extern time_t t_start; +int do_mailout = FALSE; + + +void Good_Bye(int onsig) +{ + FILE *pUsrConfig, *pExitinfo; + char *temp; + long offset; + time_t t_end; + + IsDoing("Hangup"); + temp = calloc(PATH_MAX, sizeof(char)); + Syslog('+', "Good_Bye()"); + + if (onsig != SIGHUP) + DisplayFile((char *)"goodbye"); + + if (do_mailout) + CreateSema((char *)"mailout"); + + + /* + * Update the users database record. + */ + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp,"r+b")) != NULL) { + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + if ((pExitinfo = fopen(temp,"rb")) != NULL) { + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + offset = usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize); + + fread(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + + usrconfig = exitinfo; + fclose(pExitinfo); + + usrconfig.iLastFileArea = iAreaNumber; + if (!iAreaNumber) + WriteError("Setting filearea to zero"); + usrconfig.iHangUps++; + + /* If time expired, do not say say successful logoff */ + if(!iExpired) + Syslog('+', "User successfully logged off BBS"); + + usrconfig.iLastMsgArea = iMsgAreaNumber; + + offset = usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize); + if(fseek(pUsrConfig, offset, 0) != 0) { + WriteError("Can't move pointer in file %s", temp); + ExitClient(1); + } + + fwrite(&usrconfig, sizeof(usrconfig), 1, pUsrConfig); + fclose(pUsrConfig); + } + } + + time(&t_end); + Syslog(' ', "MBSEBBS finished in %s", t_elapsed(t_start, t_end)); + + /* + * Start shutting down this session + */ + socket_shutdown(mypid); + sprintf(temp, "%s/tmp/mbsebbs%d", getenv("MBSE_ROOT"), getpid()); + unlink(temp); + + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + unlink(temp); + free(temp); + unlink("taglist"); + + /* + * Flush all data to the user, wait 5 seconds to + * be sure the user received all data, this program + * and parent are also finished. + */ + colour(7, 0); + fflush(stdout); + fflush(stdin); + sleep(5); + + Unsetraw(); + Free_Language(); + free(pTTY); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(onsig); +} + + + +void Quick_Bye(int onsig) +{ + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + Syslog('+', "Quick_Bye"); + socket_shutdown(mypid); + sprintf(temp, "%s/tmp/mbsebbs%d", getenv("MBSE_ROOT"), getpid()); + unlink(temp); + free(temp); + + colour(7, 0); + fflush(stdout); + fflush(stdin); + sleep(3); + + Free_Language(); + free(pTTY); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(0); +} + + + diff --git a/mbsebbs/bye.h b/mbsebbs/bye.h new file mode 100644 index 00000000..816a0cf6 --- /dev/null +++ b/mbsebbs/bye.h @@ -0,0 +1,8 @@ +#ifndef _BYE_H +#define _BYE_H + +void Quick_Bye(int); +void Good_Bye(int); + +#endif + diff --git a/mbsebbs/change.c b/mbsebbs/change.c new file mode 100644 index 00000000..b7886d9b --- /dev/null +++ b/mbsebbs/change.c @@ -0,0 +1,817 @@ +/***************************************************************************** + * + * File ..................: bbs/change.c + * Purpose ...............: Change user settings + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "change.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "pwcheck.h" +#include "timeout.h" +#include "exitinfo.h" +#include "bye.h" + + +int Chg_Language(int NewMode) +{ + FILE *pLang; + int iLang, iFoundLang = FALSE; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + if (!NewMode) + ReadExitinfo(); + + while(TRUE) { + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + if(( pLang = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + printf("\nFATAL: Can't open language file\n\n"); + Pause(); + free(temp); + Quick_Bye(0); + } + fread(&langhdr, sizeof(langhdr), 1, pLang); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Select your preferred language */ + printf("\n%s\n\n", (char *) Language(378)); + + iLang = 6; + colour(9,0); + while (fread(&lang, langhdr.recsize, 1, pLang) == 1) + if (lang.Available) { + colour(13, 0); + printf("(%s)", lang.LangKey); + colour(8,0); + printf(" %c ", 46); + colour(3,0); + printf("%-29s ", lang.Name); + + iLang++; + if ((iLang % 2) == 0) + printf("\n"); + } + Enter(1); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Select language: */ + printf("\n%s", (char *) Language(379)); + + fflush(stdout); + alarm_on(); + iLang = toupper(Getone()); + + printf("%c", iLang); + + fseek(pLang, langhdr.hdrsize, 0); + + while (fread(&lang, langhdr.recsize, 1, pLang) == 1) { + strcpy(lang.LangKey,tu(lang.LangKey)); + if ((lang.LangKey[0] == iLang) && (lang.Available)) { + strcpy(CFG.current_language, lang.Filename); + iFoundLang = TRUE; + break; + } + } + + fclose(pLang); + + if(!iFoundLang) { + Enter(2); + /* Invalid selection, please try again! */ + pout(10, 0, (char *) Language(265)); + Enter(2); + } else { + exitinfo.iLanguage = iLang; + strcpy(CFG.current_language, lang.Filename); + Free_Language(); + InitLanguage(); + + colour(10, 0); + /* Language now set to" */ + printf("\n\n%s%s\n\n", (char *) Language(380), lang.Name); + + if (!NewMode) { + Syslog('+', "Changed language to %s", lang.Name); + WriteExitinfo(); + Pause(); + } + break; + } + } + + free(temp); + Enter(1); + return iLang; +} + + + +void Chg_Password() +{ + unsigned long crc, crctmp; + char *temp1, *temp2; + + temp1 = calloc(PATH_MAX, sizeof(char)); + temp2 = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + DisplayFile((char *)"password"); + + Enter(1); + /* Old password: */ + language(15, 0, 120); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + Getpass(temp1); + crctmp = StringCRC32(tu(temp1)); + + if (exitinfo.iPassword == crctmp) { + while (TRUE) { + Enter(1); + /* New password: */ + language(9, 0, 121); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + Getpass(temp1); + if((strlen(temp1)) >= CFG.password_length) { + Enter(1); + /* Confirm new password: */ + language(9, 0, 122); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getpass(temp2); + if(( strcmp(temp1,temp2)) != 0) { + /* Passwords do not match! */ + Enter(2); + language(12, 0, 123); + Enter(1); + } else { + fflush(stdout); + fflush(stdin); + crc = StringCRC32(tu(temp1)); + break; + } + } else { + colour(12, 0); + /* Your password must contain at least %d characters! Try again.*/ + printf("\n%s%d %s\n\n", (char *) Language(42), CFG.password_length, (char *) Language(43)); + } + } + + Syslog('+', "%s/bin/mbpasswd -n %s ******", getenv("MBSE_ROOT"), exitinfo.Name); + sprintf(temp1, "%s/bin/mbpasswd -n %s %s", getenv("MBSE_ROOT"), exitinfo.Name, temp2); + if (system(temp1) != 0) { + WriteError("Failed to set new Unix password"); + } else { + exitinfo.iPassword = crc; + memset(&exitinfo.Password, 0, sizeof(exitinfo.Password)); + sprintf(exitinfo.Password, "%s", temp2); + Enter(1); + /* Password Change Successful */ + language(10, 0, 124); + Syslog('+', "User changed his password"); + WriteExitinfo(); + } + } else { + Enter(1); + /* Old password incorrect! */ + language(12, 0, 125); + } + + free(temp1); + free(temp2); + Enter(2); + Pause(); +} + + + +/* + * Function will allow a user to change his handle + */ +void Chg_Handle() +{ + char *Handle, *temp; + + Handle = calloc(81, sizeof(char)); + temp = calloc(81, sizeof(char)); + + ReadExitinfo(); + Syslog('+', "Old handle \"%s\"", exitinfo.sHandle); + + while (TRUE) { + Enter(1); + /* Enter a handle (Enter to Quit): */ + pout(9, 0, (char *) Language(412)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getname(temp, 34); + + if((strcmp(temp, "")) == 0) { + free(Handle); + free(temp); + return; + } + + strcpy(Handle, tl(temp)); + + if (CheckHandle(Handle)) + pout(12, 0, (char *)"\nThat handle is already been used\n"); + else + if (CheckName(Handle)) + pout(12, 0, (char *)"\nThat name is already been used\n"); + else + if((strcmp(Handle, "sysop")) == 0) + pout(12, 0, (char *)"\nYou cannot use Sysop as a handle\n"); + else { + if(strcmp(temp, "") != 0) { + Setup(exitinfo.sHandle, temp); + pout(10, 0, (char *)"\nHandle Changed!\n\n"); + Syslog('+', "New handle \"%s\"", exitinfo.sHandle); + break; + } + } + } + + WriteExitinfo(); + free(temp); + free(Handle); +} + + + +/* + * Toggle hotkeys + */ +void Chg_Hotkeys() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.HotKeys) { + exitinfo.HotKeys = FALSE; + /* Hotkeys are now OFF */ + pout(10, 0, (char *) Language(146)); + } else { + exitinfo.HotKeys = TRUE; + /* Hotkeys are now ON */ + pout(10, 0, (char *) Language(145)); + } + + Enter(2); + sleep(2); + Syslog('+', "Hotkeys changed to %s", exitinfo.HotKeys?"True":"False"); + WriteExitinfo(); +} + + + +/* + * Toggle Mail Check + */ +void Chg_MailCheck() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.MailScan) { + exitinfo.MailScan = FALSE; + /* New Mail check is now OFF */ + pout(10, 0, (char *) Language(367)); + } else { + exitinfo.MailScan = TRUE; + /* New Mail check is now ON */ + pout(10, 0, (char *) Language(366)); + } + + Enter(2); + sleep(2); + Syslog('+', "New Mail Check changed to %s", exitinfo.MailScan ?"True":"False"); + WriteExitinfo(); +} + + + +/* + * Toggle New Files Check + */ +void Chg_FileCheck() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.ieFILE) { + exitinfo.ieFILE = FALSE; + /* New Files check is now OFF */ + pout(10, 0, (char *) Language(371)); + } else { + exitinfo.ieFILE = TRUE; + /* New Files check is now ON */ + pout(10, 0, (char *) Language(370)); + } + + Enter(2); + sleep(2); + Syslog('+', "Check New Files changed to %s", exitinfo.ieFILE ?"True":"False"); + WriteExitinfo(); +} + + + +/* + * Toggle Fullscreen Editor + */ +void Chg_FsMsged() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.FsMsged) { + exitinfo.FsMsged = FALSE; + /* Fullscreen Editor is now OFF */ + pout(10, 0, (char *) Language(373)); + } else { + exitinfo.FsMsged = TRUE; + /* Fullscreen Editor is now ON */ + pout(10, 0, (char *) Language(372)); + } + + Enter(2); + sleep(2); + Syslog('+', "Fullscreen Editor changed to %s", exitinfo.FsMsged ?"True":"False"); + WriteExitinfo(); +} + + + +/* + * Function to toggle DoNotDisturb Flag + */ +void Chg_Disturb() +{ + ReadExitinfo(); + colour(10, 0); + + if(exitinfo.DoNotDisturb) { + exitinfo.DoNotDisturb = FALSE; + /* Do not disturb turned OFF */ + printf("\n%s\n", (char *) Language(416)); + } else { + exitinfo.DoNotDisturb = TRUE; + /* Do not disturb turned ON */ + printf("\n%s\n", (char *) Language(417)); + } + + Syslog('+', "Do not disturb now %s", exitinfo.DoNotDisturb?"True":"False"); + UserSilent(exitinfo.DoNotDisturb); + sleep(2); + WriteExitinfo(); +} + + + +void Chg_Location() +{ + char temp[81]; + + ReadExitinfo(); + Syslog('+', "Old location \"%s\"", exitinfo.sLocation); + + while (TRUE) { + /* Old Location: */ + Enter(1); + /* Old location: */ + pout(15, 0, (char *) Language(73)); + colour(9, 0); + printf("%s\n", exitinfo.sLocation); + Enter(1); + /* Please enter your location: */ + pout(14, 0, (char *) Language(49)); + + if(CFG.iCapLocation) { + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetnameNE(temp, 24); + } else { + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + } + + if((strcmp(temp, "")) == 0) + break; + + if(( strlen(temp)) < CFG.CityLen) { + Enter(1); + /* Please enter a longer location (min */ + colour(12, 0); + printf("%s%d)", (char *) Language(74), CFG.CityLen); + Enter(1); + } else { + Setup(exitinfo.sLocation,temp); + break; + } + } + + Syslog('+', "New location \"%s\"", exitinfo.sLocation); + WriteExitinfo(); +} + + + +/* + * Toggle Graphics + */ +void Chg_Graphics() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.GraphMode) { + exitinfo.GraphMode = FALSE; + /* Ansi Mode turned OFF */ + pout(15, 0, (char *) Language(76)); + } else { + exitinfo.GraphMode = TRUE; + /* Ansi Mode turned ON */ + pout(15, 0, (char *) Language(75)); + } + + Syslog('+', "Graphics mode now %s", exitinfo.GraphMode?"On":"Off"); + Enter(2); + TermInit(exitinfo.GraphMode); + WriteExitinfo(); + sleep(2); +} + + + +void Chg_VoicePhone() +{ + char temp[81]; + + ReadExitinfo(); + Syslog('+', "Old voice phone \"%s\"", exitinfo.sVoicePhone); + + while (TRUE) { + Enter(1); + /* Please enter you Voice Number */ + pout(10, 0, (char *) Language(45)); + Enter(1); + pout(10, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetPhone(temp, 16); + + if (strlen(temp) < 6) { + Enter(1); + /* Please enter a proper phone number */ + pout(12, 0, (char *) Language(47)); + Enter(1); + } else { + strcpy(exitinfo.sVoicePhone, temp); + break; + } + } + + Syslog('+', "New voice phone \"%s\"", exitinfo.sVoicePhone); + WriteExitinfo(); +} + + + +void Chg_DataPhone() +{ + char temp[81]; + + ReadExitinfo(); + Syslog('+', "Old data phone \"%s\"", exitinfo.sDataPhone); + + while (1) { + Enter(1); + /* Please enter you Data Number */ + pout(10, 0, (char *) Language(48)); + Enter(1); + pout(10, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + GetPhone(temp, 16); + + if( strlen(temp) < 6) { + Enter(1); + /* Please enter a proper phone number */ + pout(12, 0, (char *) Language(47)); + Enter(1); + } else { + strcpy(exitinfo.sDataPhone, temp); + break; + } + } + + Syslog('+', "New data phone \"%s\"", exitinfo.sDataPhone); + WriteExitinfo(); +} + + + +void Chg_News() +{ + ReadExitinfo(); + + if (exitinfo.ieNEWS) { + exitinfo.ieNEWS = FALSE; + /* News bulletins turned OFF */ + printf("\n\n%s\n\n", (char *) Language(79)); + } else { + exitinfo.ieNEWS = TRUE; + /* News bulletins turned ON */ + printf("\n\n%s\n\n", (char *) Language(78)); + } + + Syslog('+', "News bullentins now %s", exitinfo.ieNEWS?"True":"False"); + sleep(2); + WriteExitinfo(); +} + + + +void Chg_ScreenLen() +{ + char *temp; + + ReadExitinfo(); + temp = calloc(81, sizeof(char)); + Syslog('+', "Old screenlen %d", exitinfo.iScreenLen); + fflush(stdin); + + Enter(1); + /* Please enter your Screen Length? [24]: */ + pout(13, 0, (char *) Language(64)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getnum(temp, 2); + + if((strcmp(temp, "")) == 0) { + exitinfo.iScreenLen = 24; + printf("\n%s\n\n", (char *) Language(80)); + } else { + exitinfo.iScreenLen = atoi(temp); + printf("\n%s%d\n\n", (char *) Language(81), exitinfo.iScreenLen); + } + + Syslog('+', "New screenlen %d", exitinfo.iScreenLen); + WriteExitinfo(); + Pause(); + free(temp); +} + + + +/* + * Check users Date of Birth, if it is ok, we calculate his age. + */ +int Test_DOB(char *DOB) +{ + int tyear, year, month, day; + char temp[40], temp1[40]; + + /* First check length of string */ + if (strlen(DOB) != 10) { + Syslog('!', "Date format length %d characters", strlen(DOB)); + /* Please enter the correct date format */ + language(14, 0, 83); + return FALSE; + } + /* + * Split the date into pieces + */ + strcpy(temp1, DOB); + strcpy(temp, strtok(temp1, "-")); + day = atoi(temp); + strcpy(temp, strtok(NULL, "-")); + month = atoi(temp); + strcpy(temp, strtok(NULL, "")); + year = atoi(temp); + tyear = l_date->tm_year + 1900; + + if (((tyear - year) < 10) || ((tyear - year) > 95)) { + Syslog('!', "DOB: Year error: %d", tyear - year); + return FALSE; + } + if ((month < 1) || (month > 12)) { + Syslog('!', "DOB: Month error: %d", month); + return FALSE; + } + if ((day < 1) || (day > 31)) { + Syslog('!', "DOB: Day error: %d", day); + return FALSE; + } + + UserAge = tyear - year; + if ((l_date->tm_mon + 1) < month) + UserAge--; + if (((l_date->tm_mon + 1) == month) && (l_date->tm_mday < day)) + UserAge--; + Syslog('B', "DOB: Users age %d year", UserAge); + return TRUE; +} + + + +void Chg_DOB() +{ + char *temp; + + temp = calloc(81, sizeof(char)); + + ReadExitinfo(); + Syslog('+', "Old DOB %s", exitinfo.sDateOfBirth); + + while (TRUE) { + Enter(1); + /* Please enter your Date of Birth DD-MM-YYYY: */ + pout(3, 0, (char *) Language(56)); + colour(CFG.InputColourF, CFG.InputColourB); + GetDate(temp, 10); + if (Test_DOB(temp)) { + Setup(exitinfo.sDateOfBirth, temp); + break; + } + } + + Syslog('+', "New DOB %s", exitinfo.sDateOfBirth); + WriteExitinfo(); + free(temp); +} + + + + +/* + * Change default protocol. + */ +void Chg_Protocol() +{ + FILE *pProtConfig; + int iProt, iFoundProt = FALSE; + int precno = 0; + char *temp; + char Prot[2]; + + temp = calloc(PATH_MAX, sizeof(char)); + ReadExitinfo(); + Syslog('+', "Old protocol %s", sProtName); + + while(TRUE) { + sprintf(temp, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + + if ((pProtConfig = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + /* Protocol: Can't open protocol file. */ + printf("\n%s\n\n", (char *) Language(262)); + Pause(); + free(temp); + fclose(pProtConfig); + return; + } + fread(&PROThdr, sizeof(PROThdr), 1, pProtConfig); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Select your preferred protocol */ + printf("\n%s\n\n", (char *) Language(263)); + + colour(9,0); + while (fread(&PROT, PROThdr.recsize, 1, pProtConfig) == 1) + if (PROT.Available && Access(exitinfo.Security, PROT.Level)) + printf("(%s) %-20s Efficiency %3d %%\n", PROT.ProtKey, PROT.ProtName, PROT.Efficiency); + + colour(CFG.HiliteF, CFG.HiliteB); + printf("\n%s", (char *) Language(264)); + + fflush(stdout); + alarm_on(); + iProt = toupper(Getone()); + + printf("%c", iProt); + sprintf(Prot, "%c", iProt); + + fseek(pProtConfig, PROThdr.hdrsize, 0); + while (fread(&PROT, PROThdr.recsize, 1, pProtConfig) == 1) { + if ((strncmp(PROT.ProtKey, Prot, 1) == 0) && + PROT.Available && Access(exitinfo.Security, PROT.Level)) { + strcpy(sProtName, PROT.ProtName); + strcpy(sProtUp, PROT.ProtUp); + strcpy(sProtDn, PROT.ProtDn); + strcpy(sProtAdvice, PROT.Advice); + uProtBatch = PROT.Batch; + uProtBidir = PROT.Bidir; + iProtEfficiency = PROT.Efficiency; + iFoundProt = TRUE; + } else + precno++; + } + + fclose(pProtConfig); + + if (iProt == 13) { + free(temp); + return; + } else + if (!iFoundProt) { + Enter(2); + pout(10, 0, (char *) Language(265)); + Enter(2); + /* Loop for new attempt */ + } else { + Setup(exitinfo.sProtocol, sProtName); + colour(10,0); + /* Protocol now set to: */ + printf("\n\n%s%s\n\n", (char *) Language(266), sProtName); + Pause(); + break; + } + } + + Syslog('+', "New protocol %s", sProtName); + WriteExitinfo(); + free(temp); +} + + + +void Set_Protocol(char *Protocol) +{ + FILE *pProtConfig; + int precno = 0; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + + if(( pProtConfig = fopen(temp, "rb")) == NULL) { + WriteError("$Can't open %s", temp); + /* Protocol: Can't open protocol file. */ + printf("\n%s\n\n", (char *) Language(262)); + Pause(); + free(temp); + return; + } + + fread(&PROThdr, sizeof(PROThdr), 1, pProtConfig); + + while (fread(&PROT, PROThdr.recsize, 1, pProtConfig) == 1) { + if ((strcmp(PROT.ProtName, Protocol)) == 0) { + tlf(sProtName); + strcpy(sProtName, PROT.ProtName); + strcpy(sProtUp, PROT.ProtUp); + strcpy(sProtDn, PROT.ProtDn); + strcpy(sProtAdvice, PROT.Advice); + uProtBatch = PROT.Batch; + uProtBidir = PROT.Bidir; + iProtEfficiency = PROT.Efficiency; + } else + precno++; + } + + free(temp); + fclose(pProtConfig); +} + + + diff --git a/mbsebbs/change.h b/mbsebbs/change.h new file mode 100644 index 00000000..04b0bd8d --- /dev/null +++ b/mbsebbs/change.h @@ -0,0 +1,26 @@ +#ifndef _CHANGE_H +#define _CHANGE_H + + +int Chg_Language(int); /* Change language */ +void Chg_Password(void); /* Change BBS Password */ +void Chg_Handle(void); /* Change Handle */ +void Chg_Hotkeys(void); /* Toggle Hotkeys */ +void Chg_Disturb(void); /* Toggle "Do not disturb" */ +void Chg_MailCheck(void); /* Toggle New Mail Check */ +void Chg_FileCheck(void); /* Toggle New Files Check */ +void Chg_FsMsged(void); /* Toggle Fullscreen Editor */ +void Chg_Location(void); /* Change location */ +void Chg_Graphics(void); /* Toggle graphics */ +void Chg_VoicePhone(void); /* Change voicephone */ +void Chg_DataPhone(void); /* Change dataphone */ +void Chg_News(void); /* Toggle News Bulletins */ +void Chg_ScreenLen(void); /* Change screen len */ +int Test_DOB(char *); /* Test of Date of Birth is valid */ +void Chg_DOB(void); /* Change Date of Birth */ +void Chg_Protocol(void); /* Change default transfer protocol. */ +void Set_Protocol(char *); /* Set default protocol */ + + +#endif + diff --git a/mbsebbs/chat.c b/mbsebbs/chat.c new file mode 100644 index 00000000..1f359d28 --- /dev/null +++ b/mbsebbs/chat.c @@ -0,0 +1,194 @@ +/***************************************************************************** + * + * File ..................: bbs/chat.c + * Purpose ...............: Sysop to user chat utility + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "chat.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "exitinfo.h" + + + +#define DEVICE "/tmp/chatdev" + + + + +void Chat(void) +{ + FILE *pGetDev, *pLog, *pBusy, *pChat; + int ch; + int iLetter = 0; + char sDevice[20]; + char *sLog = NULL; + char temp[81] = ""; + + if(CFG.iAutoLog) + sLog = calloc(56, sizeof(char)); + + WhosDoingWhat(SYSOPCHAT); + + clear(); + + if((pGetDev = fopen(DEVICE,"r")) == NULL) + WriteError("Can't open file:", DEVICE); + else { + fscanf(pGetDev, "%19s", sDevice); + fclose(pGetDev); + } + + if(( pChat = fopen(sDevice,"w")) == NULL) + perror("Error"); + + /* + * Check to see if it must load a external chat program + * Check the length of the chat program is greater than Zero + * Check if user has execute permisson on the chat program + */ + if(!CFG.iExternalChat || (strlen(CFG.sExternalChat) < 1) || \ + (access(CFG.sExternalChat, X_OK) != 0)) { + if ((pBusy = fopen("/tmp/.BusyChatting", "w")) == NULL) + WriteError("Unable to open BusyChatting file", "/tmp/.BusyChatting"); + else { + fprintf(pBusy, "%s", pTTY); + fclose(pBusy); + } + + sprintf(temp, "/tmp/.chat.%s", pTTY); + if(( pBusy = fopen(temp, "w")) == NULL) + WriteError("Unable to open chat.tty file", temp); + else + fclose(pBusy); + + colour(10, 0); + printf("%s\n\r", (char *) Language(59)); + fflush(stdout); + Setraw(); + + sleep(2); + + Syslog('+', "Sysop chat started"); + + fprintf(pChat, "%s is ready ... \n\r",exitinfo.sUserName); + + while (1) { + ch = getc(stdin); + ch &= '\377'; + /* The next statement doesn't work, the chat will start again */ + if (ch == '\007') { + Syslog('+', "Sysop chat ended - User exited chat"); + unlink("/tmp/chatdev"); + sprintf(temp, "/tmp/.chat.%s", pTTY); + unlink(temp); + unlink("/tmp/.BusyChatting"); + Unsetraw(); + break; + } + putchar(ch); + putc(ch, pChat); + + if(CFG.iAutoLog) { + if(ch != '\b') + iLetter++; /* Count the letters user presses for logging */ + sprintf(sLog, "%s%c", sLog, ch); + } + + if (ch == '\n') { + ch = '\r'; + putchar(ch); + putc(ch, pChat); + } + + if (ch == '\r') { + ch = '\n'; + putchar(ch); + putc(ch, pChat); + } + + if (ch == '\b') { + ch = ' '; + putchar(ch); + putc(ch, pChat); + ch = '\b'; + putchar(ch); + putc(ch, pChat); + + if(CFG.iAutoLog) + sLog[--iLetter] = '\0'; + } + + /* Check if log chat is on and if so log chat to disk */ + if(CFG.iAutoLog) { + if(iLetter >= 55 || ch == '\n') { + iLetter = 0; + sprintf(temp, "%s/etc/%s", getenv("MBSE_ROOT"), CFG.chat_log); + if(( pLog = fopen(temp, "a+")) != NULL) { + fflush(pLog); + fprintf(pLog, "%s [%s]: %s\n", exitinfo.sUserName, (char *) GetLocalHM(), sLog); + fclose(pLog); + strcpy(sLog, ""); + } + } + } + + if(access("/tmp/chatdev", R_OK) != 0) { + colour(10, 0); + printf("\n\n\n%s\n\n\r", (char *) Language(60)); + Syslog('+', "Sysop chat ended"); + sprintf(temp, "/tmp/.chat.%s", pTTY); + unlink(temp); + unlink("/tmp/.BusyChatting"); + Unsetraw(); + Pause(); + break; + } + } + /* End of ExternalChat Check */ + } else { + system(CFG.sExternalChat); + printf("\n\n"); + Pause(); + } + + if(CFG.iAutoLog) + free(sLog); + + fclose(pChat); +} + + diff --git a/mbsebbs/chat.h b/mbsebbs/chat.h new file mode 100644 index 00000000..766333be --- /dev/null +++ b/mbsebbs/chat.h @@ -0,0 +1,8 @@ +#ifndef _CHAT_H +#define _CHAT_H + +void Chat(void); /* Chat Function */ + +#endif + + diff --git a/mbsebbs/commonio.c b/mbsebbs/commonio.c new file mode 100644 index 00000000..3c3fa706 --- /dev/null +++ b/mbsebbs/commonio.c @@ -0,0 +1,746 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/commonio.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 07-Feb-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SHADOW_PASSWORD +#include +#endif +#include "commonio.h" + +/* local function prototypes */ +static int check_link_count (const char *); +static int do_lock_file (const char *, const char *); +static FILE *fopen_set_perms (const char *, const char *, const struct stat *); +static int create_backup (const char *, FILE *); +static void free_linked_list (struct commonio_db *); +static void add_one_entry (struct commonio_db *, struct commonio_entry *); +static int name_is_nis (const char *); +static int write_all (const struct commonio_db *); +static struct commonio_entry *find_entry_by_name (struct commonio_db *, const char *); + + +static int check_link_count(const char *file) +{ + struct stat sb; + + if (stat(file, &sb) != 0) + return 0; + + if (sb.st_nlink != 2) + return 0; + + return 1; +} + + +static int do_lock_file(const char *file, const char *lock) +{ + int fd; + int pid; + int len; + int retval; + char buf[32]; + + if ((fd = open(file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1) + return 0; + + pid = getpid(); + snprintf(buf, sizeof buf, "%d", pid); + len = strlen(buf) + 1; + if (write (fd, buf, len) != len) { + close(fd); + unlink(file); + return 0; + } + close(fd); + + if (link(file, lock) == 0) { + retval = check_link_count(file); + unlink(file); + return retval; + } + + if ((fd = open(lock, O_RDWR)) == -1) { + unlink(file); + errno = EINVAL; + return 0; + } + len = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (len <= 0) { + unlink(file); + errno = EINVAL; + return 0; + } + buf[len] = '\0'; + if ((pid = strtol(buf, (char **) 0, 10)) == 0) { + unlink(file); + errno = EINVAL; + return 0; + } + if (kill(pid, 0) == 0) { + unlink(file); + errno = EEXIST; + return 0; + } + if (unlink(lock) != 0) { + unlink(file); + return 0; + } + + retval = 0; + if (link(file, lock) == 0 && check_link_count(file)) + retval = 1; + + unlink(file); + return retval; +} + + + +static FILE *fopen_set_perms(const char *name, const char *mode, const struct stat *sb) +{ + FILE *fp; + int mask; + + mask = umask(0777); + fp = fopen(name, mode); + umask(mask); + if (!fp) + return NULL; + +#ifdef HAVE_FCHMOD + if (fchmod(fileno(fp), sb->st_mode & 0777)) + goto fail; +#else + if (chmod(name, sb->st_mode & 0777)) + goto fail; +#endif + +#ifdef HAVE_FCHOWN + if (fchown(fileno(fp), sb->st_uid, sb->st_gid)) + goto fail; +#else + if (chown(name, sb->st_mode)) + goto fail; +#endif + return fp; + +fail: + fclose(fp); + unlink(name); + return NULL; +} + + + +static int create_backup(const char *backup, FILE *fp) +{ + struct stat sb; + struct utimbuf ub; + FILE *bkfp; + int c, mask; + + if (fstat(fileno(fp), &sb)) + return -1; + + mask = umask(077); + bkfp = fopen(backup, "w"); + umask(mask); + if (!bkfp) + return -1; + + /* TODO: faster copy, not one-char-at-a-time. --marekm */ + rewind(fp); + while ((c = getc(fp)) != EOF) { + if (putc(c, bkfp) == EOF) + break; + } + if (c != EOF || fflush(bkfp)) { + fclose(bkfp); + return -1; + } + if (fclose(bkfp)) + return -1; + + ub.actime = sb.st_atime; + ub.modtime = sb.st_mtime; + utime(backup, &ub); + return 0; +} + + + +static void free_linked_list(struct commonio_db *db) +{ + struct commonio_entry *p; + + while (db->head) { + p = db->head; + db->head = p->next; + + if (p->line) + free(p->line); + + if (p->entry) + db->ops->free(p->entry); + + free(p); + } + db->tail = NULL; +} + + + +int commonio_setname(struct commonio_db *db, const char *name) +{ + strcpy(db->filename, name); + return 1; +} + + + +int commonio_present(const struct commonio_db *db) +{ + return (access(db->filename, F_OK) == 0); +} + + + +int commonio_lock(struct commonio_db *db) +{ + char file[1024]; + char lock[1024]; + + if (db->locked) + return 1; + + snprintf(file, sizeof file, "%s.%ld", db->filename, (long) getpid()); + snprintf(lock, sizeof lock, "%s.lock", db->filename); + if (do_lock_file(file, lock)) { + db->locked = 1; + return 1; + } + return 0; +} + + + +int commonio_lock_first(struct commonio_db *db) +{ +#ifdef HAVE_LCKPWDF + /* + * When locking several files, *_lock_first() is called + * for the first one, and *_lock() for the others. + * If lckpwdf() is available, call it here (it may block + * for up to 15 seconds), and if it succeeds, call + * *_lock() once (no retries, it should always succeed). + */ + + if (lckpwdf() == -1) + return 0; /* failure */ + + if (!commonio_lock(db)) { + ulckpwdf(); + return 0; /* failure */ + } + + return 1; /* success */ +#else + int i; + + /* + * No lckpwdf() - do it the old way. + */ +#ifndef LOCK_TRIES +#define LOCK_TRIES 15 +#endif + for (i = 1; i < LOCK_TRIES; i++) { + if (commonio_lock(db)) + return 1; /* success */ + + sleep(1); + } + + /* + * Retry the last time... + */ + return commonio_lock(db); +#endif /* !HAVE_LCKPWDF */ +} + + + +int commonio_unlock(struct commonio_db *db) +{ + char lock[1024]; + + if (db->isopen) { + db->readonly = 1; + if (!commonio_close(db)) + return 0; + } + if (db->locked) { + db->locked = 0; + snprintf(lock, sizeof lock, "%s.lock", db->filename); + unlink(lock); + return 1; + } + return 0; +} + + + +static void add_one_entry(struct commonio_db *db, struct commonio_entry *p) +{ + p->next = NULL; + p->prev = db->tail; + if (!db->head) + db->head = p; + if (db->tail) + db->tail->next = p; + db->tail = p; +} + + + +static int name_is_nis(const char *n) +{ + return (n[0] == '+' || n[0] == '-'); +} + + +/* + * New entries are inserted before the first NIS entry. Order is preserved + * when db is written out. + */ +#ifndef KEEP_NIS_AT_END +#define KEEP_NIS_AT_END 1 +#endif + +#if KEEP_NIS_AT_END +/* prototype */ +static void add_one_entry_nis (struct commonio_db *, struct commonio_entry *); + +static void add_one_entry_nis(struct commonio_db *db, struct commonio_entry *new) +{ + struct commonio_entry *p; + + for (p = db->head; p; p = p->next) { + if (name_is_nis(p->entry ? db->ops->getname(p->entry) : p->line)) { + new->next = p; + new->prev = p->prev; + if (p->prev) + p->prev->next = new; + else + db->head = new; + p->prev = new; + return; + } + } + add_one_entry(db, new); +} +#endif /* KEEP_NIS_AT_END */ + + + +int commonio_open(struct commonio_db *db, int mode) +{ + char buf[8192]; + char *cp; + char *line; + struct commonio_entry *p; + void *entry; + int flags = mode; + + mode &= ~O_CREAT; + + if (db->isopen || (mode != O_RDONLY && mode != O_RDWR)) { + errno = EINVAL; + return 0; + } + db->readonly = (mode == O_RDONLY); + if (!db->readonly && !db->locked) { + errno = EACCES; + return 0; + } + + db->head = db->tail = db->cursor = NULL; + db->changed = 0; + + db->fp = fopen(db->filename, db->readonly ? "r" : "r+"); + + /* + * If O_CREAT was specified and the file didn't exist, it will be + * created by commonio_close(). We have no entries to read yet. --marekm + */ + if (!db->fp) { + if ((flags & O_CREAT) && errno == ENOENT) { + db->isopen++; + return 1; + } + return 0; + } + + while (db->ops->fgets(buf, sizeof buf, db->fp)) { + if ((cp = strrchr(buf, '\n'))) + *cp = '\0'; + + if (!(line = strdup(buf))) + goto cleanup; + + if (name_is_nis(line)) { + entry = NULL; + } else if ((entry = db->ops->parse(line))) { + entry = db->ops->dup(entry); + if (!entry) + goto cleanup_line; + } + + p = (struct commonio_entry *) malloc(sizeof *p); + if (!p) + goto cleanup_entry; + + p->entry = entry; + p->line = line; + p->changed = 0; + + add_one_entry(db, p); + } + + db->isopen++; + return 1; + +cleanup_entry: + if (entry) + db->ops->free(entry); +cleanup_line: + free(line); +cleanup: + free_linked_list(db); + fclose(db->fp); + db->fp = NULL; + errno = ENOMEM; + return 0; +} + + + +static int write_all(const struct commonio_db *db) +{ + const struct commonio_entry *p; + void *entry; + + for (p = db->head; p; p = p->next) { + if (p->changed) { + entry = p->entry; + if (db->ops->put(entry, db->fp)) + return -1; + } else if (p->line) { + if (db->ops->fputs(p->line, db->fp) == EOF) + return -1; + if (putc('\n', db->fp) == EOF) + return -1; + } + } + return 0; +} + + + +int commonio_close(struct commonio_db *db) +{ + char buf[1024]; + int errors = 0; + struct stat sb; + + if (!db->isopen) { + errno = EINVAL; + return 0; + } + db->isopen = 0; + + if (!db->changed || db->readonly) { + fclose(db->fp); + db->fp = NULL; + goto success; + } + + if (db->fp) { + if (fstat(fileno(db->fp), &sb)) { + fclose(db->fp); + db->fp = NULL; + goto fail; + } + + /* + * Create backup file. + */ + snprintf(buf, sizeof buf, "%s-", db->filename); + + if (create_backup(buf, db->fp)) + errors++; + + if (fclose(db->fp)) + errors++; + + if (errors) { + db->fp = NULL; + goto fail; + } + } else { + /* + * Default permissions for new [g]shadow files. + * (passwd and group always exist...) + */ + sb.st_mode = 0400; + sb.st_uid = 0; + sb.st_gid = 0; + } + + snprintf(buf, sizeof buf, "%s+", db->filename); + + db->fp = fopen_set_perms(buf, "w", &sb); + if (!db->fp) + goto fail; + + if (write_all(db)) + errors++; + + if (fflush(db->fp)) + errors++; +#ifdef HAVE_FSYNC + if (fsync(fileno(db->fp))) + errors++; +#else + sync(); +#endif + if (fclose(db->fp)) + errors++; + + db->fp = NULL; + + if (errors) { + unlink(buf); + goto fail; + } + + if (rename(buf, db->filename)) + goto fail; + +success: + free_linked_list(db); + return 1; + +fail: + free_linked_list(db); + return 0; +} + + + +static struct commonio_entry * find_entry_by_name(struct commonio_db *db, const char *name) +{ + struct commonio_entry *p; + void *ep; + + for (p = db->head; p; p = p->next) { + ep = p->entry; + if (ep && strcmp(db->ops->getname(ep), name) == 0) + break; + } + return p; +} + + + +int commonio_update(struct commonio_db *db, const void *entry) +{ + struct commonio_entry *p; + void *nentry; + + if (!db->isopen || db->readonly) { + errno = EINVAL; + return 0; + } + if (!(nentry = db->ops->dup(entry))) { + errno = ENOMEM; + return 0; + } + p = find_entry_by_name(db, db->ops->getname(entry)); + if (p) { + db->ops->free(p->entry); + p->entry = nentry; + p->changed = 1; + db->cursor = p; + + db->changed = 1; + return 1; + } + /* not found, new entry */ + p = (struct commonio_entry *) malloc(sizeof *p); + if (!p) { + db->ops->free(nentry); + errno = ENOMEM; + return 0; + } + + p->entry = nentry; + p->line = NULL; + p->changed = 1; + +#if KEEP_NIS_AT_END + add_one_entry_nis(db, p); +#else + add_one_entry(db, p); +#endif + + db->changed = 1; + return 1; +} + + + +void commonio_del_entry(struct commonio_db *db, const struct commonio_entry *p) +{ + if (p == db->cursor) + db->cursor = p->next; + + if (p->prev) + p->prev->next = p->next; + else + db->head = p->next; + + if (p->next) + p->next->prev = p->prev; + else + db->tail = p->prev; + + db->changed = 1; +} + + + +int commonio_remove(struct commonio_db *db, const char *name) +{ + struct commonio_entry *p; + + if (!db->isopen || db->readonly) { + errno = EINVAL; + return 0; + } + p = find_entry_by_name(db, name); + if (!p) { + errno = ENOENT; + return 0; + } + + commonio_del_entry(db, p); + + if (p->line) + free(p->line); + + if (p->entry) + db->ops->free(p->entry); + + return 1; +} + + + +const void * commonio_locate(struct commonio_db *db, const char *name) +{ + struct commonio_entry *p; + + if (!db->isopen) { + errno = EINVAL; + return NULL; + } + p = find_entry_by_name(db, name); + if (!p) { + errno = ENOENT; + return NULL; + } + db->cursor = p; + return p->entry; +} + + + +int commonio_rewind(struct commonio_db *db) +{ + if (!db->isopen) { + errno = EINVAL; + return 0; + } + db->cursor = NULL; + return 1; +} + + + +const void * commonio_next(struct commonio_db *db) +{ + void *entry; + + if (!db->isopen) { + errno = EINVAL; + return 0; + } + if (db->cursor == NULL) + db->cursor = db->head; + else + db->cursor = db->cursor->next; + + while (db->cursor) { + entry = db->cursor->entry; + if (entry) + return entry; + + db->cursor = db->cursor->next; + } + return NULL; +} + diff --git a/mbsebbs/commonio.h b/mbsebbs/commonio.h new file mode 100644 index 00000000..14b98f50 --- /dev/null +++ b/mbsebbs/commonio.h @@ -0,0 +1,108 @@ +#ifndef _COMMONIO_H +#define _COMMONIO_H + + + +/* + * Linked list entry. + */ +struct commonio_entry { + char *line; + int changed; + void *entry; /* struct passwd, struct spwd, ... */ + struct commonio_entry *prev, *next; +}; + + + +/* + * Operations depending on database type: passwd, group, shadow etc. + */ +struct commonio_ops { + /* + * Make a copy of the object (for example, struct passwd) + * and all strings pointed by it, in malloced memory. + */ + void * (*dup) (const void *); + + /* + * free() the object including any strings pointed by it. + */ + void (*free) (void *); + + /* + * Return the name of the object (for example, pw_name + * for struct passwd). + */ + const char * (*getname) (const void *); + + /* + * Parse a string, return object (in static area - + * should be copied using the dup operation above). + */ + void * (*parse) (const char *); + + /* + * Write the object to the file (this calls putpwent() + * for struct passwd, for example). + */ + int (*put) (const void *, FILE *); + + /* + * fgets and fputs (can be replaced by versions that + * understand line continuation conventions). + */ + char * (*fgets) (char *, int, FILE *); + int (*fputs) (const char *, FILE *); +}; + + + +/* + * Database structure. + */ +struct commonio_db { + /* + * Name of the data file. + */ + char filename[1024]; + + /* + * Operations from above. + */ + struct commonio_ops *ops; + + /* + * Currently open file stream. + */ + FILE *fp; + + /* + * Head, tail, current position in linked list. + */ + struct commonio_entry *head, *tail, *cursor; + + /* + * Various flags. + */ + int changed, isopen, locked, readonly; +}; + + + +int commonio_setname (struct commonio_db *, const char *); +int commonio_present (const struct commonio_db *); +int commonio_lock (struct commonio_db *); +int commonio_lock_first (struct commonio_db *); +int commonio_open (struct commonio_db *, int); +const void *commonio_locate (struct commonio_db *, const char *); +int commonio_update (struct commonio_db *, const void *); +int commonio_remove (struct commonio_db *, const char *); +int commonio_rewind (struct commonio_db *); +const void *commonio_next (struct commonio_db *); +int commonio_close (struct commonio_db *); +int commonio_unlock (struct commonio_db *); +void commonio_del_entry (struct commonio_db *, const struct commonio_entry *); + +#endif + diff --git a/mbsebbs/email.c b/mbsebbs/email.c new file mode 100644 index 00000000..259bd067 --- /dev/null +++ b/mbsebbs/email.c @@ -0,0 +1,1041 @@ +/***************************************************************************** + * + * File ..................: bbs/email.c + * Purpose ...............: Internet email + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "exitinfo.h" +#include "language.h" +#include "mail.h" +#include "timeout.h" +#include "msgutil.h" +#include "funcs4.h" +#include "email.h" + + +extern unsigned long LastNum; +extern int Kludges; +extern FILE *qf; +extern char *Message[]; +extern int Line; +extern int do_mailout; + + + +/* + * Internal prototypes + */ +int HasNoEmail(void); +int Export_a_Email(unsigned long); +int EmailPanel(void); +void Reply_Email(int); +int Save_Email(int); + + + +int HasNoEmail(void) +{ + if (exitinfo.Email) + return FALSE; + + colour(15, 0); + printf("\nYou have no e-mail access\n\n"); + sleep(3); + return TRUE; +} + + + +/* + * Show message header screen top for reading messages. + */ +void ShowEmailHdr(void) +{ + static char Buf1[35], Buf2[35], Buf3[81]; + struct tm *tm; + + Buf1[0] = '\0'; + Buf2[0] = '\0'; + Buf3[0] = '\0'; + + clear(); + colour(1,7); + printf(" %-70s", sMailbox); + + colour(4,7); + printf("#%-5lu\n", Msg.Id); + + /* Date : */ + pout(14, 0, (char *) Language(206)); + colour(10, 0); + tm = gmtime(&Msg.Written); + printf("%02d-%02d-%d %02d:%02d:%02d", tm->tm_mday, tm->tm_mon+1, + tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec); + colour(12, 0); + if (Msg.Local) printf(" Local"); + if (Msg.Intransit) printf(" Transit"); + if (Msg.Private) printf(" Priv."); + if (Msg.Received) printf(" Rcvd"); + if (Msg.Sent) printf(" Sent"); + if (Msg.KillSent) printf(" KillSent"); + if (Msg.ArchiveSent) printf(" ArchiveSent"); + if (Msg.Hold) printf(" Hold"); + if (Msg.Crash) printf(" Crash"); + if (Msg.Immediate) printf(" Imm."); + if (Msg.Direct) printf(" Dir"); + if (Msg.Gate) printf(" Gate"); + if (Msg.FileRequest) printf(" Freq"); + if (Msg.FileAttach) printf(" File"); + if (Msg.TruncFile) printf(" TruncFile"); + if (Msg.KillFile) printf(" KillFile"); + if (Msg.ReceiptRequest) printf(" RRQ"); + if (Msg.ConfirmRequest) printf(" CRQ"); + if (Msg.Orphan) printf(" Orphan"); + if (Msg.Encrypt) printf(" Crypt"); + if (Msg.Compressed) printf(" Comp"); + if (Msg.Escaped) printf(" 7bit"); + if (Msg.ForcePU) printf(" FPU"); + if (Msg.Localmail) printf(" Localmail"); + if (Msg.Netmail) printf(" Netmail"); + if (Msg.Echomail) printf(" Echomail"); + if (Msg.News) printf(" News"); + if (Msg.Email) printf(" E-mail"); + if (Msg.Nodisplay) printf(" Nodisp"); + if (Msg.Locked) printf(" LCK"); + if (Msg.Deleted) printf(" Del"); + printf("\n"); + + /* From : */ + pout(14,0, (char *) Language(209)); + colour(10, 0); + printf("%s\n", Msg.From); + + /* To : */ + pout(14,0, (char *) Language(208)); + colour(10, 0); + printf("%s\n", Msg.To); + + /* Subject : */ + pout(14,0, (char *) Language(210)); + colour(10, 0); + printf("%s\n", Msg.Subject); + + colour(CFG.HiliteF, CFG.HiliteB); + colour(14, 1); + if (Msg.Reply) + sprintf(Buf1, "\"+\" %s %lu", (char *)Language(211), Msg.Reply); + if (Msg.Original) + sprintf(Buf2, " \"-\" %s %lu", (char *)Language(212), Msg.Original); + sprintf(Buf3, "%s%s ", Buf1, Buf2); + colour(14, 1); + printf("%78s \n", Buf3); +} + + + + +/* + * Export a email to file in the users home directory. + */ +int Export_a_Email(unsigned long Num) +{ + char *p; + + LastNum = Num; + iLineCount = 7; + WhosDoingWhat(READ_POST); + Syslog('+', "Export email %d in area %s", Num, sMailbox); + + /* + * The area data is already set, so we can do the next things + */ + if (EmailBase.Total == 0) { + colour(15, 0); + /* There are no messages in this area */ + printf("\n%s\n\n", (char *) Language(205)); + sleep(3); + return FALSE; + } + + if (!Msg_Open(sMailpath)) { + WriteError("Error open JAM base %s", sMailpath); + return FALSE; + } + + if (!Msg_ReadHeader(Num)) { + perror(""); + colour(15, 0); + printf("\n%s\n\n", (char *)Language(77)); + Msg_Close(); + sleep(3); + return FALSE; + } + + /* + * Export the message text to the file in the users home/wrk directory. + * Create the filename as _.msg The message is + * written in M$DOS format. + */ + p = calloc(PATH_MAX, sizeof(char)); + sprintf(p, "%s/%s/wrk/%s_%lu.msg", CFG.bbs_usersdir, exitinfo.Name, sMailbox, Num); + if ((qf = fopen(p, "w")) != NULL) { + free(p); + p = NULL; + if (Msg_Read(Num, 80)) { + if ((p = (char *)MsgText_First()) != NULL) + do { + if (p[0] == '\001') { + if (Kludges) { + p[0] = 'a'; + fprintf(qf, "^%s\r\n", p); + } + } else + fprintf(qf, "%s\r\n", p); + } while ((p = (char *)MsgText_Next()) != NULL); + } + fclose(qf); + } else { + WriteError("$Can't open %s", p); + free(p); + } + Msg_Close(); + + /* + * Report the result. + */ + colour(CFG.TextColourF, CFG.TextColourB); + printf("\n\n%s", (char *) Language(46)); + colour(CFG.HiliteF, CFG.HiliteB); + printf("%s_%lu.msg\n\n", sMailbox, Num); + Pause(); + return TRUE; +} + + + +/* + * Save the message to disk. + */ +int Save_Email(int IsReply) +{ + int i; + char *p, *temp; + unsigned long crc = -1; + long id; + FILE *fp; + + if (Line < 2) + return TRUE; + + if (!Open_Msgbase(sMailpath, 'w')) { + return FALSE; + } + + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Written = Msg.Arrived; + Msg.Local = TRUE; + Msg.Netmail = TRUE; + temp = calloc(PATH_MAX, sizeof(char)); + + /* + * Add header lines + */ + sprintf(temp, "\001Date: %s", rfcdate(Msg.Written)); + MsgText_Add2(temp); + sprintf(temp, "\001From: %s", Msg.From); + MsgText_Add2(temp); + sprintf(temp, "\001Subject: %s", Msg.Subject); + MsgText_Add2(temp); + sprintf(temp, "\001Sender: %s", Msg.From); + MsgText_Add2(temp); + sprintf(temp, "\001To: %s", Msg.To); + MsgText_Add2(temp); + MsgText_Add2((char *)"\001MIME-Version: 1.0"); + MsgText_Add2((char *)"\001Content-Type: text/plain"); + MsgText_Add2((char *)"\001Content-Transfer-Encoding: 8bit"); + sprintf(temp, "\001X-Mailreader: MBSE BBS %s", VERSION); + MsgText_Add2(temp); + p = calloc(81, sizeof(char)); + id = sequencer(); + sprintf(p, "<%08lx@%s>", id, CFG.sysdomain); + sprintf(temp, "\001Message-id: %s", p); + MsgText_Add2(temp); + sprintf(temp, "\001MSGID: %s %08lx", aka2str(CFG.EmailFidoAka), id); + MsgText_Add2(temp); + Msg.MsgIdCRC = upd_crc32(temp, crc, strlen(temp)); + free(p); + sprintf(temp, "\001PID: MBSE-BBS %s", VERSION); + MsgText_Add2(temp); + + if (IsReply) { + sprintf(temp, "\001In-reply-to: %s", Msg.Replyid); + MsgText_Add2(temp); + crc = -1; + Msg.ReplyCRC = upd_crc32(temp, crc, strlen(temp)); + } else + Msg.ReplyCRC = 0xffffffff; + + + /* + * Add message text + */ + for (i = 1; i < Line; i++) { + MsgText_Add2(Message[i]); + } + + sprintf(temp, "--- MBSE BBS v%s (Linux)", VERSION); + MsgText_Add2(temp); + + /* + * Save if to disk + */ + Msg_AddMsg(); + Msg_UnLock(); + + ReadExitinfo(); + exitinfo.iPosted++; + WriteExitinfo(); + + do_mailout = TRUE; + + Syslog('+', "Email (%ld) to \"%s\", \"%s\", in mailbox", Msg.Id, Msg.To, Msg.Subject); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Saving message to disk */ + printf("\n%s(%ld)\n\n", (char *) Language(202), Msg.Id); + fflush(stdout); + sleep(2); + + /* + * Add quick mailscan info + */ + sprintf(temp, "%s/tmp/netmail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "a")) != NULL) { + fprintf(fp, "%s/%s/mailbox %lu\n", CFG.bbs_usersdir, exitinfo.Name, Msg.Id); + fclose(fp); + } + + free(temp); + Msg_Close(); + + return TRUE; +} + + + +int Read_a_Email(unsigned long Num) +{ + char *p = NULL, *fn; + lastread LR; + + LastNum = Num; + iLineCount = 7; + WhosDoingWhat(READ_POST); + + /* + * The area data is already set, so we can do the next things + */ + if (EmailBase.Total == 0) { + colour(15, 0); + /* There are no messages in this area */ + printf("\n%s\n\n", (char *) Language(205)); + sleep(3); + return FALSE; + } + + if (!Msg_Open(sMailpath)) { + WriteError("Error open JAM base %s", sMailpath); + return FALSE; + } + + if (!Msg_ReadHeader(Num)) { + perror(""); + colour(15, 0); + printf("\n%s\n\n", (char *)Language(77)); + Msg_Close(); + sleep(3); + return FALSE; + } + ShowEmailHdr(); + + /* + * Fill Quote file in case the user wants to reply. Note that line + * wrapping is set lower then normal message read, to create room + * for the Quote> strings at the start of each line. + */ + fn = calloc(PATH_MAX, sizeof(char)); + sprintf(fn, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((qf = fopen(fn, "w")) != NULL) { + if (Msg_Read(Num, 75)) { + if ((p = (char *)MsgText_First()) != NULL) + do { + if (p[0] == '\001') { + /* + * While doing this, store the original Message-id in case + * a reply will be made. + */ + if (strncasecmp(p, "\001Message-id: ", 13) == 0) { + sprintf(Msg.Msgid, "%s", p+13); + Syslog('m', "Stored Msgid \"%s\"", Msg.Msgid); + } + if (Kludges) { + p[0] = 'a'; + fprintf(qf, "^%s\n", p); + } + } else + fprintf(qf, "%s\n", p); + } while ((p = (char *)MsgText_Next()) != NULL); + } + fclose(qf); + } else { + WriteError("$Can't open %s", p); + } + free(fn); + + /* + * Show message text + */ + colour(CFG.TextColourF, CFG.TextColourB); + if (Msg_Read(Num, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (p[0] == '\001') { + if (Kludges) { + colour(7, 0); + printf("%s\n", p); + if (CheckLine(CFG.TextColourF, CFG.TextColourB, TRUE)) + break; + } + } else { + colour(CFG.TextColourF, CFG.TextColourB); + if (strchr(p, '>') != NULL) + if ((strlen(p) - strlen(strchr(p, '>'))) < 10) + colour(CFG.HiliteF, CFG.HiliteB); + printf("%s\n", p); + if (CheckLine(CFG.TextColourF, CFG.TextColourB, TRUE)) + break; + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + /* + * Set the Received status on this message. + */ + if (!Msg.Received) { + Syslog('m', "Marking message received"); + Msg.Received = TRUE; + Msg.Read = time(NULL) - (gmt_offset((time_t)0) * 60); + if (Msg_Lock(30L)) { + Msg_WriteHeader(Num); + Msg_UnLock(); + } + } + + /* + * Update lastread pointer. + */ + if (Msg_Lock(30L)) { + LR.UserID = grecno; + p = xstrcpy(exitinfo.sUserName); + if (Msg_GetLastRead(&LR) == TRUE) { + LR.LastReadMsg = Num; + if (Num > LR.HighReadMsg) + LR.HighReadMsg = Num; + if (LR.HighReadMsg > EmailBase.Highest) + LR.HighReadMsg = EmailBase.Highest; + LR.UserCRC = StringCRC32(tl(p)); + if (!Msg_SetLastRead(LR)) + WriteError("Error update lastread"); + } else { + /* + * Append new lastread pointer + */ + LR.UserCRC = StringCRC32(tl(p)); + LR.UserID = grecno; + LR.LastReadMsg = Num; + LR.HighReadMsg = Num; + if (!Msg_NewLastRead(LR)) + WriteError("Can't append lastread"); + } + free(p); + Msg_UnLock(); + } + + Msg_Close(); + return TRUE; +} + + + +/* + * The panel bar under the message while email reading + */ +int EmailPanel(void) +{ + int input; + + WhosDoingWhat(READ_POST); + + colour(15, 4); + /* (A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (D)elete, (Q)uit, e(X)port */ + printf("%s", (char *) Language(214)); + if (exitinfo.Security.level >= CFG.sysop_access) + printf(", (!)"); + printf(": "); + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + + if (input == '!') { + if (exitinfo.Security.level >= CFG.sysop_access) { + if (Kludges) + Kludges = FALSE; + else + Kludges = TRUE; + Read_a_Email(LastNum); + } + } else if (input == Keystroke(214, 0)) { /* (A)gain */ + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 4)) { /* (P)ost */ + Write_Email(); + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 2)) { /* (L)ast */ + if (LastNum > EmailBase.Lowest) + LastNum--; + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 3)) { /* (R)eply */ + Reply_Email(TRUE); + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 5)) { /* (Q)uit */ + /* Quit */ + printf("%s\n", (char *) Language(189)); + return FALSE; + } else if (input == Keystroke(214, 7)) { /* e(X)port */ + Export_a_Email(LastNum); + Read_a_Email(LastNum); + } else if (input == '+') { + if (Msg.Reply) + LastNum = Msg.Reply; + Read_a_Email(LastNum); + } else if (input == '-') { + if (Msg.Original) + LastNum = Msg.Original; + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 6)) { /* (D)elete */ +// Delete_EmailNum(LastNum); + if (LastNum < EmailBase.Highest) { + LastNum++; + Read_a_Email(LastNum); + } else { + return FALSE; + } + } else { + /* Next */ + pout(15, 0, (char *) Language(216)); + if (LastNum < EmailBase.Highest) + LastNum++; + else + return FALSE; + Read_a_Email(LastNum); + } + return TRUE; +} + + + +/* + * Read e-mail, called from the menus + */ +void Read_Email(void) +{ + char *temp; + unsigned long Start; + lastread LR; + + if (HasNoEmail()) + return; + + colour(CFG.TextColourF, CFG.TextColourB); + /* Message area \"%s\" contains %lu messages. */ + printf("\n%s\"%s\" %s%lu %s", (char *) Language(221), sMailbox, (char *) Language(222), EmailBase.Total, (char *) Language(223)); + + /* + * Check for lastread pointer, suggest lastread number for start. + */ + Start = EmailBase.Lowest; + if (Msg_Open(sMailpath)) { + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg + 1; + else + Start = 1; + Msg_Close(); + /* + * If we already have read the last message, the pointer is + * higher then HighMsgNum, we set it at HighMsgNum to prevent + * errors and read that message again. + */ + if (Start > EmailBase.Highest) + Start = EmailBase.Highest; + } + + colour(15, 0); + /* Please enter a message between */ + printf("\n%s(%lu - %lu)", (char *) Language(224), EmailBase.Lowest, EmailBase.Highest); + /* Message number [ */ + printf("\n%s%lu]: ", (char *) Language(225), Start); + + temp = calloc(128, sizeof(char)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if ((strcmp(temp, "")) != 0) + Start = atoi(temp); + free(temp); + + if (!Read_a_Email(Start)) + return; + + if (EmailBase.Total == 0) + return; + + while(EmailPanel()) {} +} + + + +/* + * Reply message, in Msg.From and Msg.Subject must be the + * name to reply to and the subject. + */ +void Reply_Email(int IsReply) +{ + int i, j, x; + char to[65]; + char from[65]; + char subj[72]; + char msgid[81]; + char replyto[81]; + char replyaddr[81]; + char *tmp, *buf; + char qin[9]; + faddr *Dest = NULL; + + sprintf(from, "%s", Msg.To); + sprintf(to, "%s", Msg.From); + sprintf(replyto, "%s", Msg.ReplyTo); + sprintf(replyaddr, "%s", Msg.ReplyAddr); + + if (strncasecmp(Msg.Subject, "Re:", 3) && IsReply) { + sprintf(subj, "Re: %s", Msg.Subject); + } else { + sprintf(subj, "%s", Msg.Subject); + } + Syslog('m', "Reply msg to %s, subject %s", to, subj); + Syslog('m', "Msgid was %s", Msg.Msgid); + sprintf(msgid, "%s", Msg.Msgid); + + x = 0; + Line = 1; + WhosDoingWhat(READ_POST); + clear(); + colour(1,7); + printf(" %-71s", sMailbox); + colour(4,7); + printf("#%-5lu", EmailBase.Highest + 1); + + colour(CFG.HiliteF, CFG.HiliteB); + sLine(); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + Message[i] = (char *) calloc(81, sizeof(char)); + Line = 1; + Msg_New(); + + sprintf(Msg.Replyid, "%s", msgid); + sprintf(Msg.ReplyTo, "%s", replyto); + sprintf(Msg.ReplyAddr, "%s", replyaddr); + + /* From : */ + pout(14, 0, (char *) Language(209)); + if (CFG.EmailMode != E_PRMISP) { + /* + * If not permanent connected to the internet, use fidonet.org style addressing. + */ + Dest = fido2faddr(CFG.EmailFidoAka); + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, ascinode(Dest, 0x2f), exitinfo.sUserName); + } else + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, CFG.sysdomain, exitinfo.sUserName); + for (i = 0; i < strlen(Msg.From); i++) { + if (Msg.From[i] == ' ') + Msg.From[i] = '_'; + if (Msg.From[i] == '@') + break; + } + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.From); + Enter(1); + Syslog('b', "Setting From: %s", Msg.From); + + /* To : */ + sprintf(Msg.To, "%s", to); + pout(14, 0, (char *) Language(208)); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.To); + Enter(1); + + /* Enter to keep Subject. */ + pout(12, 0, (char *) Language(219)); + Enter(1); + /* Subject : */ + pout(14, 0, (char *) Language(210)); + sprintf(Msg.Subject, "%s", subj); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.Subject); + + x = strlen(subj); + fflush(stdout); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrP(subj, 50, x); + fflush(stdout); + + if (strlen(subj)) + strcpy(Msg.Subject, subj); + tlf(Msg.Subject); + + Msg.Private = TRUE; + Enter(1); + +// Check_Attach(); + + /* + * Quote original message now, format the original users + * initials into qin. If its a name@system.dom the use the + * first 8 characters of the name part. + */ + sprintf(Message[1], "%s wrote to %s:", to, from); + memset(&qin, 0, sizeof(qin)); + if (strchr(to, '@')) { + tmp = xstrcpy(strtok(to, "@")); + tmp[8] = '\0'; + sprintf(qin, "%s", tmp); + free(tmp); + } else { + x = TRUE; + j = 0; + for (i = 0; i < strlen(to); i++) { + if (x) { + qin[j] = to[i]; + j++; + x = FALSE; + } + if (to[i] == ' ' || to[i] == '.') + x = TRUE; + if (j == 6) + break; + } + } + + Line = 2; + tmp = calloc(128, sizeof(char)); + buf = calloc(128, sizeof(char)); + + sprintf(tmp, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((qf = fopen(tmp, "r")) != NULL) { + while ((fgets(buf, 128, qf)) != NULL) { + Striplf(buf); + sprintf(Message[Line], "%s> %s", (char *)qin, buf); + Line++; + if (Line == TEXTBUFSIZE) + break; + } + fclose(qf); + } else + WriteError("$Can't read %s", tmp); + + free(buf); + free(tmp); + + if (Edit_Msg()) + Save_Email(IsReply); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); +} + + + +void Write_Email(void) +{ + faddr *Dest = NULL; + int i; + char *orgbox; + + if (HasNoEmail()) + return; + + orgbox = xstrcpy(sMailbox); + SetEmailArea((char *)"mailbox"); + + WhosDoingWhat(READ_POST); + clear(); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + Message[i] = (char *) calloc(81, sizeof(char)); + Line = 1; + + Msg_New(); + + colour(9, 0); + /* Posting message in area: */ + printf("\n%s\"%s\"\n", (char *) Language(156), "mailbox"); + + Enter(1); + /* From : */ + pout(14, 0, (char *) Language(157)); + if (CFG.EmailMode != E_PRMISP) { + /* + * If not permanent connected to the internet, use fidonet.org style addressing. + */ + Dest = fido2faddr(CFG.EmailFidoAka); + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, ascinode(Dest, 0x2f), exitinfo.sUserName); + } else + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, CFG.sysdomain, exitinfo.sUserName); + for (i = 0; i < strlen(Msg.From); i++) { + if (Msg.From[i] == ' ') + Msg.From[i] = '_'; + if (Msg.From[i] == '@') + break; + } + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Msg.From); + Syslog('b', "Setting From: %s", Msg.From); + + Enter(1); + /* To : */ + pout(14, 0, (char *) Language(158)); + + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrU(Msg.To, 63); + + if ((strcmp(Msg.To, "")) == 0) { + for(i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + SetEmailArea(orgbox); + return; + } + + /* Subject : */ + pout(14, 0, (char *) Language(161)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + GetstrP(Msg.Subject, 65, 0); + tlf(Msg.Subject); + + if((strcmp(Msg.Subject, "")) == 0) { + Enter(1); + /* Abort Message [y/N] ?: */ + pout(3, 0, (char *) Language(162)); + fflush(stdout); + alarm_on(); + + if (toupper(Getone()) == Keystroke(162, 0)) { + for(i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + SetEmailArea(orgbox); + return; + } + } + + Msg.Private = TRUE; + + if (Edit_Msg()) { + Save_Email(FALSE); + } + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + + SetEmailArea(orgbox); +} + + + +void QuickScan_Email(void) +{ + int FoundMsg = FALSE; + long i; + + iLineCount = 2; + WhosDoingWhat(READ_POST); + + if (EmailBase.Total == 0) { + Enter(1); + /* There are no messages in this area. */ + pout(15, 0, (char *) Language(205)); + Enter(3); + sleep(3); + return; + } + + clear(); + /* # From To Subject */ + poutCR(14, 1, (char *) Language(220)); + + if (Msg_Open(sMailpath)) { + for (i = EmailBase.Lowest; i <= EmailBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + + colour(15, 0); + printf("%-6lu", Msg.Id); + colour(3, 0); + printf("%s ", padleft(Msg.From, 20, ' ')); + + colour(2, 0); + printf("%s ", padleft(Msg.To, 20, ' ')); + colour(5, 0); + printf("%s", padleft(Msg.Subject, 31, ' ')); + printf("\n"); + FoundMsg = TRUE; + if (LC(1)) + break; + } + } + Msg_Close(); + } + + if(!FoundMsg) { + Enter(1); + /* There are no messages in this area. */ + pout(10, 0, (char *) Language(205)); + Enter(2); + sleep(3); + } + + iLineCount = 2; + Pause(); +} + + + +void Trash_Email(void) +{ + if (HasNoEmail()) + return; +} + + + +void Choose_Mailbox(char *Option) +{ + char *temp; + + if (HasNoEmail()) + return; + + if (strlen(Option)) { + if (!strcmp(Option, "M+")) { + if (!strcmp(sMailbox, "mailbox")) + SetEmailArea((char *)"archive"); + else if (!strcmp(sMailbox, "archive")) + SetEmailArea((char *)"trash"); + else if (!strcmp(sMailbox, "trash")) + SetEmailArea((char *)"mailbox"); + } + if (!strcmp(Option, "M-")) { + if (!strcmp(sMailbox, "mailbox")) + SetEmailArea((char *)"trash"); + else if (!strcmp(sMailbox, "trash")) + SetEmailArea((char *)"archive"); + else if (!strcmp(sMailbox, "archive")); + SetEmailArea((char *)"mailbox"); + } + Syslog('+', "Emailarea: %s", sMailbox); + return; + } + + clear(); + Enter(1); + /* Message areas */ + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(231)); + Enter(2); + + pout(15, 0, (char *)" 1"); pout(9, 0, (char *)" . "); pout(3, 0, (char *) Language(467)); printf("\n"); + pout(15, 0, (char *)" 2"); pout(9, 0, (char *)" . "); pout(3, 0, (char *) Language(468)); printf("\n"); + pout(15, 0, (char *)" 3"); pout(9, 0, (char *)" . "); pout(3, 0, (char *) Language(469)); printf("\n"); + + pout(CFG.MoreF, CFG.MoreB, (char *) Language(470)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + temp = calloc(81, sizeof(char)); + GetstrC(temp, 7); + + switch (atoi(temp)) { + case 1: SetEmailArea((char *)"mailbox"); + break; + case 2: SetEmailArea((char *)"archive"); + break; + case 3: SetEmailArea((char *)"trash"); + break; + } + + Syslog('+', "Emailarea: %s", sMailbox); + free(temp); +} + + + +void SetEmailArea(char *box) +{ + if (!exitinfo.Email) + return; + + sprintf(sMailpath, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, box); + sprintf(sMailbox, "%s", box); + + /* + * Get information from the message base + */ + if (Msg_Open(sMailpath)) { + EmailBase.Lowest = Msg_Lowest(); + EmailBase.Highest = Msg_Highest(); + EmailBase.Total = Msg_Number(); + Msg_Close(); + } else + WriteError("Error open JAM %s", sMailpath); +} + + + diff --git a/mbsebbs/email.h b/mbsebbs/email.h new file mode 100644 index 00000000..81bc9d1f --- /dev/null +++ b/mbsebbs/email.h @@ -0,0 +1,15 @@ +#ifndef _EMAIL_H +#define _EMAIL_H + +void ShowEmailHdr(void); +int Read_a_Email(unsigned long); +void Read_Email(void); +void Write_Email(void); +void QuickScan_Email(void); +void Trash_Email(void); +void Choose_Mailbox(char *); +void SetEmailArea(char *); + + +#endif + diff --git a/mbsebbs/encrypt.c b/mbsebbs/encrypt.c new file mode 100644 index 00000000..f4d4069c --- /dev/null +++ b/mbsebbs/encrypt.c @@ -0,0 +1,142 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/encrypt.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 13-May-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * Copyright 1990 - 1993, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "../config.h" +#include +#include +#ifdef _XOPEN_CRYPT +#include +#endif +#include "encrypt.h" + +#ifdef MD5_CRYPT +extern char *md5_crypt(); +#endif + + +char *pw_encrypt(const char *clear, const char *salt) +{ + static char cipher[128]; + char *cp; +#ifdef SW_CRYPT + static int count; +#endif + +#ifdef MD5_CRYPT + /* + * If the salt string from the password file or from crypt_make_salt() + * begins with the magic string, use the new algorithm. + */ + if (strncmp(salt, "$1$", 3) == 0) + return md5_crypt(clear, salt); +#endif + +#ifdef SW_CRYPT + /* + * Copy over the salt. It is always the first two + * characters of the string. + */ + + cipher[0] = salt[0]; + cipher[1] = salt[1]; + cipher[2] = '\0'; + + /* + * Loop up to ten times on the cleartext password. + * This is because the input limit for passwords is + * 80 characters. + * + * The initial salt is that provided by the user, or the + * one generated above. The subsequent salts are gotten + * from the first two characters of the previous encrypted + * block of characters. + */ + + for (count = 0;count < 10;count++) { + cp = crypt (clear, salt); + if (strlen(cp) != 13) + return cp; + strcat (cipher, cp + 2); + salt = cipher + 11 * count + 2; + + if (strlen (clear) > 8) + clear += 8; + else + break; + } +#else + cp = crypt (clear, salt); + if (strlen(cp) != 13) + return cp; /* nonstandard crypt() in libc, better bail out */ + strcpy (cipher, cp); + +#ifdef DOUBLESIZE + if (strlen (clear) > 8) { + cp = crypt (clear + 8, salt); + strcat (cipher, cp + 2); + } +#endif /* DOUBLESIZE */ +#endif /* SW_CRYPT */ + return cipher; +} + + diff --git a/mbsebbs/encrypt.h b/mbsebbs/encrypt.h new file mode 100644 index 00000000..48feaa89 --- /dev/null +++ b/mbsebbs/encrypt.h @@ -0,0 +1,9 @@ +#ifndef _ENCRYPT_H +#define _ENCRYPT_H + + +char *pw_encrypt(const char *, const char *); + + +#endif + diff --git a/mbsebbs/exitinfo.c b/mbsebbs/exitinfo.c new file mode 100644 index 00000000..4f66be3e --- /dev/null +++ b/mbsebbs/exitinfo.c @@ -0,0 +1,404 @@ +/***************************************************************************** + * + * File ..................: bbs/exitinfo.c + * Purpose ...............: Exitinfo functions + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "oneline.h" +#include "misc.h" +#include "bye.h" +#include "timeout.h" +#include "timecheck.h" +#include "exitinfo.h" + + + +/* + * Copy usersrecord into ~/tmp/.bbs-exitinfo.tty + */ +void InitExitinfo() +{ + FILE *pUsrConfig, *pExitinfo; + char *temp; + long offset; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + + if ((pUsrConfig = fopen(temp,"r+b")) == NULL) { + WriteError("$Can't open %s for writing", temp); + free(temp); + return; + } + + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + offset = usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize); + if(fseek(pUsrConfig, offset, 0) != 0) { + WriteError("$Can't move pointer in %s", temp); + free(temp); + Good_Bye(1); + } + + fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig); + + exitinfo = usrconfig; + fclose(pUsrConfig); + + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + mkdirs(temp); + if ((pExitinfo = fopen(temp, "w+b")) == NULL) + WriteError("$Can't open %s for writing", temp); + else { + fwrite(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + fclose(pExitinfo); + } + free(temp); +} + + + +/* + * Function will re-read users file in memory, so the latest information + * is available to other functions + */ +void ReadExitinfo() +{ + FILE *pExitinfo; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + mkdirs(temp); + if(( pExitinfo = fopen(temp,"r+b")) == NULL) + InitExitinfo(); + else { + fflush(stdin); + fread(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + fclose(pExitinfo); + } + free(temp); +} + + + +/* + * Function will rewrite userinfo from memory, so the latest information + * is available to other functions + */ +void WriteExitinfo() +{ + FILE *pExitinfo; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + if(( pExitinfo = fopen(temp,"w+b")) == NULL) + WriteError("$WriteExitinfo() failed"); + else { + fwrite(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + fclose(pExitinfo); + } + free(temp); +} + + + +/* + * Function to display what users are currently On-Line and what they + * are busy doing + */ +void WhosOn(char *OpData) +{ + FILE *pExitinfo; + DIR *Directory; + char *Heading, *Underline, *temp, *tmp, *device; + struct dirent *Dir; + int i, x; + + Underline = calloc(81, sizeof(char)); + Heading = calloc(81, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + tmp = calloc(PATH_MAX, sizeof(char)); + + WhosDoingWhat(WHOSON); + + clear(); + + Enter(1); + colour(15, 0); + sprintf(Heading, "%s%s", (char *) Language(414), CFG.bbs_name); + Center(Heading); + x = strlen(Heading); + + for(i = 0; i < x; i++) + sprintf(Underline, "%s%c", Underline, exitinfo.GraphMode ? 196 : 45); + + colour(12, 0); + Center(Underline); + + printf("\n"); + + pout(10, 0, (char *) Language(415)); + Enter(1); + + colour(2, 0); + fLine(79); + + sprintf(tmp, "%s/tmp", getenv("MBSE_ROOT")); + if ((Directory = opendir(tmp)) != NULL) + while ((Dir = readdir( Directory )) != NULL) + if((strstr(Dir->d_name, ".bbs-exitinfo.")) != NULL) { + sprintf(temp, "%s/%s", tmp, Dir->d_name); + if(( pExitinfo = fopen(temp, "rb")) != NULL) { + fread(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + + colour(11, 0); + if((strcmp(OpData, "/H")) == 0) { + if((strcmp(exitinfo.sHandle, "") != 0 && *(exitinfo.sHandle) != ' ')) + printf("%-30s", exitinfo.sHandle); + else + printf("%-30s", exitinfo.sUserName); + } else + printf("%-30s", exitinfo.sUserName); + + colour(9, 0); + if((device = strstr(Dir->d_name, "tty")) != NULL) + printf("%-9s", device); + else + printf("%-9s", "None"); + + colour(15, 0); + + /* Browseng */ + if(exitinfo.iStatus == BROWSING) + printf("%-15s", (char *) Language(418)); + + /* Downloading */ + else if(exitinfo.iStatus == DOWNLOAD) + printf("%-15s", (char *) Language(419)); + + /* Uploading */ + else if(exitinfo.iStatus == UPLOAD) + printf("%-15s", (char *) Language(420)); + + /* Msg Section */ + else if(exitinfo.iStatus == READ_POST) + printf("%-15s", (char *) Language(421)); + + /* External Door */ + else if(exitinfo.iStatus == DOOR) + printf("%-15s", (char *) Language(422)); + + /* Chatting */ + else if(exitinfo.iStatus == SYSOPCHAT) + printf("%-15s", (char *) Language(423)); + + /* Listing Files */ + else if(exitinfo.iStatus == FILELIST) + printf("%-15s", (char *) Language(424)); + + /* Banking Door */ + else if(exitinfo.iStatus == TIMEBANK) + printf("%-15s", (char *) Language(426)); + + /* Safe Door */ + else if(exitinfo.iStatus == SAFE) + printf("%-15s", (char *) Language(427)); + + /* WhosOn List */ + else if(exitinfo.iStatus == WHOSON) + printf("%-15s", (char *) Language(428)); + + /* Idle */ + else + printf("%s", (char *) Language(429)); + + colour(12, 0); + printf("%-25s\n", exitinfo.sLocation); + + fclose(pExitinfo); + } + } + closedir(Directory); + + ReadExitinfo(); + + colour(2, 0); + fLine(79); + + free(tmp); + free(temp); + free(Underline); + free(Heading); + + printf("\n"); +} + + + +/* + * Function will update users file and and update exitinfo.iStatus + */ +void WhosDoingWhat(int iStatus) +{ + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + exitinfo.iStatus = iStatus; + WriteExitinfo(); + + switch(iStatus) { + case BROWSING: + strcpy(temp, "Browsing Menus"); + break; + + case DOWNLOAD: + strcpy(temp, "Downloading"); + break; + + case UPLOAD: + strcpy(temp, "Uploading"); + break; + + case READ_POST: + strcpy(temp, "Read/post Messages"); + break; + + case DOOR: + strcpy(temp, "External Door"); + break; + + case SYSOPCHAT: + strcpy(temp, "Sysop Chat"); + break; + + case FILELIST: + strcpy(temp, "List Files"); + break; + + case TIMEBANK: + strcpy(temp, "Time Bank"); + break; + + case SAFE: + strcpy(temp, "Safe Cracker"); + break; + + case WHOSON: + strcpy(temp, "View Whoson List"); + break; + + case OLR: + strcpy(temp, "Offline Reader"); + break; + } + IsDoing(temp); + + free(temp); +} + + + +/* + * Function will allow a user to send a on-line message to another user + * It will prompt the user for the username. The message is sent thru + * mbsed, from the resonse message we can see if we succeeded. + */ +void SendOnlineMsg(char *OpData) +{ + static char buf[128]; + char *User, *String; + + User = calloc(36, sizeof(char)); + String = calloc(77, sizeof(char)); + WhosOn(OpData); + + /* Please enter username to send message to: */ + pout(3, 0, (char *) Language(430)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(User, 35); + if (!strcmp(User, "")) { + free(User); + free(String); + return; + } + + /* Please enter message to send (Max 76 Characters) */ + pout(10, 0, (char *)Language(433)); + pout(10, 0, (char *)"\n> "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(String, 76); + + if ((strcmp(String, "")) != 0) { + buf[0] = '\0'; + sprintf(buf, "CSPM:3,%s,%s,%s;", strcmp(OpData, "/H") != 0 ? exitinfo.sUserName : \ + strcmp(exitinfo.sHandle, "") == 0 ? exitinfo.sUserName : \ + exitinfo.sHandle, User, String); + + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + + if (strncmp(buf, "100:1,3;", 8) == 0) { + /* Sorry, there is no user on */ + printf("\n%s %s\n\n", (char *) Language(431), User); + } + if (strncmp(buf, "100:1,2;", 8) == 0) { + printf("\nNo more room in users message buffer\n\n"); + } + if (strncmp(buf, "100:1,1;", 8) == 0) { + colour(12, 0); + /* doesn't wish to be disturbed */ + printf("\n%s %s\n", User, (char *) Language(432)); + } + if (strncmp(buf, "100:0;", 6) == 0) { + printf("Message Sent!\n"); + Syslog('+', "Online msg to %s: \"%s\"", User, String); + } + } + } + + free(User); + free(String); + Pause(); +} + + diff --git a/mbsebbs/exitinfo.h b/mbsebbs/exitinfo.h new file mode 100644 index 00000000..a4269031 --- /dev/null +++ b/mbsebbs/exitinfo.h @@ -0,0 +1,13 @@ +#ifndef _EXITINFO_H +#define _EXITINFO_H + +void InitExitinfo(void); /* Create exitinfo */ +void ReadExitinfo(void); /* Read Users Config in Memory */ +void WriteExitinfo(void); /* Write Users config from memory */ +void WhosOn(char *); /* What users are currently online */ +void WhosDoingWhat(int); /* Update what user is doing */ +void SendOnlineMsg(char *); /* Send On-Line Message to User */ + + +#endif + diff --git a/mbsebbs/file.c b/mbsebbs/file.c new file mode 100644 index 00000000..dab8d70d --- /dev/null +++ b/mbsebbs/file.c @@ -0,0 +1,2167 @@ +/***************************************************************************** + * + * File ..................: bbs/file.c + * Purpose ...............: All the file functions. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "filesub.h" +#include "file.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "timeout.h" +#include "exitinfo.h" +#include "change.h" + + + +extern long arecno; /* File area number in xxxScan() functions */ +int Strlen = 0; +int FileRecno = 0; + + + +/* + * Show filelist from current area, called from the menu. + */ +void File_List() +{ + FILE *pFile; + int FileCount = 0; + unsigned FileBytes = 0; + _Tag T; + + iLineCount = 0; + WhosDoingWhat(FILELIST); + + Syslog('+', "Listing File Area # %d", iAreaNumber); + + if(Access(exitinfo.Security, area.LTSec) == FALSE) { + colour(14, 0); + /* You don't have enough security to list this area */ + printf("\n%s\n", (char *) Language(236)); + Pause(); + return; + } + + InitTag(); + + if ((pFile = OpenFileBase(iAreaNumber, FALSE)) == NULL) + return; + + clear(); + Header(); + if (iLC(2) == 1) { + fclose(pFile); + return; + } + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + T.Area = iAreaNumber; + T.Active = FALSE; + T.Cost = file.Cost; + T.Size = file.Size; + sprintf(T.File, "%s", file.Name); + SetTag(T); + + if (ShowOneFile() == 1) { + fclose(pFile); + return; + } + + if(file.Deleted) + /* D E L E T E D */ /* Uploaded by: */ + printf("%-15s %s [%ld] %s%s\n", file.Name, (char *) Language(239), file.TimesDL, (char *) Language(238), file.Uploader); + + if(file.Missing) + /* M I S S I N G */ /* Uploaded by: */ + printf("%-15s %s [%ld] %s%s\n", file.Name, (char *) Language(240), file.TimesDL, (char *) Language(238), file.Uploader); + + FileCount++; /* Increase File Counter by 1 */ + FileBytes += file.Size; /* Increase File Byte Count */ + } + + Mark(); + + colour(11,0); + /* Total Files: */ + printf("\n%s%d / %d bytes\n\n", (char *) Language(242), FileCount, FileBytes); + + iLineCount = 0; + fclose(pFile); + Pause(); +} + + + +/* + * Download files already tagged, called from the menu. + */ +void Download(void) +{ + FILE *tf, *fp, *fd; + int i, err, Count = 0; + int OldArea; + char *symTo, *symFrom; + char *temp; + long Size = 0, CostSize = 0; + time_t ElapstimeStart, ElapstimeFin, iTime; + long iTransfer = 0; + + Enter(2); + OldArea = iAreaNumber; + WhosDoingWhat(DOWNLOAD); + unlink("./tag/filedesc.txt"); + + if ((tf = fopen("taglist", "r+")) == NULL) { + /* No files marked for download. */ + pout(12, 0, (char *) Language(258)); + Enter(2); + Pause(); + return; + } + + symTo = calloc(PATH_MAX, sizeof(char)); + symFrom = calloc(PATH_MAX, sizeof(char)); + colour(13, 0); + /* Checking your marked downloads, please wait... */ + printf("%s\n\n", (char *) Language(255)); + + ReadExitinfo(); + while (fread(&Tag, sizeof(Tag), 1, tf) == 1) { + if (Tag.Active) { + + SetFileArea(Tag.Area); + + /* + * Check password for selected file + */ + memset(&file, 0, sizeof(file)); + if ((fp = OpenFileBase(Tag.Area, FALSE)) != NULL) { + + while (fread(&file, sizeof(file), 1, fp) == 1) { + if (strcmp(file.Name, Tag.File) == 0) + break; + } + fclose(fp); + } + + if (strcmp(file.Name, Tag.File) == 0) { + Syslog('b', "Found file %s in area %d", file.Name, Tag.Area); + if ((file.Deleted) || (file.Missing)) { + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(248)); + /* Sorry that file is unavailable for download */ + printf("%s (%s)\n", (char *) Language(248), file.Name); + Tag.Active = FALSE; + } + + } + + if (Tag.Active) { + /* + * Create/Append file description list while we're + * busy checking. If the users doesn't want it we + * can unlink it aftwerwards. We also insert CR + * characters to please the poor DOS (M$oft) users. + */ + sprintf(symTo, "./tag/filedesc.%ld", exitinfo.Downloads % 256); + if ((fd = fopen(symTo, "a")) != NULL) { + fprintf(fd, "%s\r\n", file.Name); + for (i = 0; i < 25; i++) { + if (strlen(file.Desc[i]) > 1) + fprintf(fd, " %s\r\n", file.Desc[i]); + } + fprintf(fd, "\r\n"); + fclose(fd); + } + + /* + * Make a symlink to the users download dir. + * First unlink, in case there was an old one. + */ + chdir("./tag"); + unlink(Tag.File); + sprintf(symFrom, "%s", Tag.File); + sprintf(symTo, "%s/%s", sAreaPath, Tag.File); + if (symlink(symTo, symFrom)) { + WriteError("$Can't create symlink %s %s %d", symTo, symFrom, errno); + Tag.Active = FALSE; + } + Home(); + } + + if (!Tag.Active) { + /* + * Update the download active flag in the + * taglist + */ + fseek(tf, - sizeof(Tag), SEEK_CUR); + fwrite(&Tag, sizeof(Tag), 1, tf); + } else { + /* + * Count file and sizes. + */ + Count++; + Size += file.Size; + if ((!file.Free) && (!area.Free)) + CostSize += file.Size; + + } + } + } + + /* + * If anything left to download... + */ + if (!Count) { + fclose(tf); + SetFileArea(OldArea); + unlink("taglist"); + /* No files marked for download */ + pout(12, 0, (char *) Language(258)); + Enter(2); + Pause(); + free(symTo); + free(symFrom); + return; + } + + colour(14, 0); + /* You have */ /* files( */ /* bytes) marked for download */ + printf("%s %d %s%ld %s\n\n", (char *) Language(249), Count, (char *) Language(280), Size, (char *) Language(281)); + + /* + * If user has no default protocol, make sure he has one. + */ + if (!ForceProtocol()) { + SetFileArea(OldArea); + free(symTo); + free(symFrom); + return; + } + + if (!CheckBytesAvailable(CostSize)) { + SetFileArea(OldArea); + free(symTo); + free(symFrom); + return; + } + + Pause(); + + clear(); + /* File(s) : */ + pout(14, 0, (char *) Language(349)); printf("%d\n", Count); + /* Size : */ + pout( 3, 0, (char *) Language(350)); printf("%lu\n", Size); + /* Protocol : */ + pout( 3, 0, (char *) Language(351)); printf("%s\n", sProtName); + + Syslog('+', "Download tagged files start"); + + printf("%s\n\n", sProtAdvice); + fflush(stdout); + fflush(stdin); + + /* HERE WE SHOULD MAKE A DIFFERENCE BETWEEN BATCHING AND NON + * BATCHING PROTOCOLS. + */ + + /* + * Wait a while before download + */ + sleep(2); + time(&ElapstimeStart); + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s ./tag/*", sProtDn); + Syslog('+', "Download command %s", temp); + + /* + * Transfer the files. Set the Client/Server time at the maximum + * time the user has plus 10 minutes. The overall timer 10 seconds + * less. Not a nice but working solution. + */ + alarm_set(((exitinfo.iTimeLeft + 10) * 60) - 10); + Altime((exitinfo.iTimeLeft + 10) * 60); + if ((err = system(temp)) != 0) { + /* + * Only log the error, we might have sent some files + * instead of nothing. + */ + perror(""); + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("Download error %d, prot: %s", err, sProtDn); + } + Altime(0); + alarm_off(); + alarm_on(); + fflush(stdout); + fflush(stdin); + free(temp); + time(&ElapstimeFin); + + /* + * Get time from Before Download and After Download to get + * download time, if the time is zero, it will be one. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + /* + * Checking the successfull sent files, they are missing from + * the ./tag directory. Failed files are still there. + */ + colour(11, 0); + /* Updating download counters, please wait ... */ + printf("\r%s\n\n", (char *) Language(352)); + fflush(stdout); + Count = Size = 0; + + if ((tf = fopen("taglist", "r+")) != NULL) { + + while (fread(&Tag, sizeof(Tag), 1, tf) == 1) { + + if (Tag.Active) { + + sprintf(symTo, "./tag/%s", Tag.File); + /* + * If symlink is gone the file is sent. + */ + if ((access(symTo, R_OK)) != 0) { + Syslog('+', "File %s from area %d sent ok", Tag.File, Tag.Area); + Tag.Active = FALSE; + fseek(tf, - sizeof(Tag), SEEK_CUR); + fwrite(&Tag, sizeof(Tag), 1, tf); + + /* + * Update the download counter and the + * last download date. + */ + SetFileArea(Tag.Area); + if ((fp = OpenFileBase(Tag.Area, TRUE)) != NULL) { + while (fread(&file, sizeof(file), 1, fp) == 1) { + if (strcmp(file.Name, Tag.File) == 0) + break; + } + Size += file.Size; + file.TimesDL++; + time(&file.LastDL); + fseek(fp, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, fp); + fclose(fp); + Count++; + } + } else { + Syslog('+', "Failed to sent %s from area %d", Tag.File, Tag.Area); + } + } + } + + } + + /* + * Work out transfer rate in seconds by dividing the + * Size of the File by the amount of time it took to download + * the file. + */ + iTransfer = Size / iTime; + Syslog('+', "Download time %ld seconds (%lu cps), %d files", iTime, iTransfer, Count); + + + /* + * Update the users record. + */ + ReadExitinfo(); + + exitinfo.Downloads += Count; /* Increase download counter */ + exitinfo.DownloadK += (Size / 1024); /* Increase amount download today */ + + /* + * Minus the amount downloaded today from downloadktoday + * if less than zero, it won't let the user download anymore. + */ + exitinfo.DownloadKToday -= (Size / 1024); + exitinfo.iTransferTime = iTransfer; + + WriteExitinfo(); + Pause(); + SetFileArea(OldArea); + free(symTo); + free(symFrom); +} + + + +/* + * Show Raw directory + */ +void File_RawDir(char *OpData) +{ + DIR *dirp; + char *FileName, *temp; + int iFileCount = 0; + int LineCount = 2; + int iBytes = 0; + struct dirent *dp; + struct stat statfile; + + FileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + if((strcmp(OpData, "/F")) == 0) + strcpy(temp, sAreaPath); + else + strcpy(temp, OpData); + + if ((dirp = opendir(temp)) == NULL) { + clear(); + WriteError("$RawDir: Can't open dir: %s", temp); + printf("\nCan't open directory for raw listing!\n\n"); + Pause(); + } else { + clear(); + colour(CFG.HiliteF, CFG.HiliteB); + /* Filename Size Date */ + printf("%s\n", (char *) Language(261)); + fLine(42); + + while ((dp = readdir( dirp )) != NULL ) { + sprintf(FileName, "%s/%s", temp, dp->d_name); + + if (*(dp->d_name) != '.') { + iFileCount++; + if(stat(FileName,&statfile) != 0) + printf("Can't stat file %s\n",FileName); + iBytes += statfile.st_size; + + colour(14,0); + printf("%-20s", dp->d_name); + + colour(13,0); + printf("%-12ld", statfile.st_size); + + colour(10,0); + printf("%-10s\n", StrDateDMY(statfile.st_mtime)); + + LineCount++; + if (LineCount == exitinfo.iScreenLen) { + Pause(); + LineCount = 0; + } + } + } + + colour(CFG.HiliteF, CFG.HiliteB); + fLine(42); + /* Total Files: */ /* Bytes */ + printf("%s %d, %d %s\n\n", (char *) Language(242), iFileCount, iBytes, (char *) Language(354)); + + Pause(); + closedir(dirp); + } + free(temp); + free(FileName); +} + + + +/* + * Search for keyword, called from menu. + */ +int KeywordScan() +{ + FILE *pAreas, *pFile; + int i, z, y, Found, Count = 0; + char *Name; + char *tmpname; + char *BigDesc; + char temp[81]; + _Tag T; + unsigned long OldArea; + + + Name = calloc(81, sizeof(char)); + tmpname = calloc(81, sizeof(char)); + BigDesc = calloc(1230, sizeof(char)); + OldArea = iAreaNumber; + + iLineCount = 2; /* Reset Line Counter to Zero */ + arecno = 1; /* Reset Area Number to One */ + + Enter(2); + /* Enter keyword to use for Search: */ + pout(11, 0, (char *) Language(267)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(Name, 80); + + if((strcmp(Name, "")) == 0) + return 0; + + strcpy(tmpname, tl(Name)); + strcpy(Name, ""); + y = strlen(tmpname); + for (z = 0; z < y; z++) { + if (tmpname[z] != '*') { + sprintf(temp, "%c", tmpname[z]); + strcat(Name, temp); + } + } + Syslog('+', "KeywordScan(): \"%s\"", Name); + + clear(); + /* File search by keyword */ + pout(15, 0, (char *) Language(268)); + Enter(1); + InitTag(); + + for(i = 0; i < 25; i++) + sprintf(BigDesc, "%s%s", BigDesc, *(file.Desc + i)); + + if ((pAreas = OpenFareas(FALSE)) == NULL) + return 0; + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) { + + if ((pFile = OpenFileBase(arecno, FALSE)) != NULL) { + + Nopper(); + Found = FALSE; + Sheader(); + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + for(i = 0; i < 25; i++) + sprintf(BigDesc, "%s%s", BigDesc, *(file.Desc + i)); + + if ((strstr(file.Name,Name) != NULL) || (strstr(tl(BigDesc), Name) != NULL)) { + + if (!Found) { + Enter(2); + if (iLC(2) == 1) { + free(BigDesc); + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + Found = TRUE; + } + + T.Area = arecno; + T.Active = FALSE; + T.Cost = file.Cost; + T.Size = file.Size; + sprintf(T.File, "%s", file.Name); + SetTag(T); + Count++; + if (ShowOneFile() == 1) { + free(BigDesc); + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + } + strcpy(BigDesc, ""); /* Clear BigDesc */ + + } /* while */ + + fclose(pFile); + if (Found) { + Enter(2); + if (iLC(2) == 1) { + free(BigDesc); + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + } + + } /* End check for LTSec */ + } /* if access */ + arecno++; /* Go to next file area */ + } /* End of Main */ + + Syslog('+', "Found %d files", Count); + free(BigDesc); + free(Name); + free(tmpname); + fclose(pAreas); + printf("\n"); + if (Count) + Mark(); + else + Pause(); + SetFileArea(OldArea); + return 1; +} + + + +/* + * Search for a file, called from the menu. + */ +int FilenameScan() +{ + FILE *pAreas, *pFile; + int z, y, Found, Count = 0; + char *Name; + char *tmpname; + char temp[81]; + _Tag T; + unsigned long OldArea; + + Name = calloc(81, sizeof(char)); + tmpname = calloc(81, sizeof(char)); + OldArea = iAreaNumber; + + iLineCount = 2; /* Reset Line Counter to Zero */ + arecno = 1; /* Reset Area Number to One */ + + Enter(2); + /* Accepts wildcards such as : *.zip, *.gz, .tar */ + pout(15, 0, (char *) Language(269)); + Enter(1); + /* : *.zip is the same as .zip */ + pout(15, 0, (char *) Language(270)); + + Enter(2); + /* Enter filename to search for : */ + pout(11, 0, (char *) Language(271)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(Name, 80); + + if ((strcmp(Name, "")) == 0) { + free(tmpname); + free(Name); + return 0; + } + + /* + * If there is a file extension, strip it off, it are mostly + * archiver extensions, and who knows what we're using as + * archiver. + */ + if (strchr(Name, '.') != NULL) + strcpy(tmpname, strtok(Name, ".")); + else + strcpy(tmpname, tl(Name)); + strcpy(Name, ""); + y = strlen(tmpname); + for(z = 0; z < y; z++) { + if(tmpname[z] != '*') { + sprintf(temp, "%c", tmpname[z]); + strcat(Name, temp); + } + } + Syslog('+', "FilenameScan(): \"%s\"", Name); + + clear(); + /* File Search by Filename */ + pout(15, 0, (char *) Language(272)); + Enter(1); + InitTag(); + + if ((pAreas = OpenFareas(FALSE)) == NULL) + return 0; + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) { + + if ((pFile = OpenFileBase(arecno, FALSE)) != NULL) { + + Found = FALSE; + Sheader(); + Nopper(); + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + strcpy(tmpname, tl(file.Name)); + if ((strstr(tmpname, Name)) != NULL) { + if (!Found) { + Enter(2); + if (iLC(2) == 1) { + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + Found = TRUE; + } + + T.Area = arecno; + T.Active = FALSE; + T.Cost = file.Cost; + T.Size = file.Size; + sprintf(T.File, "%s", file.Name); + SetTag(T); + Count++; + if (ShowOneFile() == 1) { + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + } + + } /* End of while */ + + fclose(pFile); + if (Found) { + Enter(2); + if (iLC(2) == 1) { + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + } + + } /* End Check for LTSec */ + } /* if access */ + arecno++; /* Go to next file area */ + + } /* End of Main */ + + Syslog('+', "Found %d files", Count); + fclose(pAreas); + free(Name); + free(tmpname); + printf("\n"); + if (Count) + Mark(); + else + Pause(); + SetFileArea(OldArea); + return 1; +} + + + +/* + * Scan for new files, called from menu. + */ +int NewfileScan(int AskStart) +{ + FILE *pAreas, *pFile; + long ifDate, itDate; + char *temp, *Date; + int Found, Count = 0; + _Tag T; + + Date = calloc(81, sizeof(char)); + temp = calloc(81, sizeof(char)); + + iLineCount = 2; + arecno = 1; /* Reset Area Number to One */ + + if (AskStart) { + Enter(2); + /* Search for new since your last call [Y/n]: */ + pout(11, 0, (char *) Language(273)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + + if (toupper(Getone()) == Keystroke(273, 1)) { + Enter(1); + /* Enter new date to search for [DD-MM-YYYY]: */ + pout(2, 0, (char *) Language(274)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetDate(temp, 10); + } else + strcpy(temp, LastLoginDate); + } else + strcpy(temp, LastLoginDate); + + Syslog('+', "NewfileScan() since %s", temp); + clear(); + /* File Search by Date */ + pout(15, 0, (char *) Language(275)); + Enter(2); + + Date[0] = temp[6]; /* Swap the date around */ + Date[1] = temp[7]; /* Instead of DD-MM-YYYY */ + Date[2] = temp[8]; /* Let it equal YYYYMMDD */ + Date[3] = temp[9]; /* Swap the date around */ + Date[4] = temp[3]; /* Swap the date around */ + Date[5] = temp[4]; /* because when you convert */ + Date[6] = temp[0]; /* a string to an int you */ + Date[7] = temp[1]; /* loose the front Zero */ + Date[8] = '\0'; /* making the number smaller */ + itDate = atol(Date); + + InitTag(); + + if ((pAreas = OpenFareas(FALSE)) == NULL) + return 0; + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && + (strlen(area.Password) == 0) && (area.New)) { + + if ((pFile = OpenFileBase(arecno, FALSE)) != NULL ) { + + Sheader(); + Found = FALSE; + Nopper(); + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + strcpy(temp, StrDateDMY(file.UploadDate)); /* Realloc Space for Date */ + Date[0] = temp[6]; /* Swap the date around */ + Date[1] = temp[7]; /* Instead of DD-MM-YYYY */ + Date[2] = temp[8]; /* Let it equal YYYYMMDD */ + Date[3] = temp[9]; /* Swap the date around */ + Date[4] = temp[3]; /* Swap the date around */ + Date[5] = temp[4]; /* because when you convert */ + Date[6] = temp[0]; /* a string to an int you */ + Date[7] = temp[1]; /* loose the front Zero */ + Date[8] = '\0'; /* making the number smaller */ + /* and invalid to this cause */ + ifDate = atol(Date); + + if(ifDate >= itDate) { + if (!Found) { + printf("\n\n"); + if (iLC(2) == 1) { + free(Date); + free(temp); + return 1; + } + Found = TRUE; + } + + T.Area = arecno; + T.Active = FALSE; + T.Cost = file.Cost; + T.Size = file.Size; + sprintf(T.File, "%s", file.Name); + SetTag(T); + + Count++; + if (ShowOneFile() == 1) { + free(Date); + free(temp); + return 1; + } + + } /* End of if */ + } /* End of while */ + + fclose(pFile); + + /* + * Add 2 blank lines after found files. + */ + if (Found) { + printf("\n\n"); + if (iLC(2) == 1) { + free(Date); + free(temp); + return 1; + } + } + + } /* End of open filebase */ + + } /* End of check new files scan */ + arecno++; /* Go to next file area */ + + } /* End of Main */ + + if (Count) + Syslog('+', "Found %d new files", Count); + fclose(pAreas); + printf("\n"); + if (Count) + Mark(); + else + Pause(); + + free(temp); + free(Date); + return 1; +} + + + +/* + * Upload a file. + */ +int Upload() +{ + char File[81], temp[81]; + int Area, x = 0; + int i, err; + unsigned long OldArea; + time_t ElapstimeStart, ElapstimeFin, iTime; + DIR *dirp; + struct dirent *dp; + struct stat statfile; + char *arc; + + + WhosDoingWhat(UPLOAD); + + /* + * Select default protocol if users hasn't any. + */ + if (!ForceProtocol()) + return 0; + + Enter(1); + Area = OldArea = iAreaNumber; + + /* + * If there is a special upload area for the current area + * then select it. + */ + if (area.Upload) + Area = area.Upload; + SetFileArea(Area); + + /* + * Only ask for a filename for non-batching protocols, + * ie. the stone age Xmodem for example. + */ + if (!uProtBatch) { + /* Please enter file to upload: */ + pout(14, 0, (char *) Language(276)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + if((strcmp(File, "")) == 0) + return 0; + + if (*(File) == '.' || *(File) == '*' || *(File) == ' ' || *(File) == '/') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return 0; + } + + Strlen = strlen(File); + Strlen--; + + if (*(File + Strlen) == '.' || *(File + Strlen) == '/' || *(File + Strlen) == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return 0; + } + + if ((!strcmp(File, "files.bbs")) || (!strcmp(File, "00index")) || (strstr(File, (char *)".html"))) { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Syslog('!', "Attempted to upload %s", File); + Pause(); + return 0; + } + + for (i = 0; i < strlen(File); i++) + printf("%d ", File[i]); + + /* + * Check for a space in filename being uploaded + */ + if ((strchr(File, 32)) != NULL) { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return 0; + } + + /* MOET IN ALLE AREAS ZOEKEN */ + if (area.Dupes) { + x = CheckFile(File, Area); + if(x) { + Enter(1); + /* The file already exists on the system */ + pout(15, 3, (char *) Language(282)); + Enter(2); + SetFileArea(OldArea); + Pause(); + return 0; + } + } + SetFileArea(OldArea); + } + + SetFileArea(Area); + Syslog('+', "Upload area is %d %s", Area, area.Name); + + /* + * Check upload access for the real upload directory. + */ + if (!Access(exitinfo.Security, area.UPSec)) { + colour(CFG.HiliteF, CFG.HiliteB); + /* You do not have enough access to upload to this area */ + printf("\n%s\n\n", (char *) Language(278)); + SetFileArea(OldArea); + Pause(); + return 0; + } + + clear(); + colour(CFG.HiliteF, CFG.HiliteB); + /* Please start your upload now ...*/ + printf("\n\n%s, %s\n\n", sProtAdvice, (char *) Language(283)); + if (uProtBatch) + Syslog('+', "Upload using %s", sProtName); + else + Syslog('+', "Upload \"%s\" using %s", File, sProtName); + + sprintf(temp, "%s/%s/upl", CFG.bbs_usersdir, exitinfo.Name); + if (chdir(temp)) { + WriteError("$Can't chdir to %s", temp); + SetFileArea(OldArea); + return 0; + } + + sprintf(temp, "%s", sProtUp); + Syslog('+', "Upload command %s", temp); + fflush(stdout); + fflush(stdin); + sleep(2); + time(&ElapstimeStart); + + /* + * Get the file(s). Set the Client/Server time to 2 hours. + * This is not a nice solution, at least it works and prevents + * that the bbs will hang. + */ + Altime(7200); + alarm_set(7190); + if ((err = system(temp)) != 0) { + /* + * Log any errors + */ + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("$Upload error %d, prot: %s", err, sProtUp); + } + Altime(0); + alarm_off(); + alarm_on(); + printf("\n\n\n"); + fflush(stdout); + fflush(stdin); + time(&ElapstimeFin); + + /* + * Get time from Before Upload and After Upload to get + * upload time, if the time is zero, it will be one. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + Syslog('b', "Transfer time %ld", iTime); + + if ((dirp = opendir(".")) == NULL) { + WriteError("$Upload: can't open ./upl"); + Home(); + SetFileArea(OldArea); + return 1; + } + + Syslog('b', "Start checking uploaded files"); + pout(CFG.UnderlineColourF, CFG.UnderlineColourB, (char *)"\n\nChecking your upload(s)\n\n"); + + while ((dp = readdir(dirp)) != NULL) { + + if (*(dp->d_name) != '.') { + stat(dp->d_name, &statfile); + Syslog('+', "Uploaded \"%s\", %ld bytes", dp->d_name, statfile.st_size); + + if ((arc = GetFileType(dp->d_name)) == NULL) { + /* + * If the filetype is unknown, it is probably + * a textfile or so. Import it direct. + */ + Syslog('b', "Unknown file type"); + ImportFile(dp->d_name, Area, FALSE, iTime, statfile.st_size); + } else { + /* + * We figured out the type of the uploaded file. + */ + Syslog('b', "File type is %s", arc); + + /* + * MS-DOS executables are handled direct. + */ + if ((strcmp("EXE", arc) == 0) || (strcmp("COM", arc) == 0)) { + if (!ScanDirect(dp->d_name)) + ImportFile(dp->d_name, Area, FALSE, iTime, statfile.st_size); + } else { + switch(ScanArchive(dp->d_name, arc)) { + + case 0: + ImportFile(dp->d_name, Area, TRUE, iTime, statfile.st_size); + break; + + case 1: + break; + + case 2: + break; + + case 3: + /* + * No valid unarchiver found, just import + */ + ImportFile(dp->d_name, Area, FALSE, iTime, statfile.st_size); + break; + } + } + } + } + } + closedir(dirp); + + Home(); + SetFileArea(OldArea); + Pause(); + return 1; +} + + + +/* + * Function will download a specific file + */ +int DownloadDirect(char *Name, int Wait) +{ + int err, rc; + char *symTo, *symFrom; + char *temp; + long Size; + time_t ElapstimeStart, ElapstimeFin, iTime; + long iTransfer = 0; + + if ((Size = file_size(Name)) == -1) { + WriteError("No file %s", Name); + colour(CFG.HiliteF, CFG.HiliteB); + printf("File not found\n\n"); + Pause(); + } + + /* + * Make a symlink to the users tmp dir. + */ + symTo = calloc(PATH_MAX, sizeof(char)); + symFrom = calloc(PATH_MAX, sizeof(char)); + sprintf(symFrom, "%s/%s/tmp%s", CFG.bbs_usersdir, exitinfo.Name, strrchr(Name, '/')); + sprintf(symTo, "%s", Name); + + if (symlink(symTo, symFrom)) { + WriteError("$Can't create symlink %s %s", symTo, symFrom); + free(symTo); + free(symFrom); + return FALSE; + } + + /* + * If user has no default protocol, make sure he has one. + */ + if (!ForceProtocol()) { + unlink(symFrom); + free(symTo); + free(symFrom); + return FALSE; + } + + WhosDoingWhat(DOWNLOAD); + ReadExitinfo(); + + clear(); + /* File(s) : */ + pout(14, 0, (char *) Language(349)); printf("%s\n", symFrom); + /* Size : */ + pout( 3, 0, (char *) Language(350)); printf("%lu\n", Size); + /* Protocol : */ + pout( 3, 0, (char *) Language(351)); printf("%s\n", sProtName); + + Syslog('+', "Download direct start %s", Name); + + printf("%s\n\n", sProtAdvice); + fflush(stdout); + fflush(stdin); + + /* + * Wait a while before download + */ + sleep(2); + time(&ElapstimeStart); + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s %s", sProtDn, symFrom); + Syslog('+', "Download command %s", temp); + + /* + * Transfer the file. Set the Client/Server time at the maximum + * time the user has plus 10 minutes. The overall timer 10 seconds + * less. + */ + alarm_set(((exitinfo.iTimeLeft + 10) * 60) - 10); + Altime((exitinfo.iTimeLeft + 10) * 60); + if ((err = system(temp)) != 0) { + /* + * Only log the error, we might have sent some files + * instead of nothing. + */ + perror(""); + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("Download error %d, prot: %s", err, sProtDn); + } + Altime(0); + alarm_off(); + alarm_on(); + fflush(stdout); + fflush(stdin); + free(temp); + time(&ElapstimeFin); + + /* + * Get time from Before Download and After Download to get + * download time, if the time is zero, it will be one. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + if ((access(symFrom, R_OK)) != 0) { + + /* + * Work out transfer rate in seconds by dividing the + * Size of the File by the amount of time it took to download + * the file. + */ + iTransfer = Size / iTime; + Syslog('+', "Download ok, time %ld seconds (%lu cps)", iTime, iTransfer); + + /* + * Update the users record. The file is free, so only statistics. + */ + ReadExitinfo(); + exitinfo.Downloads++; /* Increase download counter */ + exitinfo.iTransferTime = iTransfer; + WriteExitinfo(); + rc = TRUE; + } else { + Syslog('+', "Download failed to sent file"); + unlink(symFrom); + rc = FALSE; + } + if (Wait) + Pause(); + free(symTo); + free(symFrom); + return rc; +} + + + +/* + * Function will list users home directory + */ +void List_Home() +{ + DIR *dirp; + char *FileName, *temp; + int iFileCount = 0; + int iBytes = 0; + struct dirent *dp; + struct stat statfile; + + FileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + iLineCount = 2; + clear(); + sprintf(temp, "%s/%s/wrk", CFG.bbs_usersdir, exitinfo.Name); + + if ((dirp = opendir(temp)) == NULL) { + WriteError("$List_Home: Can't open dir: %s", temp); + /* Can't open directory for listing: */ + printf("\n%s\n\n", (char *) Language(290)); + Pause(); + } else { + colour(1, 7); + /* Home directory listing for */ + printf(" %s", (char *) Language(291)); + colour(4, 7); + printf("%-51s\n", exitinfo.sUserName); + + while ((dp = readdir( dirp )) != NULL ) { + sprintf(FileName, "%s/%s", temp, dp->d_name); + /* + * Check first letter of file for a ".", do not display hidden files + * This includes the current directory and parent directory . & .. + */ + if (*(dp->d_name) != '.') { + iFileCount++; + if(stat(FileName, &statfile) != 0) + WriteError("$Can't stat file %s",FileName); + iBytes += statfile.st_size; + + colour(14,0); + printf("%-20s", dp->d_name); + + colour(13,0); + printf("%-12ld", statfile.st_size); + + colour(10,0); + printf("%s ", StrDateDMY(statfile.st_mtime)); + + colour(11,0); + printf("%s", StrTimeHMS(statfile.st_mtime)); + + printf("\n"); + } + if (iLC(1) == 1) + return; + } + + colour(11,0); + /* Total Files: */ /* Bytes */ + printf("\n\n%s%d / %d %s\n", (char *) Language(242), iFileCount, iBytes, (char *) Language(354)); + + Pause(); + closedir(dirp); + } + + free(temp); + free(FileName); +} + + + +/* + * Delete files from home directory + */ +void Delete_Home() +{ + char *temp, *temp1; + int i; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/%s/wrk/", CFG.bbs_usersdir, exitinfo.Name); + + Enter(1); + /* Please enter filename to delete: */ + pout(9, 0, (char *) Language(292)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(temp1, 80); + + + if(strcmp(temp1, "") == 0) { + free(temp); + free(temp1); + return; + } + + if(temp1[0] == '.') { + Enter(1); + /* Sorry you may not delete hidden files ...*/ + pout(12, 0, (char *) Language(293)); + } else { + strcat(temp, temp1); + + if ((access(temp, R_OK)) == 0) { + colour(10, 0); + /* Delete file: */ /* Are you Sure? [Y/n]: */ + printf("\n%s %s, %s", (char *) Language(368), temp1, (char *) Language(369)); + fflush(stdout); + i = toupper(Getone()); + + if (i == Keystroke(368, 0) || i == 13) { + i = unlink(temp); + + if (i == -1) { + Enter(1); + /* Unable to delete file ... */ + pout(12, 0, (char *) Language(294)); + } else { + Syslog('+', "Delete %s from homedir", temp1); + } + } else { + Enter(2); + /* Aborting ... */ + pout(8, 0, (char *) Language(116)); + } + } else { + Enter(1); + /* Invalid filename, please try again ... */ + pout(12, 0, (char *) Language(295)); + } + + } + + free(temp); + free(temp1); + printf("\n"); + Pause(); +} + + + +/* + * Function allows user to download from his/her home directory + * but still does all the necessary checks + */ +int Download_Home() +{ + char *temp, *File; + struct stat statfile; + int rc; + + File = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + WhosDoingWhat(DOWNLOAD); + + colour(14,0); + /* Please enter filename: */ + printf("\n%s", (char *) Language(245)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + if(( strcmp(File, "")) == 0) { + colour(CFG.HiliteF, CFG.HiliteB); + /* No filename entered, Aborting. */ + printf("\n\n%s\n", (char *) Language(246)); + Pause(); + free(File); + free(temp); + return FALSE; + } + + if( *(File) == '/' || *(File) == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + free(File); + free(temp); + return FALSE; + } + + /* + * Get path for users home directory + */ + sprintf(temp, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, File); + + if (stat(temp, &statfile) != 0) { + Enter(1); + /* File does not exist, please try again ...*/ + pout(12, 0, (char *) Language(296)); + Enter(2); + Pause(); + free(File); + free(temp); + return FALSE; + } + + rc = DownloadDirect(temp, TRUE); + + free(File); + free(temp); + return rc; +} + + + +/* + * Function will upload to users home directory + */ +int Upload_Home() +{ + DIR *dirp; + struct dirent *dp; + char *File, *sFileName, *temp, *arc; + time_t ElapstimeStart, ElapstimeFin, iTime; + int err; + struct stat statfile; + + WhosDoingWhat(UPLOAD); + if (!ForceProtocol()) + return 0; + + File = calloc(PATH_MAX, sizeof(char)); + sFileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + if (!uProtBatch) { + + Enter(1); + /* Please enter file to upload: */ + pout(14, 0, (char *) Language(276)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + if((strcmp(File, "")) == 0) { + free(File); + free(sFileName); + free(temp); + return 0; + } + + if(File[0] == '.' || File[0] == '*' || File[0] == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + free(File); + free(sFileName); + free(temp); + return 0; + } + + Strlen = strlen(File); + Strlen--; + + if(File[Strlen] == '.' || File[Strlen] == '/' || File[Strlen] == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + free(File); + free(sFileName); + free(temp); + return 0; + } + + } + + clear(); + colour(CFG.HiliteF, CFG.HiliteB); + /* Please start your upload now ...*/ + printf("\n\n%s, %s\n\n", sProtAdvice, (char *) Language(283)); + if (uProtBatch) + Syslog('+', "Upload using %s", sProtName); + else + Syslog('+', "Upload \"%s\" using %s", File, sProtName); + + sprintf(temp, "%s/%s/upl", CFG.bbs_usersdir, exitinfo.Name); + if (chdir(temp)) { + WriteError("$Can't chdir to %s", temp); + free(File); + free(sFileName); + free(temp); + return 0; + } + + sprintf(temp, "%s", sProtUp); + Syslog('+', "Upload command %s", temp); + fflush(stdout); + fflush(stdin); + sleep(2); + time(&ElapstimeStart); + + /* + * Get the file(s). Set the Client/Server time to 2 hours. + * This is not a nice solution, at least it works and prevents + * that the bbs will hang. + */ + Altime(7200); + alarm_set(7190); + if ((err = system(temp)) != 0) { + /* + * Log any errors + */ + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("$Upload error %d, prot: %s", err, sProtUp); + } + Altime(0); + alarm_off(); + alarm_on(); + printf("\n\n\n"); + fflush(stdout); + fflush(stdin); + time(&ElapstimeFin); + + /* + * Get time from Before Upload and After Upload to get + * upload time, if the time is zero, it will be one. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + Syslog('b', "Transfer time %ld", iTime); + + if ((dirp = opendir(".")) == NULL) { + WriteError("$Upload: can't open ./upl"); + Home(); + free(File); + free(sFileName); + free(temp); + return 1; + } + + Syslog('b', "Start checking uploaded files"); + pout(CFG.UnderlineColourF, CFG.UnderlineColourB, (char *)"\n\nChecking your upload(s)\n\n"); + + while ((dp = readdir(dirp)) != NULL) { + + if (*(dp->d_name) != '.') { + stat(dp->d_name, &statfile); + Syslog('+', "Uploaded \"%s\", %ld bytes", dp->d_name, statfile.st_size); + + if ((arc = GetFileType(dp->d_name)) == NULL) { + /* + * If the filetype is unknown, it is probably + * a textfile or so. Import it direct. + */ + Syslog('b', "Unknown file type"); + ImportHome(dp->d_name); + } else { + /* + * We figured out the type of the uploaded file. + */ + Syslog('b', "File type is %s", arc); + + /* + * MS-DOS executables are handled direct. + */ + if ((strcmp("EXE", arc) == 0) || (strcmp("COM", arc) == 0)) { + if (!ScanDirect(dp->d_name)) + ImportHome(dp->d_name); + } else { + switch(ScanArchive(dp->d_name, arc)) { + + case 0: + ImportHome(dp->d_name); + break; + + case 1: + break; + + case 2: + break; + + case 3: + /* + * No valid unarchiver found, just import + */ + ImportHome(dp->d_name); + break; + } + } + } + } + } + closedir(dirp); + Home(); + + ReadExitinfo(); + exitinfo.Uploads++; + WriteExitinfo(); + + Pause(); + free(File); + free(sFileName); + free(temp); + return 1; +} + + + +/* + * Select filearea, called from menu. + */ +void FileArea_List(char *Option) +{ + FILE *pAreas; + int iAreaCount = 6, Recno = 1; + int iOldArea, iAreaNum = 0; + int iGotArea = FALSE; /* Flag to check if user typed in area */ + long offset; + char *temp; + + /* + * Save old area, incase he picks a invalid area + */ + iOldArea = iAreaNumber; + if ((pAreas = OpenFareas(FALSE)) == NULL) + return; + + /* + * Count howmany records there are + */ + fseek(pAreas, 0, SEEK_END); + iAreaNum = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + + /* + * If there are menu options, select area direct. + */ + if (strlen(Option) != 0) { + + if (strcmp(Option, "F+") == 0) + while(TRUE) { + iAreaNumber++; + if (iAreaNumber > iAreaNum) + iAreaNumber = 1; + + offset = areahdr.hdrsize + ((iAreaNumber - 1) * areahdr.recsize); + if (fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer here"); + } + + fread(&area, areahdr.recsize, 1, pAreas); + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) + break; + } + + if (strcmp(Option, "F-") == 0) + while(TRUE) { + iAreaNumber--; + if (iAreaNumber < 1) + iAreaNumber = iAreaNum; + + offset = areahdr.hdrsize + ((iAreaNumber - 1) * areahdr.recsize); + if (fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer here"); + } + + fread(&area, areahdr.recsize, 1, pAreas); + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) + break; + } + SetFileArea(iAreaNumber); + Syslog('+', "File area %lu %s", iAreaNumber, sAreaDesc); + fclose(pAreas); + return; + } + + /* + * Interactive mode + */ + clear(); + Enter(1); + /* File Areas */ + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(298)); + Enter(2); + temp = calloc(81, sizeof(char)); + + fseek(pAreas, areahdr.hdrsize, 0); + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available)) { + area.Name[31] = '\0'; + + colour(15,0); + printf("%5d", Recno); + + colour(9,0); + printf(" %c ", 46); + + colour(3,0); + printf("%-31s", area.Name); + + iAreaCount++; + + if ((iAreaCount % 2) == 0) + printf("\n"); + else + printf(" "); + } + + Recno++; + + if ((iAreaCount / 2) == exitinfo.iScreenLen) { + /* More (Y/n/=/Area #): */ + pout(CFG.MoreF, CFG.MoreB, (char *) Language(207)); + /* + * Ask user for Area or enter to continue + */ + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(temp, 7); + + if (toupper(*(temp)) == Keystroke(207, 1)) + break; + + if ((strcmp(temp, "")) != 0) { + iGotArea = TRUE; + break; + } + + iAreaCount = 2; + } + } + + /* + * If user type in area above during area listing + * don't ask for it again + */ + if (!iGotArea) { + Enter(1); + /* Select Area: */ + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(232)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + } + + /* + * Check if user pressed ENTER + */ + if((strcmp(temp, "")) == 0) { + fclose(pAreas); + return; + } + + iAreaNumber = atoi(temp); + + /* + * Do a check in case user enters a negative value + */ + if (iAreaNumber < 1) + iAreaNumber = 1; + + offset = areahdr.hdrsize + ((iAreaNumber - 1) * areahdr.recsize); + if(fseek(pAreas, offset, 0) != 0) + printf("Can't move pointer there."); + else + fread(&area, areahdr.recsize, 1, pAreas); + + /* + * Do a check if area is greater or less number than allowed, + * security access level, is oke, and the area is active. + */ + if (iAreaNumber > iAreaNum || iAreaNumber < 1 || + (Access(exitinfo.Security, area.LTSec) == FALSE) || + (strlen(area.Name) == 0)) { + Enter(1); + /* Invalid area specified - Please try again ...*/ + pout(12, 0, (char *) Language(233)); + Enter(2); + Pause(); + fclose(pAreas); + iAreaNumber = iOldArea; + SetFileArea(iAreaNumber); + free(temp); + return; + } + + SetFileArea(iAreaNumber); + Syslog('+', "File area %lu %s", iAreaNumber, sAreaDesc); + + /* + * Check if file area has a password, if it does ask user for it + */ + if((strlen(area.Password)) > 2) { + Enter(2); + /* Please enter Area Password: */ + pout(15, 0, (char *) Language(299)); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 20); + + if((strcmp(temp, area.Password)) != 0) { + Enter(1); + /* Password is incorrect */ + pout(15, 0, (char *) Language(234)); + Enter(2); + Syslog('!', "Incorrect File Area # %d password given: %s", iAreaNumber, temp); + SetFileArea(iOldArea); + } else { + Enter(1); + /* Password is correct */ + pout(15, 0, (char *) Language(235)); + Enter(2); + } + Pause(); + } + + free(temp); + fclose(pAreas); +} + + + +/* + * Show filelist from current area, called from the menu. + */ +void Copy_Home() +{ + FILE *pFile; + char *File, *temp1, *temp2; + int err, Found = FALSE; + + File = calloc(81, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + temp2 = calloc(PATH_MAX, sizeof(char)); + + colour(14,0); + /* Please enter filename: */ + printf("\n%s", (char *) Language(245)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + if ((strcmp(File, "")) == 0) { + colour(CFG.HiliteF, CFG.HiliteB); + /* No filename entered, Aborting. */ + printf("\n\n%s\n", (char *) Language(246)); + Pause(); + free(File); + free(temp1); + free(temp2); + return; + } + + if (*(File) == '/' || *(File) == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + free(File); + free(temp1); + free(temp2); + return; + } + + if(Access(exitinfo.Security, area.DLSec) == FALSE) { + colour(14, 0); + printf("\n%s\n", (char *) Language(236)); + Pause(); + free(File); + free(temp1); + free(temp2); + return; + } + + if ((pFile = OpenFileBase(iAreaNumber, FALSE)) == NULL) { + free(File); + free(temp1); + free(temp2); + return; + } + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + if (strcmp(File, file.Name) == 0) { + + Found = TRUE; + if (((file.Size + Quota()) > (CFG.iQuota * 1048576))) { + colour(CFG.HiliteF, CFG.HiliteB); + /* You have not enough diskspace free to copy this file */ + printf("%s\n", (char *) Language(279)); + Syslog('+', "Copy homedir, not enough quota"); + } else { + sprintf(temp1, "%s/%s", area.Path, File); + sprintf(temp2, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, File); + colour(CFG.TextColourF, CFG.TextColourB); + /* Start copy: */ + printf("%s%s ", (char *) Language(289), File); + fflush(stdout); + + Syslog('b', "Copy from : %s", temp1); + Syslog('b', "Copy to : %s", temp2); + + if ((err = file_cp(temp1, temp2))) { + colour(CFG.HiliteF, CFG.HiliteB); + /* Failed! */ + printf("%s\n", (char *) Language(353)); + WriteError("Copy %s to homedir failed, code %d", File, err); + } else { + /* Ok */ + printf("%s\n", (char *) Language(200)); + Syslog('+', "Copied %s from area %d to homedir", File, iAreaNumber); + } + } + } + } + fclose(pFile); + + if (!Found) { + colour(CFG.HiliteF, CFG.HiliteB); + /* File does not exist, please try again ... */ + printf("%s\n", (char *) Language(296)); + } + + Pause(); + free(File); + free(temp1); + free(temp2); +} + + + +/* + * Edit the list of tagged files. + */ +void EditTaglist() +{ + FILE *tf; + int i, x, Fg, Count; + char *temp; + + if ((tf = fopen("taglist", "r+")) == NULL) { + colour(CFG.HiliteF, CFG.HiliteB); + /* No files tagged. */ + printf("\n%s\n\n", (char *) Language(361)); + Pause(); + return; + } + + temp = calloc(81, sizeof(char)); + + while (TRUE) { + clear(); + fseek(tf, 0, SEEK_SET); + Count = 0; + colour(CFG.HiliteF, CFG.HiliteB); + /* # Area Active File Size Cost */ + printf("%s\n", (char *) Language(355)); + colour(10, 0); + fLine(48); + + while ((fread(&Tag, sizeof(Tag), 1, tf) == 1)) { + Count++; + + if (Tag.Active) + Fg = 15; + else + Fg = 7; + + colour(Fg, 0); + printf("%3d ", Count); + + Fg--; + colour(Fg, 0); + printf("%5ld ", Tag.Area); + + Fg--; + colour(Fg, 0); + if (Tag.Active) + /* Yes */ + printf("%-6s ", (char *) Language(356)); + else + /* No */ + printf("%-6s ", (char *) Language(357)); + + Fg--; + colour(Fg, 0); + printf("%-14s", Tag.File); + + Fg--; + colour(Fg, 0); + printf(" %8ld", Tag.Size); + + Fg--; + colour(Fg, 0); + printf(" %5d\n", Tag.Cost); + } + colour(10, 0); + fLine(48); + + colour(15, 4); + /* (T)oggle active, (E)rase all, (ENTER) to continue: */ + printf("\n%s", (char *) Language(358)); + fflush(stdout); + fflush(stdin); + + i = toupper(Getone()); + colour(CFG.CRColourF, CFG.CRColourB); + + if (i == Keystroke(358, 0)) { + /* Enter file number, 1.. */ + printf("\n\n%s%d ", (char *) Language(359), Count); + fflush(stdout); + fflush(stdin); + + GetstrC(temp, 5); + x = atoi(temp); + + if ((x > 0) && (x <= Count)) { + if (fseek(tf, (x - 1) * sizeof(Tag), SEEK_SET) == 0) { + if (fread(&Tag, sizeof(Tag), 1, tf) == 1) { + if (Tag.Active) + Tag.Active = FALSE; + else + Tag.Active = TRUE; + + fseek(tf,(x - 1) * sizeof(Tag), SEEK_SET); + fwrite(&Tag, sizeof(Tag), 1, tf); + } + } + } + } + + if (i == Keystroke(358, 1)) { + fclose(tf); + unlink("taglist"); + free(temp); + return; + } + + if ((i == '\r') || (i == '\n')) { + fclose(tf); + free(temp); + return; + } + } +} + + + +/* + * View a file in the current area. + */ +void ViewFile() +{ +} + + diff --git a/mbsebbs/file.h b/mbsebbs/file.h new file mode 100644 index 00000000..14021785 --- /dev/null +++ b/mbsebbs/file.h @@ -0,0 +1,24 @@ +#ifndef _FILE_H +#define _FILE_H + + +void File_RawDir(char *); /* Raw Directory List of a Directory */ +void File_List(void); /* List files in current Area */ +void Download(void); /* Tagged file download */ +int DownloadDirect(char *, int);/* Download a file direct */ +int KeywordScan(void); /* Search a file on a keyword */ +int FilenameScan(void); /* Search a file on filenames */ +int NewfileScan(int); /* Scan for new files */ +int Upload(void); /* Upload a file. */ +void FileArea_List(char *); /* Select file area */ +void SetFileArea(unsigned long);/* Select new area and load globals */ +void EditTaglist(void); /* Edit download taglist */ +void List_Home(void); /* List users home directory */ +void Delete_Home(void); /* Delete file from home directory */ +int Download_Home(void); /* Allows user to download from home dir */ +int Upload_Home(void); /* Allows user to upload to home directory */ +void Copy_Home(void); /* Copy a file to home directory */ +void ViewFile(void); /* View a file in the current area. */ + +#endif + diff --git a/mbsebbs/filesub.c b/mbsebbs/filesub.c new file mode 100644 index 00000000..48af87f3 --- /dev/null +++ b/mbsebbs/filesub.c @@ -0,0 +1,1099 @@ +/***************************************************************************** + * + * File ..................: bbs/filesub.c + * Purpose ...............: All the file sub functions. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "filesub.h" +#include "funcs.h" +#include "language.h" +#include "funcs4.h" +#include "misc.h" +#include "timeout.h" +#include "exitinfo.h" +#include "change.h" + + + +long arecno = 1; /* Area record number */ +int Hcolor = 9; /* Color of area line in xxxScan() functions */ + + +/* + * Variables for file tagging + */ +int Tagnr; +_Tag Tagbuf[100]; + + + +/* + * Reset the tag ringbuffer. + */ +void InitTag() +{ + int i; + + Tagnr = 0; + + for (i = 0; i < 100; i++) { + memset(&Tagbuf[i], 0, sizeof(_Tag)); + } +} + + + +/* + * Add a file in the tag ringbuffer. + */ +void SetTag(_Tag tag) +{ + if (Tagnr < 99) + Tagnr++; + else + Tagnr = 1; + + Tagbuf[Tagnr] = tag; +} + + + +int ForceProtocol() +{ + /* + * If user has no default protocol, make sure he has one. + */ + if (strcmp(sProtName, "") == 0) { + Chg_Protocol(); + + /* + * If the user didn't pick a protocol, quit. + */ + if (strcmp(sProtName, "") == 0) { + return FALSE; + } + } + return TRUE; +} + + + +/* + * Get string, no newline afterwards. + */ +void GetstrD(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + + if ((ttyfd = open ("/dev/tty", O_RDWR)) < 0) { + perror("open 6"); + return; + } + Setraw(); + strcpy(sStr, ""); + + alarm_on(); + while (ch != 13) { + ch = Readkey(); + + if (((ch == 8) || (ch == KEY_DEL) || (ch == 127)) && (iPos > 0)) { + printf("\b \b"); + fflush(stdout); + sStr[--iPos]='\0'; + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + fflush(stdout); + } else + ch=07; + } + } + + Unsetraw(); + close(ttyfd); +} + + + +/* + * Open FileDataBase. + */ +FILE *OpenFileBase(unsigned long Area, int Write) +{ + FILE *pFile; + char *FileBase; + + FileBase = calloc(PATH_MAX, sizeof(char)); + sprintf(FileBase,"%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), Area); + + if (Write) + pFile = fopen(FileBase, "r+"); + else + pFile = fopen(FileBase, "r"); + + if (pFile == NULL) { + WriteError("$Can't open file: %s", FileBase); + /* Can't open file database for this area */ + printf("%s\n\n", (char *) Language(237)); + sleep(2); + } + free(FileBase); + return pFile; +} + + + +/* + * Open the fareas.data file for read or R/W and read the headerrecord. + * The filepointer is at the start of the first record. + */ +FILE *OpenFareas(int Write) +{ + FILE *pAreas; + char *FileArea; + + FileArea = calloc(PATH_MAX, sizeof(char)); + sprintf(FileArea, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if (Write) + pAreas = fopen(FileArea, "r+"); + else + pAreas = fopen(FileArea, "r"); + + if (pAreas == NULL) { + WriteError("$Can't open FileBase %s", FileArea); + /* FATAL: Unable to open areas database */ + printf("%s\n\n", (char *) Language(243)); + sleep(2); + } else + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + free(FileArea); + return pAreas; +} + + + +/* + * Pageheader for filelistings + */ +void Header() +{ + colour(4, 7); + printf(" Area "); + + colour(4, 7); + printf("%-5d ", iAreaNumber); + + colour(1,7); + printf("%-65s\n", sAreaDesc); + + colour(15,0); + fLine(79); +} + + + +/* + * Searchheader for areas during xxxxScan(). + */ +void Sheader() +{ + colour(Hcolor, 0); + printf("\r %-4ld", arecno); + + colour(9, 0); + printf(" ... "); + + colour(Hcolor, 0); + printf("%-40s", area.Name); + fflush(stdout); + + if (Hcolor < 15) + Hcolor++; + else + Hcolor = 9; +} + + + +/* + * Blank current line without newline. + */ +void Blanker(int count) +{ + int i; + + for (i = 0; i < count; i++) + printf("\b"); + + for (i = 0; i < count; i++) + printf(" "); + + printf("\r"); + fflush(stdout); +} + + + +/* + * Mark one or more files for download by putting them into the "taglist" + * in the users homedirectory. Check against dupe tags. + */ +void Mark() +{ + char *temp; + FILE *fp; + int i, Found; + int Count, Size; + + temp = calloc(81, sizeof(char)); + + /* + * First count the already tagged files. + */ + Count = Size = 0; + if ((fp = fopen("taglist", "r")) != NULL) { + while (fread(&Tag, sizeof(Tag), 1, fp) == 1) { + if (Tag.Active) { + Count++; + Size += (Tag.Size / 1024); + } + } + fclose(fp); + } + + colour(CFG.HiliteF, CFG.HiliteB); + /* Marked: */ + printf("%s%d, %dK; ", (char *) Language(360), Count, Size); + + /* Mark file number of press to stop */ + printf("%s", (char *) Language(7)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrD(temp, 10); + Blanker(strlen(Language(7)) + strlen(temp)); + + if (strlen(temp) == 0) { + free(temp); + return; + } + + i = atoi(temp); + + if ((i > 0) && (i < 100)) { + if ((Tagbuf[i].Area) && (strlen(Tagbuf[i].File))) { + if (Access(exitinfo.Security, area.DLSec)) { + if ((fp = fopen("taglist", "a+")) != NULL) { + + fseek(fp, 0, SEEK_SET); + Found = FALSE; + while (fread(&Tag, sizeof(Tag), 1, fp) == 1) + if ((Tag.Area == Tagbuf[i].Area) && (strcmp(Tag.File, Tagbuf[i].File) == 0)) { + Found = TRUE; + Syslog('b', "Tagbuf[i].File already tagged"); + } + + if (!Found) { + memset(&Tag, 0, sizeof(Tag)); + Tag = Tagbuf[i]; + Tag.Active = TRUE; + fwrite(&Tag, sizeof(Tag), 1, fp); + Syslog('+', "Tagged file %s from area %d", Tag.File, Tag.Area); + } + + fclose(fp); + } + } else { + colour(12, 0); + /* You do not have enough access to download from this area. */ + printf("%s", (char *) Language(244)); + fflush(stdout); + sleep(3); + Blanker(strlen(Language(244))); + } + } + } + + free(temp); +} + + + +/* + * More prompt, returns 1 if user decides not to look any further. + */ +int iLC(int Lines) +{ + int x, z; + + x = strlen(Language(131)); + iLineCount += Lines; + + if ((iLineCount >= exitinfo.iScreenLen) && (iLineCount < 1000)) { + iLineCount = 0; + + while(TRUE) { + /* More (Y/n/=) M=Mark */ + pout(CFG.MoreF, CFG.MoreB, (char *) Language(131)); + + fflush(stdout); + alarm_on(); + z = toupper(Getone()); + Blanker(x); + + if (z == Keystroke(131, 1)) { + printf("\n"); + return 1; + } + + if (z == Keystroke(131, 2)) { + iLineCount = 1000; + return 0; + } + + if ((z == Keystroke(131, 0)) || (z == '\r') || (z == '\n')) { + return 0; + } + + if (z == Keystroke(131, 3)) { + Mark(); + } + } + } + return 0; +} + + + +/* + * Show one file, return 1 if user wants to stop, 0 to show next file. + */ +int ShowOneFile() +{ + int y, z, fg, bg; + + if ((!file.Deleted) && (!file.Missing)) { + + colour(7, 0); + printf(" %02d ", Tagnr); + + colour(CFG.FilenameF, CFG.FilenameB); + if(strlen(file.Name) < 25) + printf("%-15s", file.Name); + else { + printf("%-75s", file.Name); + if (iLC(1) == 1) + return 1; + } + + colour(CFG.FilesizeF, CFG.FilesizeB); + if(strlen(file.Name) < 25) + printf("%10lu ", file.Size); + else + printf("%25lu ", file.Size); + + colour(CFG.FiledateF, CFG.FiledateB); + printf("%-10s ", StrDateDMY(file.UploadDate)); + + colour(12, 0); + if(file.TimesDL < 10) + printf(" "); + + if(file.TimesDL < 100) + printf(" "); + + if(file.TimesDL < 1000) + printf(" "); + + if(file.TimesDL > 9999) + file.TimesDL = 9999; + + printf("[%ld] ", file.TimesDL); + + if((strcmp(file.Uploader, "")) == 0) + strcpy(file.Uploader, "SysOp"); + + colour(CFG.HiliteF, CFG.HiliteB); + printf("%s%s\n", (char *) Language(238), file.Uploader); + + if (iLC(1) == 1) + return 1; + + for(z = 0; z <= 25; z++) { + if ((y = strlen(file.Desc[z])) > 1) { + if ((file.Desc[z][0] == '@') && (file.Desc[z][1] == 'X')) { + /* + * Color formatted description lines. + */ + if (file.Desc[z][3] > '9') + fg = (int)file.Desc[z][3] - 55; + else + fg = (int)file.Desc[z][3] - 48; + bg = (int)file.Desc[z][2] - 48; + colour(fg, bg); + printf(" %s\n",file.Desc[z]+4); + } else { + colour(CFG.FiledescF, CFG.FiledescB); + printf(" %s\n",file.Desc[z]); + } + + if (iLC(1) == 1) + return 1; + } + } + } + return 0; +} + + + +int CheckBytesAvailable(long CostSize) +{ + if((exitinfo.DownloadKToday <= 0) || ((CostSize / 1024) > exitinfo.DownloadKToday)) { + + /* You do not have enough bytes to download \" */ + pout(12, 0, (char *) Language(252)); + Enter(1); + Syslog('+', "Not enough bytes to download %ld", CostSize); + + colour(15, 0); + /* You must upload before you can download. */ + pout(12, 0, (char *) Language(253)); + Enter(2); + + colour(14, 0); + /* Kilobytes currently available: */ + printf("%s%lu Kbytes.\n\n", (char *) Language(254), exitinfo.DownloadKToday); + + Pause(); + return FALSE; + } + + return TRUE; +} + + + +/* + * Change back to users homedir. + */ +void Home() +{ + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/%s", CFG.bbs_usersdir, exitinfo.Name); + chdir(temp); + free(temp); +} + + + +/* + * Scan a .COM or .EXE file in users upload directory. + */ +int ScanDirect(char *fn) +{ + FILE *fp; + int err, Found = FALSE; + char *temp, *temp1; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/%s/upl/%s", CFG.bbs_usersdir, exitinfo.Name, fn); + sprintf(temp1, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp1, "r")) != NULL) { + fread(&virscanhdr, sizeof(virscanhdr), 1, fp); + + while (fread(&virscan, virscanhdr.recsize, 1, fp) == 1) { + + sprintf(temp1, "%s %s %s >/dev/null", virscan.scanner, virscan.options, temp); + colour(CFG.TextColourF, CFG.TextColourB); + /* Scanning */ /* with */ + printf("%s %s %s %s ", (char *) Language(132), fn, (char *) Language(133), virscan.comment); + fflush(stdout); + Syslog('b', "%s ", temp1); + + if ((err = system(temp1))) { + Syslog('?', "VIRUS ALERT: Result %d", err); + colour(CFG.HiliteF, CFG.HiliteB); + /* Possible VIRUS found! */ + printf("%s\n", (char *) Language(199)); + Found = TRUE; + } else + /* Ok */ + printf("%s\n", (char *) Language(200)); + fflush(stdout); + } + fclose(fp); + } + + free(temp); + free(temp1); + return Found; +} + + + +/* + * Scan archive using users ./tmp directory. + * Return codes: + * 0 - All seems well + * 1 - Error unpacking archive + * 2 - Possible virus found + * 3 - Not a known archive format. + */ +int ScanArchive(char *fn, char *ftype) +{ + FILE *fp; + int err, Found = FALSE; + char *temp; + char *cwd = NULL; + + + /* + * First search for the right archiver program + */ + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + free(temp); + return 3; + } + + fread(&archiverhdr, sizeof(archiverhdr), 1, fp); + + while (fread(&archiver, archiverhdr.recsize, 1, fp) == 1) { + if ((strcmp(ftype, archiver.name) == 0) && (archiver.available)) { + break; + } + } + fclose(fp); + if ((strcmp(ftype, archiver.name)) || (!archiver.available)) { + free(temp); + return 3; + } + + Syslog('b', "Archiver %s", archiver.comment); + + cwd = getcwd(cwd, 80); + Syslog('b', "Current directory is %s", cwd); + + sprintf(temp, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + if (chdir(temp)) { + WriteError("$Can't chdir(%s)", temp); + free(temp); + return 1; + } + + colour(CFG.TextColourF, CFG.TextColourB); + /* Unpacking archive */ + printf("%s %s ", (char *) Language(201), fn); + fflush(stdout); + sprintf(temp, "%s %s/%s >/dev/null", archiver.funarc, cwd, fn); + Syslog('b', "Unarc %s", temp); + + if ((err = system(temp))) { + WriteError("$Failed %s", temp); + system("rm -f -r *"); + chdir(cwd); + free(cwd); + colour(CFG.HiliteF, CFG.HiliteB); + /* ERROR */ + printf("%s\n", (char *) Language(217)); + fflush(stdout); + return 1; + } + /* Ok */ + printf("%s\n", (char *) Language(200)); + fflush(stdout); + + sprintf(temp, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r")) != NULL) { + fread(&virscanhdr, sizeof(virscanhdr), 1, fp); + + while (fread(&virscan, virscanhdr.recsize, 1, fp) == 1) { + + sprintf(temp, "%s %s * >/dev/null", virscan.scanner, virscan.options); + colour(CFG.TextColourF, CFG.TextColourB); + /* Scanning */ /* with */ + printf("%s %s %s %s ", (char *) Language(132), fn, (char *) Language(133), virscan.comment); + fflush(stdout); + Syslog('b', "%s ", temp); + + if ((err = system(temp))) { + Syslog('?', "VIRUS ALERT: Result %d", err); + colour(CFG.HiliteF, CFG.HiliteB); + /* Possible VIRUS found! */ + printf("%s\n", (char *) Language(199)); + Found = TRUE; + } else + /* Ok */ + printf("%s\n", (char *) Language(200)); + fflush(stdout); + } + fclose(fp); + } + + system("rm -f -r *"); + chdir(cwd); + free(cwd); + free(temp); + + if (Found) + return 2; + else + return 0; +} + + + +/* + * Try to find out the type of uploaded file. + */ +char *GetFileType(char *fn) +{ + unsigned char buf[8], dbuf[80]; + FILE *fp; + int i; + + if ((fp = fopen(fn, "r")) == NULL) { + WriteError("$Can't open file %s", fn); + return NULL; + } + + if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) { + WriteError("$Can't read head of file %s", fn); + return NULL; + } + + fclose(fp); + dbuf[0] = '\0'; + + for (i = 0; i < sizeof(buf); i++) + if ((buf[i] >= ' ') && (buf[i] <= 127)) + sprintf((char*)dbuf+strlen(dbuf), " %c", buf[i]); + else + sprintf((char*)dbuf+strlen(dbuf), " %02x", buf[i]); + + Syslog('b', "file head: %s", dbuf); + + /* + * Various expected uploads. Not that the standard MS-DOS archivers + * must return the exact format, ie "ZIP" for PKZIP. These strings + * are tested against the archivers database. Others that aren't + * compressed files are not important, they just pop up in your + * logfiles. + */ + if (memcmp(buf, "PK\003\004", 4) == 0) return (char *)"ZIP"; + if (*buf == 0x1a) return (char *)"ARC"; + if (memcmp(buf+2, "-l", 2) == 0) return (char *)"LZH"; + if (memcmp(buf, "ZOO", 3) == 0) return (char *)"ZOO"; + if (memcmp(buf, "`\352", 2) == 0) return (char *)"ARJ"; + if (memcmp(buf, "Rar!", 4) == 0) return (char *)"RAR"; + if (memcmp(buf, "MZ", 2) == 0) return (char *)"EXE"; + if (memcmp(buf, "\000\000\001\263", 4) == 0) return (char *)"MPEG"; + if (memcmp(buf, "MOVI", 4) == 0) return (char *)"MOVI"; + if (memcmp(buf, "\007\007\007", 3) == 0) return (char *)"CPIO"; + if (memcmp(buf, "\351,\001JAM", 6) == 0) return (char *)"JAM"; + if (memcmp(buf, "SQSH", 4) == 0) return (char *)"SQSH"; + if (memcmp(buf, "UC2\0x1a", 4) == 0) return (char *)"UC2"; + if (memcmp(buf, ".snd", 4) == 0) return (char *)"SND"; + if (memcmp(buf, "MThd", 4) == 0) return (char *)"MID"; + if (memcmp(buf, "RIFF", 4) == 0) return (char *)"WAV"; + if (memcmp(buf, "EMOD", 4) == 0) return (char *)"MOD"; + if (memcmp(buf, "MTM", 3) == 0) return (char *)"MTM"; + if (memcmp(buf, "#/bin/", 6) == 0) return (char *)"UNIX script"; + if (memcmp(buf, "\037\235", 2) == 0) return (char *)"Compressed data"; + if (memcmp(buf, "\037\213", 2) == 0) return (char *)"gzip compress"; + if (memcmp(buf, "\177ELF", 4) == 0) return (char *)"ELF"; + if (memcmp(buf, "%!", 2) == 0) return (char *)"PostScript"; + if (memcmp(buf, "GIF8", 4) == 0) return (char *)"GIF"; + if (memcmp(buf, "\377\330\377\340", 4) == 0) return (char *)"JPEG"; + if (memcmp(buf, "\377\330\377\356", 4) == 0) return (char *)"JPG"; + if (memcmp(buf, "BM", 2) == 0) return (char *)"Bitmap"; + if (memcmp(buf, "%PDF", 4) == 0) return (char *)"PDF"; + if (memcmp(buf, "THNL", 4) == 0) return (char *)"ThumbNail"; + if ((memcmp(buf, "", 6) == 0) || + (memcmp(buf, "", 6) == 0)) return (char *)"HTML"; + + /* + * .COM formats. Should cover about 2/3 of COM files. + */ + if ((*buf == 0xe9) || (*buf == 0x8c) || + (*buf == 0xeb) || (*buf == 0xb8)) return (char *)"COM"; + + return NULL; +} + + + +/* + * Import file in area. Returns TRUE if successfull. + */ +int ImportFile(char *fn, int Area, int fileid, time_t iTime, off_t Size) +{ + char *temp, *temp1; + int i, x; + char *token; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/%s", area.Path, fn); + sprintf(temp1, "%s/%s/upl/%s", CFG.bbs_usersdir, exitinfo.Name, fn); + + Syslog('b', "Move %s to %s", temp1, temp); + if ((file_mv(temp1, temp))) { + WriteError("$Can't move %s to %s", fn, area.Path); + } else { + if (Addfile(fn, Area, fileid)) { + + ReadExitinfo(); + + /* + * If Size is equal to Zero, don't increase file counters else + * Increase file counters if any other size + */ + if (Size) { + exitinfo.Uploads++; + exitinfo.UploadK += (Size / 1024); + exitinfo.UploadKToday += (Size / 1024); + Syslog('b', "Uploads %d, Kb %d, Kb today %d", exitinfo.Uploads, + exitinfo.UploadK, exitinfo.UploadKToday); + + /* + * Give back the user his bytes from the upload + * Work out byte ratio, then give time back to user + */ + strcpy(temp, CFG.sByteRatio); + token = strtok(temp, ":"); + i = atoi(token); + token = strtok(NULL, "\0"); + x = atoi(token); + Size *= i / x; + /* You have */ /* extra download KBytes. */ + printf("%s %ld %s\n", (char *) Language(249), Size / 1024, (char *) Language(250)); + + exitinfo.DownloadKToday += (Size / 1024); + Syslog('b', "DownloadKToday %d", exitinfo.DownloadKToday); + } + + /* + * Give back the user his time that he used to upload + * Work out time ratio, then give time back to user + * Ratio 3:1, Upload time: times by 3 / 1 + */ + strcpy(temp, CFG.sTimeRatio); + token = strtok(temp, ":"); + i = atoi(token); + token = strtok(NULL, "\0"); + x = atoi(token); + + iTime *= i / x; + iTime /= 60; /* Divide Seconds by 60 to give minutes */ + /* You have */ /* extra minutes. */ + printf("%s %ld %s\n", (char *) Language(249), iTime, (char *) Language(259)); + + exitinfo.iTimeLeft += iTime; + + WriteExitinfo(); + return TRUE; + } + } + + free(temp); + free(temp1); + return FALSE; +} + + + +/* + * Add file to the FileDataBase. If fileid is true, then try to + * get the filedescription from FILE_ID.DIZ if it is in the + * archive, else the user must supply the description. + * Returns TRUE is successfull. + */ +int Addfile(char *File, int AreaNum, int fileid) +{ + FILE *id, *pFileDB, *pPrivate; + int err, iDesc = 1, iPrivate = FALSE, GotId = FALSE; + char *Filename, *temp1; + char *Desc[26]; + struct stat statfile; + int i; + char temp[81]; + + Filename = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + + sprintf(Filename, "%s/%s", area.Path, File); + + if ((pFileDB = OpenFileBase(AreaNum, TRUE)) != NULL) { + /* + * Do a physical check of file to see if it exists + * if it fails it will return a zero which will not + * increase his uploads stats + */ + if(stat(Filename, &statfile) != 0) { + + colour(10, 0); + /* Upload was unsuccessful for: */ + printf("\n%s%s\n\n", (char *) Language(284), File); + + fclose(pFileDB); + free(Filename); + free(temp1); + return FALSE; + } + + memset(&file, 0, sizeof(file)); + strcpy(file.Name, File); + sprintf(temp1,"%ld",statfile.st_size); + file.Size = atoi(temp1); + file.FileDate = statfile.st_mtime; + strcpy(file.Uploader, exitinfo.sUserName); + time(&file.UploadDate); + + if(area.PwdUP) { + colour(9,0); + /* Do you want to password protect your upload ? [y/N]: */ + printf("\n%s", (char *) Language(285)); + fflush(stdout); + + if (toupper(Getone()) == Keystroke(285, 0)) { + colour(10, 0); + /* REMEMBER: Passwords are "CaSe SeNsITiVe!" */ + printf("\n%s\n", (char *) Language(286)); + colour(14,0); + /* Password: */ + printf("%s", (char *) Language(8)); + fflush(stdout); + fflush(stdin); + GetstrC(file.Password, 20); + } + } + + if (fileid) { + /* + * The right unarchiver is still in memory, + * get the FILE_ID.DIZ if it exists. + */ + sprintf(temp, "%s %s/%s FILE_ID.DIZ >/dev/null", archiver.iunarc, area.Path, File); + Syslog('b', "%s", temp); + if ((err = system(temp))) { + WriteError("$Unpack error %s", temp); + } else { + Syslog('+', "Found FILE_ID.DIZ"); + GotId = TRUE; + colour(CFG.TextColourF, CFG.TextColourB); + /* Found FILE_ID.DIZ in */ + printf("%s %s\n", (char *) Language(257), File); + fflush(stdout); + } + } + + if (GotId) { + if ((id = fopen("FILE_ID.DIZ", "r")) != NULL) { + /* + * Import FILE_ID.DIZ, format to max. 25 + * lines, 48 chars width. + */ + while ((fgets(temp1, 256, id)) != NULL) { + if (iDesc < 26) { + Striplf(temp1); + temp1[48] = '\0'; + strcpy(file.Desc[iDesc - 1], temp1); + } + iDesc++; + } + } + fclose(id); + unlink("FILE_ID.DIZ"); + } else { + /* + * Ask the user for a description. + */ + for (i = 0; i < 26; i++) + *(Desc + i) = (char *) calloc(49, sizeof(char)); + + colour(12,0); + /* Please enter description of file */ + printf("\n%s %s\n\n", (char *) Language(287), File); + while (TRUE) { + colour(10,0); + printf("%2d> ", iDesc); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + + GetstrC(*(Desc + iDesc), 48); + + if((strcmp(*(Desc + iDesc), "")) == 0) + break; + + iDesc++; + + if(iDesc >= 26) + break; + } + + for(i = 1; i < iDesc; i++) + strcpy(file.Desc[i - 1], Desc[i]); + + for (i = 0; i < 26; i++) + free(Desc[i]); + } + + fseek(pFileDB, 0, SEEK_END); + fwrite(&file, sizeof(file), 1, pFileDB); + fclose(pFileDB); + + sprintf(temp, "%s/log/uploads.log", getenv("MBSE_ROOT")); + if ((pPrivate = fopen(temp, "a+")) == NULL) + WriteError("$Can't open %s", temp); + else { + iPrivate = TRUE; + fprintf(pPrivate, "****************************************************"); + fprintf(pPrivate, "\nUser : %s", file.Uploader); + fprintf(pPrivate, "\nFile : %s", file.Name); + fprintf(pPrivate, "\nSize : %lu", file.Size); + fprintf(pPrivate, "\nUpload Date : %s\n\n", StrDateDMY(file.UploadDate)); + + for(i = 0; i < iDesc - 1; i++) + fprintf(pPrivate, "%2d: %s\n", i, file.Desc[i]); + + fclose(pPrivate); + } + + Enter(1); + /* Your upload time has been returned to you. Thank you for your upload! */ + pout(10, 0, (char *) Language(288)); + Enter(1); + } + + free(Filename); + free(temp1); + return TRUE; +} + + + +/* + * Set file area number, set global area description and path. + */ +void SetFileArea(unsigned long AreaNum) +{ + FILE *pArea; + long offset; + + memset(&area, 0, sizeof(area)); + + if ((pArea = OpenFareas(FALSE)) == NULL) + return; + + offset = areahdr.hdrsize + ((AreaNum - 1) * areahdr.recsize); + if (fseek(pArea, offset, 0) != 0) { + WriteError("$Seek error in fareas.data, area %ld", AreaNum); + return; + } + + fread(&area, areahdr.recsize, 1, pArea); + strcpy(sAreaDesc, area.Name); + strcpy(sAreaPath, area.Path); + iAreaNumber = AreaNum; + fclose(pArea); +} + + + +unsigned long Quota() +{ + DIR *dirp; + char *FileName, *temp; + unsigned long Bytes = 0; + struct dirent *dp; + struct stat statfile; + + FileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/%s/wrk", CFG.bbs_usersdir, exitinfo.Name); + + if ((dirp = opendir(temp)) == NULL) { + WriteError("$Can't open dir %s", temp); + } else { + while ((dp = readdir(dirp)) != NULL) { + sprintf(FileName, "%s/%s", temp, dp->d_name); + + if (*(dp->d_name) != '.') + if (stat(FileName, &statfile) == 0) + Bytes += statfile.st_size; + } + + closedir(dirp); + } + + free(FileName); + free(temp); + return Bytes; +} + + + +void ImportHome(char *fn) +{ + char *temp1, *temp2; + + temp1 = calloc(PATH_MAX, sizeof(char)); + temp2 = calloc(PATH_MAX, sizeof(char)); + sprintf(temp1, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, fn); + sprintf(temp2, "%s/%s/upl/%s", CFG.bbs_usersdir, exitinfo.Name, fn); + + Syslog('+', "Move %s to home, result %d", fn, file_mv(temp2, temp1)); + free(temp1); + free(temp2); +} + + diff --git a/mbsebbs/filesub.h b/mbsebbs/filesub.h new file mode 100644 index 00000000..bcc2ee16 --- /dev/null +++ b/mbsebbs/filesub.h @@ -0,0 +1,28 @@ +#ifndef _FILESUB_H +#define _FILESUB_H + + +FILE *OpenFileBase(unsigned long Area, int); +FILE *OpenFareas(int); +int ForceProtocol(void); +int CheckBytesAvailable(long); +int iLC(int); +void Header(void); +void Sheader(void); +int ShowOneFile(void); +int Addfile(char *, int, int); +void InitTag(void); +void SetTag(_Tag); +void Blanker(int); +void GetstrD(char *, int); +void Mark(void); +int UploadB_Home(char *); +char *GetFileType(char *); +void Home(void); +int ScanDirect(char *); +int ScanArchive(char *, char *); +int ImportFile(char *, int, int, time_t, off_t); +unsigned long Quota(void); +void ImportHome(char *); + +#endif diff --git a/mbsebbs/fsedit.c b/mbsebbs/fsedit.c new file mode 100644 index 00000000..ecd0887c --- /dev/null +++ b/mbsebbs/fsedit.c @@ -0,0 +1,753 @@ +/***************************************************************************** + * + * File ..................: bbs/fsedit.c + * Purpose ...............: FullScreen Message editor. + * Last modification date : 23-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/ansi.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "mail.h" +#include "funcs4.h" +#include "language.h" +#include "timeout.h" +#include "pinfo.h" +#include "fsedit.h" + + +extern int Line; /* Number of lines + 1 */ +extern char *Message[]; /* TEXTBUFSIZE lines of 80 chars */ + +int Row; /* Current row on screen */ +int Col; /* Current column in text and on screen */ +int TopVisible; /* First visible line of text */ +int InsMode; /* Insert mode */ +int CurRow; /* Current row in buffer */ + + + +void Show_Ins(void); +void Show_Ins(void) +{ + locate(1, 70); + colour(YELLOW, BLUE); + if (InsMode) + printf("INS"); + else + printf("OVR"); + fflush(stdout); +} + + + +void Top_Help(void); +void Top_Help() +{ + locate(1,1); + colour(YELLOW, BLUE); + printf("%s", padleft((char *)"Press ESC for menu, other keys is edit text", 80, ' ')); + Show_Ins(); +} + + + +void Top_Menu(void); +void Top_Menu(void) +{ + locate(1,1); + colour(WHITE, RED); + printf("%s", padleft((char *)"(A)bort (H)elp (S)ave - Any other key is continue edit", 80, ' ')); + fflush(stdout); +} + + + +void Ls(int, int); +void Ls(int a, int y) +{ + locate(y, 10); + printf("%c ", a ? 179 : '|'); +} + + + +void Rs(int); +void Rs(int a) +{ + colour(LIGHTGREEN, BLUE); + printf("%c", a ? 179 : '|'); +} + + + +void Ws(int, int); +void Ws(int a, int y) +{ + int i; + + Ls(a, y); + for (i = 0; i < 57; i++) + printf(" "); + Rs(a); +} + + + +void Hl(int, int, char *); +void Hl(int a, int y, char *txt) +{ + Ls(a, y); + colour(WHITE, BLUE); + printf("%s", padleft(txt, 57, ' ')); + Rs(a); +} + + + +void Full_Help(void); +void Full_Help(void) +{ + int a, i; + + a = exitinfo.GraphMode; + + colour(LIGHTGREEN, BLUE); + + /* Top row */ + locate(1, 10); + printf("%c", a ? 213 : '+'); + for (i = 0; i < 58; i++) + printf("%c", a ? 205 : '='); + printf("%c", a ? 184 : '+'); + + Ws(a, 2); + + Ls(a, 3); + colour(YELLOW, BLUE); + printf("%s", padleft((char *)" Editor Help", 57, ' ')); + Rs(a); + + Ws(a, 4); + Hl(a, 5, (char *)"Ctrl-S or LeftArrow - Cursor left"); + Hl(a, 6, (char *)"Ctrl-D or RightArrow - Cursor right"); + Hl(a, 7, (char *)"Ctrl-E or UpArrow - Cursor up"); + Hl(a, 8, (char *)"Ctrl-X or DownArrow - Cursor down"); + Hl(a, 9, (char *)"Ctrl-V or Insert - Insert or Overwrite"); + Hl(a, 10, (char *)"Ctrl-N - Insert line"); + Hl(a, 11, (char *)"Ctrl-Y - Delete line"); + Ws(a, 12); + Hl(a, 13, (char *)"Ctrl-L - Refresh screen"); + Hl(a, 14, (char *)"Ctrl-R - Read from file"); + Ws(a, 15); + + locate(16,10); + printf("%c", a ? 212 : '+'); + for (i = 0; i < 58; i++) + printf("%c", a ? 205 : '='); + printf("%c", a ? 190 : '+'); + fflush(stdout); +} + + + +void Setcursor(void); +void Setcursor(void) +{ + CurRow = Row + TopVisible - 1; + locate(Row + 1, Col); + fflush(stdout); +} + + + +void Beep(void); +void Beep(void) +{ + printf("\007"); + fflush(stdout); +} + + + +/* + * Refresh and rebuild screen in editing mode. + */ +void Refresh(void); +void Refresh(void) +{ + int i, j = 2; + + clear(); + Top_Help(); + locate(j,1); + colour(CFG.TextColourF, CFG.TextColourB); + + for (i = 1; i <= Line; i++) { + if ((i >= TopVisible) && (i < (TopVisible + exitinfo.iScreenLen -1))) { + locate(j, 1); + j++; + printf("%s", Message[i]); + } + } + Setcursor(); +} + + + +void Debug(void); +void Debug(void) +{ + Syslog('B', "Col=%d Row=%d TopVisible=%d Lines=%d CurRow=%d Len=%d", + Col, Row, TopVisible, Line, Row+TopVisible-1, strlen(Message[Row+TopVisible-1])); +} + + + +void GetstrLC(char *, int); +void GetstrLC(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos] = '\0'; + } else + putchar('\007'); + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + printf("\n"); +} + + + +int Fs_Edit() +{ + unsigned char ch; + int i, Changed = FALSE; + char *filname, *tmpname; + FILE *fd; + + Syslog('b', "Entering FullScreen editor"); + clear(); + fflush(stdout); + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + WriteError("$Can't open tty"); + return FALSE; + } + Setraw(); + InsMode = TRUE; + TopVisible = 1; + Col = 1; + Row = 1; + Refresh(); + Debug(); + + while (TRUE) { + Nopper(); + alarm_on(); + ch = Readkey(); + CurRow = Row + TopVisible - 1; + + switch (ch) { + case KEY_ENTER: + Syslog('B', "Enter pressed: Col=%d CurRow=%d Line=%d", Col, CurRow, Line); + Debug(); + if (Col == 1) { + Syslog('B', "Enter at beginning of line"); + for (i = Line; i >= CurRow; i--) { + sprintf(Message[i+1], "%s", Message[i]); + Syslog('B', "-Moving row %d to %d", i, i+1); + Syslog('B', ":%s", Message[i]); + } + Message[i+1][0] = '\0'; + Syslog('B', "-Clearing row %d", i+1); + } else { + for (i = Line; i > CurRow; i--) { + sprintf(Message[i+1], "%s", Message[i]); + Syslog('B', "-Moving row %d to %d", i, i+1); + } + Message[CurRow+1][0] = '\0'; + Syslog('B', "-Clearing row %d", CurRow+1); + if (Col <= strlen(Message[CurRow])) { + Syslog('B', "Enter in middle of line"); + for (i = Col-1; i <= strlen(Message[CurRow]); i++) { + sprintf(Message[CurRow+1], "%s%c", Message[CurRow+1], Message[CurRow][i]); + } + Message[CurRow][Col-1] = '\0'; + } else { + Syslog('B', "Enter at end of line"); + } + } + Line++; + Row++; + Col = 1; + if (Row < (exitinfo.iScreenLen -1)) { + CurRow++; + } else { + Syslog('B', "Scroll down by ENTER"); + Row -= 12; + TopVisible += 12; + } + Refresh(); + Setcursor(); + Debug(); + Changed = TRUE; + break; + + case ('N' - 64): /* Insert line, scroll down */ + Syslog('B', "Insert line"); + Debug(); + for (i = Line; i >= CurRow; i--) + sprintf(Message[i+1], "%s", Message[i]); + Message[CurRow][0] = '\0'; + Line++; + Col = 1; + Refresh(); + Debug(); + Changed = TRUE; + break; + + case ('Y' - 64): /* Erase line, scroll up */ + Syslog('B', "Erase line"); + Debug(); + if (Line == CurRow) { + Syslog('B', "Erasing last line"); + if (Line > 1) { + Message[CurRow][0] = '\0'; + Line--; + if ((Row == 1) && (TopVisible > 12)) { + Row += 12; + TopVisible -= 12; + } else + Row--; + Refresh(); + Setcursor(); + Debug(); + Changed = TRUE; + } else + Beep(); + } else { + Syslog('B', "Erasing line in the middle"); + for (i = CurRow; i < Line; i++) { + sprintf(Message[i], "%s", Message[i+1]); + } + Message[i+1][0] = '\0'; + Line--; + if (Col > strlen(Message[CurRow]) + 1) + Col = strlen(Message[CurRow]) + 1; + Refresh(); + Setcursor(); + Debug(); + Changed = TRUE; + } + break; + + case KEY_UP: + case ('E' - 64): + Syslog('B', "Cursor up"); + if (Row > 1) { + Row--; + CurRow--; + if (Col > strlen(Message[CurRow]) + 1) + Col = strlen(Message[CurRow]) + 1; + Setcursor(); + Debug(); + } else { + if (TopVisible > 12) { + Syslog('B', "Scroll up"); + TopVisible -= 12; + Row += 12; + Refresh(); + Setcursor(); + Debug(); + } else + Beep(); + } + break; + + case KEY_DOWN: + case ('X' - 64): + Syslog('B', "Cursor down"); + Debug(); + if (Row < (Line - TopVisible + 1)) { + if (Row < (exitinfo.iScreenLen -1)) { + Row++; + CurRow++; + if (Col > strlen(Message[CurRow]) + 1) + Col = strlen(Message[CurRow]) + 1; + Setcursor(); + Debug(); + } else { + Syslog('B', "Scroll down"); + Row -= 12; + TopVisible += 12; + Refresh(); + Setcursor(); + Debug(); + } + } else + Beep(); + break; + + case KEY_LEFT: + case ('S' - 64): + Syslog('B', "Cursor left"); + if (Col > 1) { + Col--; + Setcursor(); + Debug(); + } else + Beep(); + break; + + case KEY_RIGHT: + case ('D' - 64): + if (Col <= strlen(Message[CurRow])) { + Col++; + Setcursor(); + Debug(); + } else + Beep(); + break; + + case KEY_DEL: + Syslog('b', "DEL key"); + if (Col <= strlen(Message[CurRow])) { + Syslog('B', "DEL in middle of line"); + Debug(); + Setcursor(); + for (i = Col; i <= strlen(Message[CurRow]); i++) { + Syslog('B', "i=%d", i); + Message[CurRow][i-1] = Message[CurRow][i]; + printf("%c", Message[CurRow][i]); + } + printf(" \b"); + Message[i-1] = '\0'; + Setcursor(); + } else + Beep(); + + /* + * Trap the extra code so it isn't + * inserted in the text + */ + ch = Readkey(); + break; + + case KEY_BACKSPACE: + case KEY_RUBOUT: + Syslog('B', "BS at Col=%d Row=%d CurRow=%d", Col, Row, CurRow); + if (Col == 1 && CurRow == 1) { + Syslog('B', "BS on first character in message"); + Beep(); + } else if (Col == 1) { + if (strlen(Message[CurRow-1]) + strlen(Message[CurRow]) < 75) { + Col = strlen(Message[CurRow-1]) + 1; + strcat(Message[CurRow-1], Message[CurRow]); + for ( i = CurRow; i < Line; i++) + sprintf(Message[i], "%s", Message[i+1]); + Message[i+1][0] = '\0'; + Line--; + Row--; + CurRow--; + Refresh(); + Setcursor(); + Debug(); + Changed = TRUE; + } else Beep(); + } else { + if (Col == strlen(Message[CurRow]) + 1) { + Syslog('B', "BS at end of line"); + Debug(); + printf("\b \b"); + fflush(stdout); + Col--; + Message[CurRow][Col-1] = '\0'; + Changed = TRUE; + } else { + Syslog('B', "BS in middle of line"); + Debug(); + Col--; + Setcursor(); + for (i = Col; i < strlen(Message[CurRow]); i++) { + Syslog('B', "i=%d", i); + Message[CurRow][i-1] = Message[CurRow][i]; + printf("%c", Message[CurRow][i]); + } + printf(" \b"); + Message[CurRow][strlen(Message[CurRow])] = '\0'; + Setcursor(); + Changed = TRUE; + } + } + break; + + case KEY_INS: + case ('V' - 64): + if (InsMode) + InsMode = FALSE; + else + InsMode = TRUE; + Show_Ins(); + colour(CFG.TextColourF, CFG.TextColourB); + Setcursor(); + Syslog('B', "InsertMode now %s", InsMode ? "True" : "False"); + /* + * Trap the extra code so it isn't + * inserted in the text + */ + ch = Readkey(); + break; + + case ('L' - 64): /* Refresh screen */ + Syslog('B', "Refresh()"); + Refresh(); + Debug(); + break; + + case ('R' - 64): /* Read from file */ + Syslog('b', "Read from file"); + + tmpname = calloc(PATH_MAX, sizeof(char)); + filname = calloc(PATH_MAX, sizeof(char)); + + colour(14, 0); + /* Please enter filename: */ + printf("\n%s", (char *) Language(245)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrLC(filname, 80); + + if ((strcmp(filname, "") == 0)) { + colour(CFG.HiliteF, CFG.HiliteB); + /* No filename entered, aborting */ + printf("\n\n%s\n", (char *) Language(246)); + Pause(); + free(filname); + free(tmpname); + Refresh(); + Debug(); + break; + } + + if (*(filname) == '/' || *(filname) == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal filename */ + printf("\n\n%s\n", (char *) Language(247)); + Pause(); + free(tmpname); + free(filname); + Refresh(); + Debug(); + break; + } + + sprintf(tmpname, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, filname); + if ((fd = fopen(tmpname, "r")) == NULL) { + WriteError("$Can't open %s", tmpname); + colour(CFG.HiliteF, CFG.HiliteB); + /* File does not exist, please try again */ + printf("\n\n%s\n", (char *) Language(296)); + Pause(); + } else { + while ((fgets(filname, 80, fd)) != NULL) { + for (i = 0; i < strlen(filname); i++) { + if (*(filname + i) == '\0') + break; + if (*(filname + i) == '\n') + *(filname + i) = '\0'; + if (*(filname + i) == '\r') + *(filname + i) = '\0'; + } + /* + * Make sure that any tear or origin lines are + * made invalid. + */ + if (strncmp(filname, (char *)"--- ", 4) == 0) + filname[1] = 'v'; + if (strncmp(filname, (char *)" * Origin:", 10) == 0) + filname[1] = '+'; + sprintf(Message[Line], "%s", filname); + Line++; + } + fclose(fd); + Changed = TRUE; + Syslog('+', "Inserted file %s", tmpname); + } + + free(tmpname); + free(filname); + Refresh(); + Debug(); + Col = 1; + Setcursor(); + break; + + case KEY_ESCAPE: /* Editor menu */ + Syslog('B', "Escape pressed"); + Top_Menu(); + + ch = toupper(Readkey()); + if (ch == 'A' || ch == 'S') { + Syslog('B', "%s message (%c)", (ch == 'S' && Changed) ? "Saving" : "Aborting", ch); + Unsetraw(); + close(ttyfd); + Debug(); + clear(); + fflush(stdout); + for (i = 1; i <= Line; i++) + Syslog('B', "%3d \"%s\"", i, Message[i]); + if (ch == 'S' && Changed) { + Syslog('+', "Message saved"); + return TRUE; + } else { + Syslog('+', "Message aborted"); + return FALSE; + } + } + + if (ch == 'H') { + Syslog('B', "User wants help"); + Full_Help(); + ch = Readkey(); + Refresh(); + } else + Top_Help(); + + colour(CFG.TextColourF, CFG.TextColourB); + Setcursor(); + break; + + default: + if (ch > 31 && ch < 127) { + /* + * Normal printable characters + */ + Debug(); + if (Col == strlen(Message[CurRow]) + 1) { + /* + * Append to line + */ + if (Col < 79) { + Col++; + sprintf(Message[CurRow], "%s%c", Message[CurRow], ch); + printf("%c", ch); + fflush(stdout); + Changed = TRUE; + } else { + /* + * Do simple word wrap + */ + for (i = Line; i > CurRow; i--) { + sprintf(Message[i+1], "%s", Message[i]); + Syslog('B', "[WW]-Moving row %d to %d", i, i+1); + } + Message[CurRow+1][0] = '\0'; + Syslog('B', "[WW]-Clearing row %d", CurRow+1); + Col = 74; + while (Message[CurRow][Col] != ' ' && i != 0) + Col--; + Col++; + if (Col <= strlen(Message[CurRow])) { + Syslog('B', "[WW]-Move end of line %d to new row %d", CurRow, CurRow+1); + for (i = Col; i <= strlen(Message[CurRow]); i++) { + sprintf(Message[CurRow+1], "%s%c", Message[CurRow+1], Message[CurRow][i]); + } + Message[CurRow][Col-1] = '\0'; + } + sprintf(Message[CurRow+1], "%s%c", Message[CurRow+1], ch); + Line++; + Row++; + Col = strlen(Message[CurRow+1])+1; + Refresh(); + Debug(); + Changed = TRUE; + } + } else { + /* + * Insert or overwrite + */ + Syslog('b', "%s in line", InsMode ? "Insert" : "Overwrite"); + if (InsMode) { + if (strlen(Message[CurRow]) < 80) { + for (i = strlen(Message[CurRow]); i > (Col-1); i--) { + Syslog('B', "(i+1=%d)[%c] = (i=%d)[%c]", i+1, Message[CurRow][i+1], i, Message[CurRow][i]); + Message[CurRow][i+1] = Message[CurRow][i]; + } + Message[CurRow][Col-1] = ch; + Col++; + locate(Row + 1, 1); + printf(Message[CurRow]); + Setcursor(); + Changed = TRUE; + } else { + Beep(); + } + } else { + Message[CurRow][Col-1] = ch; + printf("%c", ch); + fflush(stdout); + Col++; + Changed = TRUE; + } + } + } else + Syslog('b', "Pressed %d (unsupported)", ch); + } + } + + WriteError("FsEdit(): Impossible to be here"); + Unsetraw(); + close(ttyfd); + return FALSE; +} + + diff --git a/mbsebbs/fsedit.h b/mbsebbs/fsedit.h new file mode 100644 index 00000000..f4909be9 --- /dev/null +++ b/mbsebbs/fsedit.h @@ -0,0 +1,7 @@ +#ifndef _FSEDIT_H +#define _FSEDIT_H + +int Fs_Edit(void); /* The fullscreen message editor */ + +#endif + diff --git a/mbsebbs/funcs.c b/mbsebbs/funcs.c new file mode 100644 index 00000000..bd9ac9cc --- /dev/null +++ b/mbsebbs/funcs.c @@ -0,0 +1,1031 @@ +/***************************************************************************** + * + * File ..................: bbs/funcs.c + * Purpose ...............: Misc functions + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "../lib/clcomm.h" +#include "funcs.h" +#include "language.h" +#include "funcs4.h" +#include "oneline.h" +#include "misc.h" +#include "bye.h" +#include "timeout.h" +#include "timecheck.h" +#include "exitinfo.h" +#include "mail.h" +#include "email.h" + + +extern long ActiveMsgs; +extern time_t t_start; + + + +/* + * Security Access Check + */ +int Access(securityrec us, securityrec ref) +{ + Syslog('B', "User %5d %08lx %08lx", us.level, us.flags, ~us.flags); + Syslog('B', "Ref. %5d %08lx %08lx", ref.level, ref.flags, ref.notflags); + + if (us.level < ref.level) + return FALSE; + + if ((ref.notflags & ~us.flags) != ref.notflags) + return FALSE; + + if ((ref.flags & us.flags) != ref.flags) + return FALSE; + + return TRUE; +} + + + +void UserList(char *OpData) +{ + FILE *pUsrConfig; + int LineCount = 2; + int iFoundName = FALSE; + int iNameCount = 0; + char *Name, *sTemp, *User; + char *temp; + struct userhdr uhdr; + struct userrec u; + + temp = calloc(PATH_MAX, sizeof(char)); + Name = calloc(37, sizeof(char)); + sTemp = calloc(81, sizeof(char)); + User = calloc(81, sizeof(char)); + + clear(); + /* User List */ + language(15, 0, 126); + Enter(1); + LineCount = 1; + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp, "rb")) == NULL) { + WriteError("UserList: Can't open file: %s", temp); + return; + } + fread(&uhdr, sizeof(uhdr), 1, pUsrConfig); + + /* Enter Username search string or (Enter) for all users: */ + language(15, 0, 127); + colour(CFG.InputColourF, CFG.InputColourB); + alarm_on(); + GetstrC(Name,35); + clear(); + + /* Name Location Last On Calls */ + language(15, 0, 128); + Enter(1); + + colour(2, 0); + fLine(79); + + colour(3, 0); + while (fread(&u, uhdr.recsize, 1, pUsrConfig) == 1) { + if ((strcmp(Name,"")) != 0) { + if((strcmp(OpData, "/H")) == 0) + sprintf(User, "%s", u.sHandle); + else + sprintf(User, "%s", u.sUserName); + + if ((strstr(tl(User), tl(Name)) != NULL)) { + if ((!u.Hidden) && (!u.Deleted)) { + if((strcmp(OpData, "/H")) == 0) { + if((strcmp(u.sHandle, "") != 0 && *(u.sHandle) != ' ')) + printf("%-25s", u.sHandle); + else + printf("%-25s", u.sUserName); + } else + printf("%-25s", u.sUserName); + + printf("%-30s%-14s%-11d", u.sLocation, StrDateDMY(u.tLastLoginDate), u.iTotalCalls); + iFoundName = TRUE; + LineCount++; + iNameCount++; + } + } + } else + if ((!u.Hidden) && (!u.Deleted) && (strlen(u.sUserName) > 0)) { + if((strcmp(OpData, "/H")) == 0) { + if((strcmp(u.sHandle, "") != 0 && *(u.sHandle) != ' ')) + printf("%-25s", u.sHandle); + else + printf("%-25s", u.sUserName); + } else + printf("%-25s", u.sUserName); + + printf("%-30s%-14s%-11d", u.sLocation, StrDateDMY(u.tLastLoginDate), u.iTotalCalls); + iFoundName = TRUE; + LineCount++; + iNameCount++; + Enter(1); + } + + if (LineCount >= exitinfo.iScreenLen - 2) { + LineCount = 0; + Pause(); + colour(3, 0); + } + } + + if(!iFoundName) { + language(3, 0, 129); + Enter(1); + } + + fclose(pUsrConfig); + + colour(2, 0); + fLine(79); + + free(temp); + free(Name); + free(sTemp); + free(User); + + Pause(); +} + + + +void TimeStats() +{ + clear(); + ReadExitinfo(); + + colour(15, 0); + /* TIME STATISTICS for */ + printf("\n%s%s ", (char *) Language(134), exitinfo.sUserName); + /* on */ + printf("%s %s\n", (char *) Language(135), (char *) logdate()); + + colour(12, 0); + fLine(79); + + printf("\n"); + + colour(10, 0); + + /* Current Time */ + printf("%s %s\n", (char *) Language(136), (char *) GetLocalHMS()); + + /* Current Date */ + printf("%s %s\n\n", (char *) Language(137), (char *) GLCdateyy()); + + /* Connect time */ + printf("%s %d %s\n", (char *) Language(138), exitinfo.iConnectTime, (char *) Language(471)); + + /* Time used today */ + printf("%s %d %s\n", (char *) Language(139), exitinfo.iTimeUsed, (char *) Language(471)); + + /* Time remaining today */ + printf("%s %d %s\n", (char *) Language(140), exitinfo.iTimeLeft, (char *) Language(471)); + + /* Daily time limit */ + printf("%s %d %s\n", (char *) Language(141), exitinfo.iTimeUsed + exitinfo.iTimeLeft, (char *) Language(471)); + + printf("\n"); + Pause(); +} + + + +char *Gdate(time_t, int); +char *Gdate(time_t tt, int Y2K) +{ + static char GLC[15]; + struct tm *tm; + + tm = localtime(&tt); + if (Y2K) + sprintf(GLC, "%02d-%02d-%04d", tm->tm_mon +1, tm->tm_mday, tm->tm_year + 1900); + else + sprintf(GLC, "%02d-%02d-%02d", tm->tm_mon +1, tm->tm_mday, tm->tm_year % 100); + + return (GLC); +} + + + +char *Rdate(char *, int); +char *Rdate(char *ind, int Y2K) +{ + static char GLC[15]; + + memset(&GLC, 0, sizeof(GLC)); + GLC[0] = ind[3]; + GLC[1] = ind[4]; + GLC[2] = '-'; + GLC[3] = ind[0]; + GLC[4] = ind[1]; + GLC[5] = '-'; + if (Y2K) { + GLC[6] = ind[6]; + GLC[7] = ind[7]; + GLC[8] = ind[8]; + GLC[9] = ind[9]; + } else { + GLC[6] = ind[8]; + GLC[7] = ind[9]; + } + + return GLC; +} + + + +/* + * Function will run a external program or door + */ +void ExtDoor(char *Program, int NoDoorsys, int Y2Kdoorsys, int Comport) +{ + char *String, *String1; + int i, rc; + char *temp1; + FILE *fp; + + temp1 = calloc(PATH_MAX, sizeof(char)); + String = calloc(81, sizeof(char)); + + WhosDoingWhat(DOOR); + + if((strstr(Program, "/A")) != NULL) { + colour(3, 0); + if((String = strstr(Program, "/T=")) != NULL) { + String1 = String + 3; + printf("\n%s", String1); + } else + printf("\nPlease enter filename: "); + + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp1, 80); + + strreplace(Program, (char *)"/A", temp1); + + for(i = 0; i < strlen(Program); i++) { + if(*(Program + i) == '\0') + break; + if(*(Program + i) == '/') + *(Program + i) = '\0'; + } + } + + free(String); + Syslog('+', "Door: %s", Program); + ReadExitinfo(); + alarm_set((exitinfo.iTimeLeft * 60) - 10); + Altime((exitinfo.iTimeLeft * 60)); + + /* + * Always remove the old door.sys first. + */ + sprintf(temp1, "%s/%s/door.sys", CFG.bbs_usersdir, exitinfo.Name); + unlink(temp1); + + /* + * Write door.sys in users homedirectory + */ + if (!NoDoorsys) { + if ((fp = fopen(temp1, "w+")) == NULL) { + WriteError("$Can't create %s", temp1); + } else { + if (Comport) { + fprintf(fp, "COM1\r\n"); /* COM port */ + fprintf(fp, "115200\r\n");/* Effective baudrate */ + + } else { + fprintf(fp, "COM0\r\n");/* COM port */ + fprintf(fp, "0\r\n"); /* Effective baudrate */ + } + fprintf(fp, "8\r\n"); /* Databits */ + fprintf(fp, "1\r\n"); /* Node number */ + if (Comport) + fprintf(fp, "115200\r\n");/* Locked baudrate */ + else + fprintf(fp, "%ld\r\n", ttyinfo.portspeed); /* Locked baudrate */ + fprintf(fp, "Y\r\n"); /* Screen display */ + fprintf(fp, "N\r\n"); /* Printer on */ + fprintf(fp, "Y\r\n"); /* Page bell */ + fprintf(fp, "Y\r\n"); /* Caller alarm */ + fprintf(fp, "%s\r\n", exitinfo.sUserName); + fprintf(fp, "%s\r\n", exitinfo.sLocation); + fprintf(fp, "%s\r\n", exitinfo.sVoicePhone); + fprintf(fp, "%s\r\n", exitinfo.sDataPhone); + fprintf(fp, "%s\r\n", exitinfo.Password); + fprintf(fp, "%d\r\n", exitinfo.Security.level); + fprintf(fp, "%d\r\n", exitinfo.iTotalCalls); + fprintf(fp, "%s\r\n", Gdate(exitinfo.tLastLoginDate, Y2Kdoorsys)); + fprintf(fp, "%d\r\n", exitinfo.iTimeLeft * 60); + fprintf(fp, "%d\r\n", exitinfo.iTimeLeft); + fprintf(fp, "GR\r\n"); /* ANSI graphics */ + fprintf(fp, "%d\r\n", exitinfo.iScreenLen); + fprintf(fp, "N\r\n"); /* User mode, always N */ + fprintf(fp, "\r\n"); /* Always blank */ + fprintf(fp, "\r\n"); /* Always blank */ + fprintf(fp, "%s\r\n", Rdate(exitinfo.sExpiryDate, Y2Kdoorsys)); + fprintf(fp, "%d\r\n", grecno); /* Users recordnumber */ + fprintf(fp, "%s\r\n", exitinfo.sProtocol); + fprintf(fp, "%ld\r\n", exitinfo.Uploads); + fprintf(fp, "%ld\r\n", exitinfo.Downloads); + fprintf(fp, "%ld\r\n", LIMIT.DownK); + fprintf(fp, "%ld\r\n", LIMIT.DownK); + fprintf(fp, "%s\r\n", Rdate(exitinfo.sDateOfBirth, Y2Kdoorsys)); + fprintf(fp, "\r\n"); /* Path to userbase */ + fprintf(fp, "\r\n"); /* Path to messagebase */ + fprintf(fp, "%s\r\n", CFG.sysop_name); + fprintf(fp, "%s\r\n", exitinfo.sHandle); + fprintf(fp, "none\r\n"); /* Next event time */ + fprintf(fp, "Y\r\n"); /* Error free connect. */ + fprintf(fp, "N\r\n"); /* Always N */ + fprintf(fp, "Y\r\n"); /* Always Y */ + fprintf(fp, "7\r\n"); /* Default textcolor */ + fprintf(fp, "0\r\n"); /* Always 0 */ + fprintf(fp, "%s\r\n", Gdate(exitinfo.tLastLoginDate, Y2Kdoorsys)); + fprintf(fp, "%s\r\n", StrTimeHM(t_start)); + fprintf(fp, "%s\r\n", LastLoginTime); + fprintf(fp, "32768\r\n"); /* Always 32768 */ + fprintf(fp, "%d\r\n", exitinfo.DownloadsToday); + fprintf(fp, "%ld\r\n", exitinfo.UploadK); + fprintf(fp, "%ld\r\n", exitinfo.DownloadK); + fprintf(fp, "%s\r\n", exitinfo.sComment); + fprintf(fp, "0\r\n"); /* Always 0 */ + fprintf(fp, "%d\r\n", exitinfo.iPosted); + fclose(fp); + } + } + + clear(); + printf("Loading ...\n\n"); + rc = execute((char *)"/bin/sh", (char *)"-c", Program, NULL, NULL, NULL); + + Altime(0); + alarm_off(); + alarm_on(); + Syslog('+', "Door end, rc=%d", rc); + + free(temp1); + printf("\n\n"); + Pause(); +} + + + +/* + * Function will display textfile in either ansi or ascii and + * display control codes if they exist. + * Returns Success if it can display the requested file + */ +int DisplayFile(char *filename) +{ + FILE *pFileName; + long iSec = 0; + char *sFileName, *tmp, *tmp1; + char newfile[PATH_MAX]; + int i, x; + + sFileName = calloc(16385, sizeof(char)); + tmp = calloc(PATH_MAX, sizeof(char)); + tmp1 = calloc(PATH_MAX, sizeof(char)); + + /* + * Open the file in the following search order: + * 1 - if GraphMode -> users language .ans + * 2 - if GraphMode -> default language .ans + * 3 - users language .asc + * 4 - default language .asc + * 5 - Abort, there is no file to show. + */ + pFileName = NULL; + if (exitinfo.GraphMode) { + sprintf(newfile, "%s/%s.ans", lang.TextPath, filename); + if ((pFileName = fopen(newfile, "rb")) == NULL) { + sprintf(newfile, "%s/%s.ans", CFG.bbs_txtfiles, filename); + pFileName = fopen(newfile, "rb"); + } + } + if (pFileName == NULL) { + sprintf(newfile, "%s/%s.asc", lang.TextPath, filename); + if ((pFileName = fopen(newfile, "rb")) == NULL) { + sprintf(newfile, "%s/%s.asc", CFG.bbs_txtfiles, filename); + if ((pFileName = fopen(newfile, "rb")) == NULL) { + free(sFileName); + free(tmp); + free(tmp1); + return FALSE; + } + } + } + + Syslog('B', "Displayfile %s", newfile); + + while (!feof(pFileName)) { + i = fread(sFileName, sizeof(char), 16384, pFileName); + + for(x = 0; x < i; x++) { + switch(*(sFileName + x)) { + case '': + ControlCodeU(sFileName[++x]); + break; + + case '': + ControlCodeF(sFileName[++x]); + break; + + case ' ': + ControlCodeK(sFileName[++x]); + break; + + case '': + fflush(stdout); + fflush(stdin); + alarm_on(); + Getone(); + break; + + case '': + /* + * This code will allow you to specify a security level + * in front of the text, ie ^B32000^Bthis is a test^B + * will print this is a test only if you have security + * above 32000. Only one set of control chars per line. + * You cannot have multiple securitys etc + */ + x++; + strcpy(tmp1, ""); + while (*(sFileName + x) != '') { + sprintf(tmp, "%c", *(sFileName + x)); + strcat(tmp1, tmp); + x++; + } + x++; + iSec = atoi(tmp1); + while ((x <= i) && (*(sFileName + x) != '')) { + if (exitinfo.Security.level >= iSec) + printf("%c", *(sFileName + x)); + x++; + } + break; + + case '': + fflush(stdout); + sleep(1); + break; + + default: + printf("%c", *(sFileName + x)); + + } /* switch */ + } /* for */ + } /* while !eof */ + + fclose(pFileName); + free(sFileName); + free(tmp); + free(tmp1); + return TRUE; +} + + + +int DisplayFileEnter(char *File) +{ + int rc; + + rc = DisplayFile(File); + Enter(1); + /* Press ENTER to continue */ + language(13, 0, 436); + fflush(stdout); + fflush(stdin); + alarm_on(); + Getone(); + return rc; +} + + + +int CheckFile(char *File, int iArea) +{ + FILE *pFileB; + int iFile = FALSE; + char *sFileArea; + + sFileArea = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileArea,"%s/fdb/fdb%d.dta", getenv("MBSE_ROOT"), iArea); + + if(( pFileB = fopen(sFileArea,"r+")) == NULL) { + mkdir(sFileArea, 755); + return FALSE; + } + + while ( fread(&file, sizeof(file), 1, pFileB) == 1) { + if((strcmp(tl(file.Name), tl(File))) == 0) { + iFile = TRUE; + fclose(pFileB); + return TRUE; + } + + } + + fclose(pFileB); + free(sFileArea); + + if(!iFile) + return FALSE; + return 1; +} + + + +void ControlCodeF(int ch) +{ + /* Update user info */ + ReadExitinfo(); + + switch (toupper(ch)) { + case '!': + printf(exitinfo.sProtocol); + break; + case 'A': + printf("%ld", exitinfo.Uploads); + break; + + case 'B': + printf("%ld", exitinfo.Downloads); + break; + + case 'C': + printf("%lu", exitinfo.DownloadK); + break; + + case 'D': + printf("%lu", exitinfo.UploadK); + break; + + case 'E': + printf("%lu", exitinfo.DownloadK + exitinfo.UploadK); + break; + + case 'F': + printf("%lu", LIMIT.DownK); + break; + + case 'G': + printf("%d", exitinfo.iTransferTime); + break; + + case 'H': + printf("%d", iAreaNumber); + break; + + case 'I': + printf(sAreaDesc); + break; + + case 'J': + printf("%u", LIMIT.DownF); + break; + + case 'K': + printf("%s", LIMIT.Description); + break; + + default: + printf(" "); + } +} + + + +void ControlCodeU(int ch) +{ + /* + * Update user info + */ + TimeCheck(); + ReadExitinfo(); + + switch (toupper(ch)) { + case 'A': + printf("%s", exitinfo.sUserName); + break; + + case 'B': + printf(exitinfo.sLocation); + break; + + case 'C': + printf(exitinfo.sVoicePhone); + break; + + case 'D': + printf(exitinfo.sDataPhone); + break; + + case 'E': + printf(LastLoginDate); + break; + + case 'F': + printf("%s %s", StrDateDMY(exitinfo.tFirstLoginDate), StrTimeHMS(exitinfo.tFirstLoginDate)); + break; + + case 'G': + printf(LastLoginTime); + break; + + case 'H': + printf("%d", exitinfo.Security.level); + break; + + case 'I': + printf("%d", exitinfo.iTotalCalls); + break; + + case 'J': + printf("%d", exitinfo.iTimeUsed); + break; + + case 'K': + printf("%d", exitinfo.iConnectTime); + break; + + case 'L': + printf("%d", exitinfo.iTimeLeft); + break; + + case 'M': + printf("%d", exitinfo.iScreenLen); + break; + + case 'N': + printf(FirstName); + break; + + case 'O': + printf(LastName); + break; + + case 'Q': + printf("%s", exitinfo.ieNEWS ? (char *) Language(147) : (char *) Language(148)); + break; + + case 'P': + printf("%s", exitinfo.GraphMode ? (char *) Language(147) : (char *) Language(148)); + break; + + case 'R': + printf("%s", exitinfo.HotKeys ? (char *) Language(147) : (char *) Language(148)); + break; + + case 'S': + printf("%d", exitinfo.iTimeUsed + exitinfo.iTimeLeft); + break; + + case 'T': + printf(exitinfo.sDateOfBirth); + break; + + case 'U': + printf("%d", exitinfo.iPosted); + break; + + case 'X': + printf(lang.Name); + break; + + case 'Y': + printf(exitinfo.sHandle); + break; + + case 'Z': + printf("%s", exitinfo.DoNotDisturb ? (char *) Language(147) : (char *) Language(148)); + break; + + case '1': + printf("%s", exitinfo.MailScan ? (char *) Language(147) : (char *) Language(148)); + break; + + case '2': + printf("%s", exitinfo.ieFILE ? (char *) Language(147) : (char *) Language(148)); + break; + + case '3': + printf("%s", exitinfo.FsMsged ? (char *) Language(147) : (char *) Language(148)); + break; + + default: + printf(" "); + } +} + + + +void ControlCodeK(int ch) +{ + FILE *pCallerLog; + char sDataFile[PATH_MAX]; + lastread LR; + + switch (toupper(ch)) { + case 'A': + printf("%s", (char *) GetDateDMY()); + break; + + case 'B': + printf("%s", (char *) GetLocalHMS()); + break; + + case 'C': + printf("%s", (char *) GLCdate()); + break; + + case 'D': + printf("%s", (char *) GLCdateyy()); + break; + + case 'E': + printf("%d", Speed() ); + break; + + case 'F': + printf("%s", LastCaller); + break; + + case 'G': + printf("%d", TotalUsers()); + break; + + case 'H': + sprintf(sDataFile, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + if((pCallerLog = fopen(sDataFile, "rb")) != NULL) { + fread(&SYSINFO, sizeof(SYSINFO), 1, pCallerLog); + printf("%ld", SYSINFO.SystemCalls); + fclose(pCallerLog); + } + break; + + case 'I': + printf("%d", iMsgAreaNumber + 1); + break; + + case 'J': + printf(sMsgAreaDesc); + break; + + case 'K': + printf("%s", Oneliner_Get()); + break; + + case 'L': + SetMsgArea(iMsgAreaNumber); + printf("%ld", MsgBase.Total); + break; + + case 'M': + LR.UserID = grecno; + if (Msg_Open(sMsgAreaBase)) { + if (Msg_GetLastRead(&LR) == TRUE) { + if (LR.HighReadMsg > MsgBase.Highest) + LR.HighReadMsg = MsgBase.Highest; + printf("%ld", LR.HighReadMsg); + } else + printf("?"); + Msg_Close(); + } + break; + + case 'N': + printf("%s", sMailbox); + break; + + case 'O': + SetEmailArea(sMailbox); + printf("%ld", EmailBase.Total); + break; + + case 'P': + sprintf(sDataFile, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, sMailbox); + LR.UserID = grecno; + if (Msg_Open(sDataFile)) { + if (Msg_GetLastRead(&LR) == TRUE) { + if (LR.HighReadMsg > EmailBase.Highest) + LR.HighReadMsg = EmailBase.Highest; + printf("%ld", LR.HighReadMsg); + } else + printf("?"); + Msg_Close(); + } + break; + + default: + printf(" "); + + } +} + + + +/* + * View a textfile. + */ +void ViewTextFile(char *Textfile) +{ + FILE *fp; + int iLine = 0; + char *temp, *temp1; + char sPrompt[] = "\n(More (Y/n/=): "; + int i, x, z; + + x = strlen(sPrompt); + + temp1 = calloc(PATH_MAX, sizeof(char)); + temp = calloc(81, sizeof(char)); + + sprintf(temp1, "%s", Textfile); + + if(( fp = fopen (temp1, "r")) != NULL) { + while (fgets(temp, 80, fp) != NULL) { + printf("%s", temp); + ++iLine; + if(iLine >= exitinfo.iScreenLen && iLine < 1000) { + iLine = 0; + pout(CFG.MoreF, CFG.MoreB, sPrompt); + + fflush(stdout); + z = Getone(); + switch(z) { + + case 'n': + case 'N': + printf("\n"); + break; + + case '=': + iLine = 1000; + } + for(i = 0; i < x; i++) + printf("\b"); + for(i = 0; i < x; i++) + printf(" "); + printf("\r"); + } + } + fclose(fp); + } + + Pause(); + free(temp1); + free(temp); +} + + + +/* + * Function will make log entry in users logfile + * Understands @ for Fileareas and ^ for Message Areas + */ +void LogEntry(char *Log) +{ + char *Entry, *temp; + int i; + + Entry = calloc(256, sizeof(char)); + temp = calloc(1, sizeof(char)); + + for(i = 0; i < strlen(Log); i++) { + if(*(Log + i) == '@') + strcat(Entry, sAreaDesc); + else + if(*(Log + i) == '^') + strcat(Entry, sMsgAreaDesc); + else { + sprintf(temp, "%c", *(Log + i)); + strcat(Entry, temp); + } + } + + Syslog('+', Entry); + free(Entry); + free(temp); +} + + + +/* + * Function will take two date strings in the following format DD-MM-YYYY and + * swap them around in the following format YYYYMMDD + * ie. 01-02-1995 will become 19950201 so that the leading Zeros are not in + * the beginning as leading Zeros will fall away if you try compare the + * two with a if statement (Millenium proof). + */ +void SwapDate(char *Date3, char *Date4) +{ + char *temp2, *temp3; + + temp2 = calloc(10, sizeof(char)); + temp3 = calloc(10, sizeof(char)); + Date1 = calloc(10, sizeof(char)); + Date2 = calloc(10, sizeof(char)); + + temp2[0] = Date3[6]; + temp2[1] = Date3[7]; + temp2[2] = Date3[8]; + temp2[3] = Date3[9]; + temp2[4] = Date3[3]; + temp2[5] = Date3[4]; + temp2[6] = Date3[0]; + temp2[7] = Date3[1]; + temp2[8] = '\0'; + + temp3[0] = Date4[6]; + temp3[1] = Date4[7]; + temp3[2] = Date4[8]; + temp3[3] = Date4[9]; + temp3[4] = Date4[3]; + temp3[5] = Date4[4]; + temp3[6] = Date4[0]; + temp3[7] = Date4[1]; + temp3[8] = '\0'; + + strcpy(Date1, temp2); + strcpy(Date2, temp3); + + free(temp2); + free(temp3); +} + + + +/* + * Function returns total number of bbs users + */ +int TotalUsers() +{ + FILE *pUsrConfig; + int ch = 0; + char *temp; + struct userhdr uhdr; + struct userrec u; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if(( pUsrConfig = fopen(temp,"rb")) == NULL) + WriteError("ControlCodeK: Can't open users file %s for reading", temp); + else { + fread(&uhdr, sizeof(uhdr), 1, pUsrConfig); + + while (fread(&u, uhdr.recsize, 1, pUsrConfig) == 1) + if ((!u.Deleted) && (strlen(u.sUserName) > 0)) + ch++; + + fclose(pUsrConfig); + } + free(temp); + + return ch; +} + + + diff --git a/mbsebbs/funcs.h b/mbsebbs/funcs.h new file mode 100644 index 00000000..a6e5c7e5 --- /dev/null +++ b/mbsebbs/funcs.h @@ -0,0 +1,23 @@ +/* funcs.h */ + +#ifndef _FUNCS_H +#define _FUNCS_H + +int Access(securityrec, securityrec); /* Check security access */ +void UserList(char *); /* Get complete users list */ +void TimeStats(void); /* Get users Time Statistics */ +void ExtDoor(char *, int, int, int); /* Run external door */ +int DisplayFile(char *); /* Display .ans/.asc textfile */ +int DisplayFileEnter(char *); /* Display .ans/.asc wait for Enter*/ +int CheckFile(char *, int); /* Check for Dupe file in Database */ +void ControlCodeF(int); /* Check Control Codes in File */ +void ControlCodeU(int); /* Check Control Codes in File */ +void ControlCodeK(int); /* Check Control Codes in File */ +void ViewTextFile(char *); /* View text file */ +void LogEntry(char *); /* Create log entry in logfile */ +void SwapDate(char *, char *); /* Swap two Date strings around */ +int TotalUsers(void); /* Returns total numbers of users */ + + +#endif + diff --git a/mbsebbs/funcs4.c b/mbsebbs/funcs4.c new file mode 100644 index 00000000..ee2e7945 --- /dev/null +++ b/mbsebbs/funcs4.c @@ -0,0 +1,1051 @@ +/***************************************************************************** + * + * File ..................: bbs/funcs4.c + * Purpose ...............: Misc functions, also for some utils. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "../lib/msg.h" +#include "funcs4.h" +#include "misc.h" +#include "timeout.h" +#include "language.h" + + +extern pid_t mypid; /* Original pid */ + + + +void UserSilent(int flag) +{ + SockS("ADIS:2,%d,%d;", mypid, flag); +} + + + +/* + * Check BBS open status, return FALSE if the bbs is closed. + * Display the reason why to the user. + */ +int CheckStatus() +{ + static char buf[81]; + + sprintf(buf, "SBBS:0;"); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:2,0", 7) == 0) + return TRUE; + if ((strncmp(buf, "100:2,2", 7) == 0) && (!ttyinfo.honor_zmh)) + return TRUE; + buf[strlen(buf) -1] = '\0'; + printf("\n\n\007*** %s ***\n\n\n", buf+8); + fflush(stdout); + } + return FALSE; +} + + + +/* + * Get a character string with cursor position + */ +void GetstrP(char *sStr, int iMaxLen, int Position) +{ + unsigned char ch = 0; + int iPos = Position; + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 1"); + return; + } + Setraw(); + + alarm_on(); + + while (ch != KEY_ENTER) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == KEY_BACKSPACE) || (ch == KEY_DEL) || (ch == KEY_RUBOUT)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos] = '\0'; + } else + putchar('\007'); + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxLen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a character string + */ +void GetstrC(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 6"); + return; + } + Setraw(); + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos] = '\0'; + } else + putchar('\007'); + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * get a string, don't allow spaces (for Unix accounts) + */ +void GetstrU(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 6"); + return; + } + Setraw(); + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos] = '\0'; + } else + putchar('\007'); + } + + if (ch > 32 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a phone number, only allow digits, + and - characters. + */ +void GetPhone(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 5"); + return; + } + Setraw(); + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos]='\0'; + } else + putchar('\007'); + } + + if ((ch >= '0' && ch <= '9') || (ch == '-') || (ch == '+')) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a number, allow digits, spaces, minus sign, points and comma's + */ +void Getnum(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 5"); + return; + } + Setraw(); + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos]='\0'; + } else + putchar('\007'); + } + + if ((ch >= '0' && ch <= '9') || (ch == '-') || (ch == ' ') \ + || (ch == ',') || (ch == '.')) { + + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * This function gets the date from the user checking the length and + * putting two minus signs in the right places + */ +void GetDate(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + + strcpy(sStr, ""); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 4"); + return; + } + Setraw(); + + alarm_on(); + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) + printf("\b \b"); + else + putchar('\007'); + + if (iPos == 3 || iPos == 6) { + printf("\b \b"); + --iPos; + } + + sStr[--iPos]='\0'; + } + + if (ch >= '0' && ch <= '9') { + if (iPos < iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + if (iPos == 2 || iPos == 5) { + printf("-"); + sprintf(sStr, "%s-", sStr); + iPos++; + } + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a string, capitalize only if set in config. + */ +void Getname(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0, iNewPos = 0; + + fflush(stdout); + + strcpy(sStr, ""); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 2"); + return; + } + Setraw(); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos]='\0'; + } else + putchar('\007'); + } + + if (ch > 31 && (ch < 127)) { + if (iPos < iMaxlen) { + iPos++; + if (iPos == 1 && CFG.iCapUserName) + ch = toupper(ch); + + if (ch == 32) { + iNewPos = iPos; + iNewPos++; + } + + if (iNewPos == iPos && CFG.iCapUserName) + ch = toupper(ch); + else + if (CFG.iCapUserName) + ch = tolower(ch); + + if (iPos == 1 && CFG.iCapUserName) + ch = toupper(ch); + + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a Fidonet style username, always capitalize. + */ +void GetnameNE(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0, iNewPos = 0; + + fflush(stdout); + + strcpy(sStr, ""); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 2"); + return; + } + Setraw(); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos]='\0'; + } else + putchar('\007'); + } + + if (ch > 31 && ch < 127) { + if (iPos < iMaxlen) { + iPos++; + + if (iPos == 1) + ch = toupper(ch); + + if (ch == 32) { + iNewPos = iPos; + iNewPos++; + } + + if (iNewPos == iPos) + ch = toupper(ch); + else + ch = tolower(ch); + + if (iPos == 1) + ch = toupper(ch); + + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Function will Scan Users Database for existing phone numbers. If + * found, it will write a log entry to the logfile. The user WILL NOT + * be notified about the same numbers + */ +int TelephoneScan(char *Number, char *Name) +{ + FILE *fp; + int Status = FALSE; + char *temp; + struct userhdr uhdr; + struct userrec u; + + temp = calloc(81, sizeof(char)); + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if(( fp = fopen(temp,"rb")) != NULL) { + fread(&uhdr, sizeof(uhdr), 1, fp); + + while (fread(&u, uhdr.recsize, 1, fp) == 1) { + if (strcasecmp(u.sUserName, Name) != 0) + if ((strlen(u.sVoicePhone) && (strcmp(u.sVoicePhone, Number) == 0)) || + (strlen(u.sDataPhone) && (strcmp(u.sDataPhone, Number) == 0))) { + Status = TRUE; + Syslog('b', "Dupe phones ref: \"%s\" voice: \"%s\" data: \"%s\"", + Number, u.sVoicePhone, u.sDataPhone); + Syslog('+', "Uses the same telephone number as %s", u.sUserName); + } + } + fclose(fp); + } + + free(temp); + return Status; +} + + + +void Pause() +{ + int i, x; + char *string; + + string = malloc(81); + + /* Press (Enter) to continue: */ + sprintf(string, "\r%s", (char *) Language(375)); + colour(CFG.CRColourF, CFG.CRColourB); + printf(string); + + do { + fflush(stdout); + fflush(stdin); + alarm_on(); + i = Getone(); + } while ((i != '\r') && (i != '\n')); + + x = strlen(string); + for(i = 0; i < x; i++) + printf("\b"); + for(i = 0; i < x; i++) + printf(" "); + for(i = 0; i < x; i++) + printf("\b"); + fflush(stdout); + + free(string); +} + + + +/* + * Function to check if UserName exists and returns a 0 or 1 + */ +int CheckName(char *Name) +{ + FILE *fp; + int Status = FALSE; + char *temp, *temp1; + struct userhdr ushdr; + struct userrec us; + + temp = calloc(81, sizeof(char)); + temp1 = calloc(81, sizeof(char)); + + strcpy(temp1, tl(Name)); + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp,"rb")) != NULL) { + fread(&ushdr, sizeof(ushdr), 1, fp); + + while (fread(&us, ushdr.recsize, 1, fp) == 1) { + strcpy(temp, tl(us.sUserName)); + + if((strcmp(temp, temp1)) == 0) { + Status = TRUE; + break; + } + } + fclose(fp); + } + + free(temp); + free(temp1); + return Status; +} + + + +/* + * This function returns the date in the following format: + * DD-Mon HH:MM:SS (Day-Month Time) + * The users language is used. + */ +char *logdate() +{ + static char Logdate[15]; + + time(&Time_Now); + l_date = localtime(&Time_Now); + sprintf(Logdate,"%02d-%s %02d:%02d:%02d", l_date->tm_mday, GetMonth(l_date->tm_mon+1), + l_date->tm_hour, l_date->tm_min, l_date->tm_sec); + return(Logdate); +} + + + +/* + * Function will ask user to create a unix login + * Name cannot be longer than 8 characters + */ +char *NameGen(char *FidoName) +{ + char *sUserName; + struct passwd *pw; + + sUserName = calloc(10, sizeof(char)); + + Syslog('+', "NameGen(%s)", FidoName); + setpwent(); + while ((strcmp(sUserName, "") == 0 || (pw = getpwnam(sUserName)) != NULL) || (strlen(sUserName) < 3)) { + colour(12, 0); + printf("\n%s\n\n", (char *) Language(381)); + colour(15, 0); + /* Please enter a login name (Maximum 8 characters) */ + printf("\n%s\n", (char *) Language(383)); + /* ie. John Doe, login = jdoe */ + printf("%s\n", (char *) Language(384)); + colour(10, 0); + /* login > */ + printf("%s", (char *) Language(385)); + fflush(stdout); + fflush(stdin); + GetstrU(sUserName, 7); + + setpwent(); + if (pw = getpwnam(tl(sUserName)), pw != NULL) { + /* That login name already exists, please choose another one. */ + colour(12, 0); + printf("\n%s\n", (char *) Language(386)); + setpwent(); + } + } + return tl(sUserName); +} + + + +/* + * Function will create the users name in the passwd file + */ +char *NameCreate(char *Name, char *Comment, char *Password) +{ + char *PassEnt; + + PassEnt = calloc(256, sizeof(char)); + + /* + * Call mbuseradd, this is a special setuid root program to create + * unix acounts and home directories. + */ + sprintf(PassEnt, "%s/bin/mbuseradd %d %s \"%s\" %s", + getenv("MBSE_ROOT"), getgid(), Name, Comment, CFG.bbs_usersdir); + Syslog('+', "%s", PassEnt); + fflush(stdout); + fflush(stdin); + + if (system(PassEnt) != 0) { + WriteError("Failed to create unix account"); + free(PassEnt); + ExitClient(1); + } + sprintf(PassEnt, "%s/bin/mbpasswd -f %s %s", getenv("MBSE_ROOT"), Name, Password); + Syslog('+', "%s/bin/mbpasswd -f %s ******", getenv("MBSE_ROOT"), Name); + if (system(PassEnt) != 0) { + WriteError("Failed to set unix password"); + free(PassEnt); + ExitClient(1); + } + + colour(14, 0); + /* Your "Unix Account" is created, you may use it the next time you call */ + printf("\n%s\n", (char *) Language(382)); + Syslog('+', "Created Unix account %s for %s", Name, Comment); + + free(PassEnt); + return Name; +} + + + +/* + * Function will check and create a home directory for the user if + * needed. It will also change into the users home directory when + * they login. + */ +char *ChangeHomeDir(char *Name, int Mailboxes) +{ + char *temp; + static char temp1[PATH_MAX]; + + temp = calloc(PATH_MAX, sizeof(char)); + + /* + * set umask bits to zero's then reset with mkdir + */ + umask(000); + + /* + * First check to see if users home directory exists + * else try create directory, as set in CFG.bbs_usersdir + */ + if ((access(CFG.bbs_usersdir, R_OK)) != 0) { + WriteError("$FATAL: Access to %s failed", CFG.bbs_usersdir); + free(temp); + ExitClient(1); + } + + sprintf(temp1, "%s/%s", CFG.bbs_usersdir, Name); + + /* + * Then check to see if users directory exists in the home dir + */ + if ((access(temp1, R_OK)) != 0) { + WriteError("$FATAL: Users homedir %s doesn't exist", temp1); + free(temp); + ExitClient(1); + } + + /* + * Change to users home directory + */ + if (chdir(temp1) != 0) { + WriteError("$FATAL: Can't change to users home dir, aborting: %s", temp1); + free(temp); + ExitClient(1); + } + setenv("HOME", temp1, 1); + + /* + * Check subdirectories, create them if they don't exist. + */ + sprintf(temp, "%s/wrk", temp1); + CheckDir(temp); + sprintf(temp, "%s/tag", temp1); + CheckDir(temp); + sprintf(temp, "%s/upl", temp1); + CheckDir(temp); + sprintf(temp, "%s/tmp", temp1); + CheckDir(temp); + sprintf(temp, "%s/.dosemu", temp1); + CheckDir(temp); + sprintf(temp, "%s/.dosemu/run", temp1); + CheckDir(temp); + sprintf(temp, "%s/.dosemu/tmp", temp1); + CheckDir(temp); + umask(007); + + /* + * Check users private emailboxes + */ + if (Mailboxes) { + sprintf(temp, "%s/mailbox", temp1); + if (Msg_Open(temp)) + Msg_Close(); + sprintf(temp, "%s/archive", temp1); + if (Msg_Open(temp)) + Msg_Close(); + sprintf(temp, "%s/trash", temp1); + if (Msg_Open(temp)) + Msg_Close(); + } + + free(temp); + return temp1; +} + + + +void CheckDir(char *dir) +{ + if ((access(dir, R_OK) != 0)) { + Syslog('+', "Creating %s", dir); + if (mkdir(dir, 0770)) + WriteError("$Can't create %s", dir); + } +} + + + +/* + * Function will check /etc/passwd for users fidonet login name. + * This will allow users to login in with there full name instead of + * their login name, to cut out confusion between unix accounts + * and normal bbs logins. + */ +int Check4UnixLogin(char *UsersName) +{ + unsigned UID = -1; /* Set to -1 incase user is not found */ + struct passwd *pw; + + while ((pw = getpwent())) { + #ifdef linux + if(strcmp(pw->pw_gecos, UsersName) == 0) { + #else + if(strcmp(pw->pw_comment, UsersName) == 0) { + #endif + UID = pw->pw_uid; + break; + } + } + + return UID; +} + + + +/* + * Function to check if User Handle exists and returns a 0 or 1 + */ +int CheckHandle(char *Name) +{ + FILE *fp; + int Status = FALSE; + char *temp, *temp1; + struct userhdr uhdr; + struct userrec u; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + strcpy(temp1, tl(Name)); + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if(( fp = fopen(temp,"rb")) != NULL) { + fread(&uhdr, sizeof(uhdr), 1, fp); + + while (fread(&u, uhdr.recsize, 1, fp) == 1) { + strcpy(temp, tl(u.sHandle)); + + if((strcmp(temp, temp1)) == 0) { + Status = TRUE; + break; + } + } + free(temp); + free(temp1); + fclose(fp); + } + + return Status; +} + + + +/* + * Function will check for unwanted user names + */ +int BadNames(char *Username) +{ + FILE *fp; + short iFoundName = FALSE; + char *temp, *String, *User; + + temp = calloc(PATH_MAX, sizeof(char)); + String = calloc(81, sizeof(char)); + User = calloc(81, sizeof(char)); + + strcpy(User, tl(Username)); + + sprintf(temp, "%s/etc/badnames.ctl", getenv("MBSE_ROOT")); + if(( fp = fopen(temp, "r")) != NULL) { + while((fgets(String, 80, fp)) != NULL) { + strcpy(String, tl(String)); + Striplf(String); + if((strstr(User, String)) != NULL) { + printf("\nSorry that name is not acceptable on this system\n"); + iFoundName = TRUE; + break; + } + } + fclose(fp); + } + + free(temp); + free(String); + free(User); + return iFoundName; +} + + + +/* + * Function will find where MBSE is located on system and load + * the file $MBSE_ROOT/etc/config.data in memory. + */ +void FindMBSE() +{ + FILE *pDataFile; + static char p[81]; + char *FileName; + struct passwd *pw; + + FileName = calloc(PATH_MAX, sizeof(char)); + + /* + * Check if the environment is set, if not, then we create the + * environment from the passwd file. + */ + if (getenv("MBSE_ROOT") == NULL) { + pw = getpwnam("mbse"); + memset(&p, 0, sizeof(p)); + sprintf(p, "MBSE_ROOT=%s", pw->pw_dir); + putenv(p); + } + + if (getenv("MBSE_ROOT") == NULL) { + printf("FATAL ERROR: Environment variable MBSE_ROOT not set\n"); + free(FileName); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + sprintf(FileName, "%s/etc/config.data", getenv("MBSE_ROOT")); + + if(( pDataFile = fopen(FileName, "rb")) == NULL) { + printf("FATAL ERROR: Can't open %s for reading!\n", FileName); + printf("Please run mbsetup to create configuration file.\n"); + printf("Or check that your environment variable MBSE_ROOT is set to the BBS Path!\n"); + free(FileName); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + fread(&CFG, sizeof(CFG), 1, pDataFile); + free(FileName); + fclose(pDataFile); +} + + + +/* + * Returns Mmm in the users language. + */ +char *GetMonth(int Month) +{ + static char month[10]; + + switch (Month) { + case 1: + strcpy(month, *(mLanguage + 398)); + break; + case 2: + strcpy(month, *(mLanguage + 399)); + break; + case 3: + strcpy(month, *(mLanguage + 400)); + break; + case 4: + strcpy(month, *(mLanguage + 401)); + break; + case 5: + strcpy(month, *(mLanguage + 402)); + break; + case 6: + strcpy(month, *(mLanguage + 403)); + break; + case 7: + strcpy(month, *(mLanguage + 404)); + break; + case 8: + strcpy(month, *(mLanguage + 405)); + break; + case 9: + strcpy(month, *(mLanguage + 406)); + break; + case 10: + strcpy(month, *(mLanguage + 407)); + break; + case 11: + strcpy(month, *(mLanguage + 408)); + break; + case 12: + strcpy(month, *(mLanguage + 409)); + break; + default: + strcpy(month, "Unknown"); + } + + return(month); +} + + + +/* Returns DD-Mmm-YYYY */ +char *GLCdateyy() +{ + static char GLcdateyy[15]; + char ntime[15]; + + time(&Time_Now); + l_date = localtime(&Time_Now); + + sprintf(GLcdateyy,"%02d-", + l_date->tm_mday); + + sprintf(ntime,"-%02d", l_date->tm_year+1900); + strcat(GLcdateyy, GetMonth(l_date->tm_mon+1)); + strcat(GLcdateyy,ntime); + + return(GLcdateyy); +} + + diff --git a/mbsebbs/funcs4.h b/mbsebbs/funcs4.h new file mode 100644 index 00000000..fa1238d8 --- /dev/null +++ b/mbsebbs/funcs4.h @@ -0,0 +1,31 @@ +#ifndef _FUNCS4_H +#define _FUNCS4_H + +void UserSilent(int); /* Update users silent flag info */ +int CheckStatus(void); /* Check BBS open status */ +void GetstrU(char *, int); /* Get string, forbid spaces */ +void GetstrP(char *, int, int); /* Get string with cursor position */ +void GetstrC(char *, int); /* Get string, length, clear string */ +void Getnum(char *, int); /* Get only numbers from user */ +void Getname(char *, int); /* Get name & convert every 1st char to U/C */ +void GetnameNE(char *, int); /* Get name & convert every 1st char to U/C */ +void GetDate(char *, int); /* Get users birth date and check */ +void GetPhone(char *, int); /* Get telephone number */ +int TelephoneScan(char *, char *);/* Scans for Duplicate User Phone Numbers */ +void Pause(void); /* Puts Pause on Screen and halts screen */ +int CheckName(char *); /* Check if user name exists */ +char *logdate(void); /* Returns DD-Mon HH:MM:SS */ +char *NameGen(char *); /* Get and test for unix login */ +char *NameCreate(char *, char *, char *);/* Create users login in passwd file */ +char *ChangeHomeDir(char *, int); /* Change and Create Users Home Directories */ +void CheckDir(char *); /* Check and create directory */ +int Check4UnixLogin(char *); /* Check Passwd File for Users Login */ +int CheckHandle(char *); /* Check if user handle exists */ +int BadNames(char *); /* Check for Unwanted user names */ +void FindMBSE(void); /* Load Configuration file in memory */ +char *GLCdateyy(void); /* Returns current date DD-Mmm-YYYY */ +char *GetMonth(int); /* Returns Mmm */ + + +#endif + diff --git a/mbsebbs/getdef.c b/mbsebbs/getdef.c new file mode 100644 index 00000000..6940c34a --- /dev/null +++ b/mbsebbs/getdef.c @@ -0,0 +1,393 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/getdef.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 27-Jun-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * Copyright 1991 - 1994, Julianne Frances Haugh and Chip Rosenthal + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "../config.h" +#include +#include +#include +#include +#include +#include "getdef.h" + + +/* + * A configuration item definition. + */ + +struct itemdef { + const char *name; /* name of the item */ + char *value; /* value given, or NULL if no value */ +}; + +/* + * This list *must* be sorted by the "name" member. + */ + +#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0])) +static struct itemdef def_table[] = { + { "CHFN_AUTH", NULL }, + { "CHFN_RESTRICT", NULL }, + { "CONSOLE", NULL }, + { "CONSOLE_GROUPS", NULL }, +#ifdef HAVE_LIBCRACK + { "CRACKLIB_DICTPATH", NULL }, +#endif + { "CREATE_HOME", NULL }, + { "DEFAULT_HOME", NULL }, + { "DIALUPS_CHECK_ENAB", NULL }, + { "ENVIRON_FILE", NULL }, + { "ENV_HZ", NULL }, + { "ENV_PATH" , NULL }, + { "ENV_SUPATH", NULL }, + { "ENV_TZ", NULL }, + { "ERASECHAR", NULL }, + { "FAILLOG_ENAB", NULL }, + { "FAIL_DELAY", NULL }, + { "FTMP_FILE", NULL }, + { "GID_MAX", NULL }, + { "GID_MIN", NULL }, + { "HUSHLOGIN_FILE", NULL }, + { "ISSUE_FILE", NULL }, + { "KILLCHAR", NULL }, + { "LASTLOG_ENAB", NULL }, + { "LOGIN_RETRIES", NULL }, + { "LOGIN_STRING", NULL }, + { "LOGIN_TIMEOUT", NULL }, + { "LOG_OK_LOGINS", NULL }, + { "LOG_UNKFAIL_ENAB", NULL }, + { "MAIL_CHECK_ENAB", NULL }, + { "MAIL_DIR", NULL }, + { "MAIL_FILE", NULL }, + { "MD5_CRYPT_ENAB", NULL }, + { "MOTD_FILE", NULL }, + { "NOLOGINS_FILE", NULL }, + { "NOLOGIN_STR", NULL }, + { "OBSCURE_CHECKS_ENAB", NULL }, + { "PASS_ALWAYS_WARN", NULL }, + { "PASS_CHANGE_TRIES", NULL }, + { "PASS_MAX_DAYS", NULL }, + { "PASS_MAX_LEN", NULL }, + { "PASS_MIN_DAYS", NULL }, + { "PASS_MIN_LEN", NULL }, + { "PASS_WARN_AGE", NULL }, + { "PORTTIME_CHECKS_ENAB", NULL }, + { "QMAIL_DIR", NULL }, + { "QUOTAS_ENAB", NULL }, + { "SULOG_FILE", NULL }, + { "SU_NAME", NULL }, + { "SU_WHEEL_ONLY", NULL }, + { "SYSLOG_SG_ENAB", NULL }, + { "SYSLOG_SU_ENAB", NULL }, + { "TTYGROUP", NULL }, + { "TTYPERM", NULL }, + { "TTYTYPE_FILE", NULL }, + { "UID_MAX", NULL }, + { "UID_MIN", NULL }, + { "ULIMIT", NULL }, + { "UMASK", NULL }, + { "USERDEL_CMD", NULL }, + { "USERGROUPS_ENAB", NULL }, +}; + +#ifndef LOGINDEFS +#define LOGINDEFS "/etc/login.defs" +#endif + +static char def_fname[] = LOGINDEFS; /* login config defs file */ +static int def_loaded = 0; /* are defs already loaded? */ + + +/* local function prototypes */ +static struct itemdef *def_find (const char *); +static void def_load (void); + + +/* + * getdef_str - get string value from table of definitions. + * + * Return point to static data for specified item, or NULL if item is not + * defined. First time invoked, will load definitions from the file. + */ + +char *getdef_str(const char *item) +{ + struct itemdef *d; + + if (!def_loaded) + def_load(); + + return ((d = def_find(item)) == NULL ? (char *)NULL : d->value); +} + + +/* + * getdef_bool - get boolean value from table of definitions. + * + * Return TRUE if specified item is defined as "yes", else FALSE. + */ + +int getdef_bool(const char *item) +{ + struct itemdef *d; + + if (!def_loaded) + def_load(); + + if ((d = def_find(item)) == NULL || d->value == NULL) + return 0; + + return (strcmp(d->value, "yes") == 0); +} + + +/* + * getdef_num - get numerical value from table of definitions + * + * Returns numeric value of specified item, else the "dflt" value if + * the item is not defined. Octal (leading "0") and hex (leading "0x") + * values are handled. + */ + +int getdef_num(const char *item, int dflt) +{ + struct itemdef *d; + + if (!def_loaded) + def_load(); + + if ((d = def_find(item)) == NULL || d->value == NULL) + return dflt; + + return (int) strtol(d->value, (char **)NULL, 0); +} + + +/* + * getdef_long - get long integer value from table of definitions + * + * Returns numeric value of specified item, else the "dflt" value if + * the item is not defined. Octal (leading "0") and hex (leading "0x") + * values are handled. + */ + +long getdef_long(const char *item, long dflt) +{ + struct itemdef *d; + + if (!def_loaded) + def_load(); + + if ((d = def_find(item)) == NULL || d->value == NULL) + return dflt; + + return strtol(d->value, (char **)NULL, 0); +} + +/* + * def_find - locate named item in table + * + * Search through a sorted table of configurable items to locate the + * specified configuration option. + */ + +static struct itemdef *def_find(const char *name) +{ + int min, max, curr, n; + + /* + * Invariant - desired item in range [min:max]. + */ + + min = 0; + max = NUMDEFS-1; + + /* + * Binary search into the table. Relies on the items being + * sorted by name. + */ + + while (min <= max) { + curr = (min+max)/2; + + if (! (n = strcmp(def_table[curr].name, name))) + return &def_table[curr]; + + if (n < 0) + min = curr+1; + else + max = curr-1; + } + + /* + * Item was never found. + */ + + fprintf(stderr, "mbpasswd: configuration error - unknown item '%s' (notify administrator)\r\n", name); + syslog(LOG_CRIT, "unknown configuration item `%s'", name); + return (struct itemdef *) NULL; +} + +/* + * def_load - load configuration table + * + * Loads the user-configured options from the default configuration file + */ + +static void def_load(void) +{ + int i; + FILE *fp; + struct itemdef *d; + char buf[BUFSIZ], *name, *value, *s; + + /* + * Open the configuration definitions file. + */ + + if ((fp = fopen(def_fname, "r")) == NULL) { + syslog(LOG_CRIT, "cannot open login definitions %s [%m]", def_fname); + return; + } + + /* + * Go through all of the lines in the file. + */ + + while (fgets(buf, sizeof(buf), fp) != NULL) { + + /* + * Trim trailing whitespace. + */ + + for (i = strlen(buf)-1 ; i >= 0 ; --i) { + if (!isspace(buf[i])) + break; + } + buf[++i] = '\0'; + + /* + * Break the line into two fields. + */ + + name = buf + strspn(buf, " \t"); /* first nonwhite */ + if (*name == '\0' || *name == '#') + continue; /* comment or empty */ + + s = name + strcspn(name, " \t"); /* end of field */ + if (*s == '\0') + continue; /* only 1 field?? */ + + *s++ = '\0'; + value = s + strspn(s, " \"\t"); /* next nonwhite */ + *(value + strcspn(value, "\"")) = '\0'; + + /* + * Locate the slot to save the value. If this parameter + * is unknown then "def_find" will print an err message. + */ + + if ((d = def_find(name)) == NULL) + continue; + + /* + * Save off the value. + */ + + if ((d->value = strdup(value)) == NULL) { + fprintf(stderr, "mbpasswd: Could not allocate space for config info.\n"); + syslog(LOG_ERR, "could not allocate space for config info"); + break; + } + } + (void) fclose(fp); + + /* + * Set the initialized flag. + */ + + ++def_loaded; +} + +#ifdef CKDEFS +int main(int argc, char **argv) +{ + int i; + char *cp; + struct itemdef *d; + + def_load (); + + for (i = 0 ; i < NUMDEFS ; ++i) { + if ((d = def_find(def_table[i].name)) == NULL) + printf("error - lookup '%s' failed\n", def_table[i].name); + else + printf("%4d %-24s %s\n", i+1, d->name, d->value); + } + for (i = 1;i < argc;i++) { + if (cp = getdef_str (argv[1])) + printf ("%s `%s'\n", argv[1], cp); + else + printf ("%s not found\n", argv[1]); + } + exit(0); +} +#endif diff --git a/mbsebbs/getdef.h b/mbsebbs/getdef.h new file mode 100644 index 00000000..ac6c5489 --- /dev/null +++ b/mbsebbs/getdef.h @@ -0,0 +1,10 @@ +#ifndef _GETDEF_H +#define _GETDEF_H + +/* getdef.c */ +int getdef_bool(const char *); +long getdef_long(const char *, long); +int getdef_num(const char *, int); +char *getdef_str(const char *); + +#endif /* _GETDEF_H */ diff --git a/mbsebbs/language.c b/mbsebbs/language.c new file mode 100644 index 00000000..4dcf50a3 --- /dev/null +++ b/mbsebbs/language.c @@ -0,0 +1,169 @@ +/***************************************************************************** + * + * File ..................: bbs/language.c + * Purpose ...............: Language functions. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "funcs4.h" +#include "language.h" + + + + +/* + * Function will print text in language file + * Forground Colour, Background Colour, Record Number + */ +void language(int fg, int bg, int lRecord) +{ + pout(fg, bg, *(mLanguage + lRecord)); +} + + + +/* + * Function will return line for output + */ +char *Language(int lRecord) +{ + /* + * Return language string + */ + return (*(mLanguage + lRecord)); +} + + + +int Keystroke(int lRecord, int Pos) +{ + char temp[30]; + + memset(&temp, 0, sizeof(temp)); + sprintf(temp, "%s", *(mKeystroke + lRecord)); + + if ((Pos < 0) || (Pos > strlen(temp))) { + WriteError("Keystroke(%d, %d): Range Error", lRecord, Pos); + return '\0'; + } else { + return temp[Pos]; + } +} + + + +/* + * Function will set up the necessary language paths and names + */ +void Set_Language(int iLanguage) +{ + FILE *pLang; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + + if ((pLang = fopen(temp, "rb")) == NULL) { + WriteError("Language: Can't open file: %s", temp); + printf("\nLanguage: Can't open language file\n\n"); + free(temp); + Pause(); + return; + } + + fread(&langhdr, sizeof(langhdr), 1, pLang); + while (fread(&lang, langhdr.recsize, 1, pLang) == 1) { + if ((lang.LangKey[0] == iLanguage) && (lang.Available)) { + strcpy(CFG.current_language, lang.Filename); + break; + } + } + + free(temp); + fclose(pLang); +} + + + +/* + * Function will initialize language variables and load them into + * memory for speed + */ +void InitLanguage() +{ + FILE *pLang; + int iLang = 0; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/%s", getenv("MBSE_ROOT"), CFG.current_language); + if ((pLang = fopen(temp, "rb")) == NULL) { + WriteError("$FATAL: Can't open %s", temp); + ExitClient(1); + } + + while (fread(&ldata, sizeof(ldata), 1, pLang) == 1) { + *(mLanguage + iLang) = (char *) calloc(strlen(ldata.sString) + 1, sizeof(char)); + *(mKeystroke + iLang) = (char *) calloc(strlen(ldata.sKey) + 1, sizeof(char)); + strcpy(mLanguage[iLang], ldata.sString); + strcpy(mKeystroke[iLang], ldata.sKey); + iLang++; + + if(iLang >= LANG) { + printf("FATAL: Language file has to many lines in it"); + ExitClient(1); + } + } + + fclose(pLang); + Syslog('b', "%d language lines read (%s)", iLang, CFG.current_language); + free(temp); +} + + + +void Free_Language() +{ + int i; + + for (i = 0; i < LANG; i++) { + if (*(mLanguage + i)) + free(*(mLanguage + i)); + if (*(mKeystroke + i)) + free(*(mKeystroke + i)); + } +} + + + diff --git a/mbsebbs/language.h b/mbsebbs/language.h new file mode 100644 index 00000000..07c19bd6 --- /dev/null +++ b/mbsebbs/language.h @@ -0,0 +1,13 @@ +#ifndef _LANGUAGE_H +#define _LANGUAGE_H + + +void language(int, int, int); /* Print language text */ +int Keystroke(int, int); /* Return keystroke */ +void InitLanguage(void); /* Initialize Language */ +char *Language(int); /* Return line for output */ +void Set_Language(int); /* Set Language Variables Up */ +void Free_Language(void); /* Free language memory */ + +#endif + diff --git a/mbsebbs/lineedit.c b/mbsebbs/lineedit.c new file mode 100644 index 00000000..c52d6ac7 --- /dev/null +++ b/mbsebbs/lineedit.c @@ -0,0 +1,577 @@ +/***************************************************************************** + * + * File ..................: bbs/lineedit.c + * Purpose ...............: Message line editor. + * Last modification date : 06-Jul-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "mail.h" +#include "funcs4.h" +#include "language.h" +#include "timeout.h" +#include "lineedit.h" + + +extern int Line; +extern char *Message[]; + + +/* + * Internal prototypes + */ +void Line_Edit_Append(void); /* Append lines */ +void Line_Edit_Delete(void); /* Delete lines */ +void Line_Edit_Edit(void); /* Edit lines */ +void Line_Edit_Insert(void); /* Insert lines */ +void Line_Edit_Replace(void); /* Replace lines */ +void Line_Edit_Text(void); /* Edit (replace) text in line */ +void Line_Edit_Center(void); /* Center a line */ + + + + +void Line_Edit_Append() +{ + if((Line - 1) == TEXTBUFSIZE) { + Enter(1); + /* Maximum message length exceeded */ + pout(3, 0, (char *) Language(166)); + Enter(1); + return; + } + + while (TRUE) { + colour(10, 0); + printf("%-2d : ", Line); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + GetstrP(Message[Line], 72, 0); + + if((strcmp(Message[Line], "")) == 0) + return; + + Line++; + if((Line - 1) == TEXTBUFSIZE) { + Enter(1); + /* Maximum message length exceeded */ + pout(12, 0, (char *) Language(166)); + Enter(1); + return; + } + } +} + + + +void Line_Edit_Delete() +{ + int i, start, end = 0, total; + int Loop; + char temp[81]; + + while (TRUE) { + colour(10, 0); + /* Delete starting at line */ + printf("\n\n%s#(1 - %d): ", (char *) Language(176), (Line - 1) ); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) { + /* Aborted. */ + pout(15, 0, (char *) Language(177)); + Enter(1); + return; + } + + start = atoi(temp); + colour(10, 0); + if(start > (Line - 1) ) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d)", (char *) Language(178), (Line - 1) ); + else + break; + } + + while (TRUE) { + colour(10, 0); + /* Delete ending at line */ + printf("%s# (1 - %d): ", (char *) Language(179), (Line - 1) ); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) { + /* Aborted. */ + pout(15, 0, (char *) Language(176)); + Enter(1); + return; + } + + end = atoi(temp); + + colour(10, 0); + if(end > (Line - 1)) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d)\n\n", (char *) Language(179), (Line - 1) ); + else + break; + + } + + /* Get total by minusing the end line from the start line */ + /* and + 1 will give you total lines between start and end */ + total = (end - start) + 1; + + /* Define loop by minusing total lines from end which will */ + /* do a loop for only the amount of lines left after the */ + /* end line */ + Loop = Line - end++; + + /* Minus the total amount of deleted lines from the current */ + /* amount of lines to keep track of how many lines you are */ + /* working with */ + Line -= total; + + /* Do loop to copy the current message over the deleted lines */ + + for (i = 0; i < Loop; i++) + strcpy(*(Message + start++), *(Message + end++)); +} + + + +void Line_Edit_Edit() +{ + int j, edit; + char temp[81]; + + while (TRUE) { + while (TRUE) { + colour(10, 0); + /* Enter line # to edit */ + printf("\n%s(1 - %d): ", (char *) Language(181), (Line - 1) ); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) + return; + + edit = atoi(temp); + + colour(10, 0); + if(edit > Line) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d) ", (char *) Language(178), (Line - 1) ); + else + break; + } + + colour(10, 0); + printf("\n%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Message[edit]); + fflush(stdout); + j = strlen(Message[edit]); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + alarm_on(); + GetstrP(Message[edit], 81, j); + } +} + + + +void Line_Edit_Insert() +{ + int i, j, start, end = 0, total; + char temp[81]; + + if((Line - 1) == TEXTBUFSIZE) { + Enter(1); + /* Maximum message length exceeded */ + pout(3, 0, (char *) Language(166)); + Enter(1); + return; + } + + while (TRUE) { + colour(10, 0); + /* Enter line # to insert text before */ + printf("\n\n%s(1 - %d): ", (char *) Language(183), (Line - 1)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) { + /* Aborted. */ + pout(15, 0, (char *) Language(177)); + return; + } + + start = atoi(temp); + + colour(10, 0); + if(start > (Line - 1)) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d)", (char *) Language(178), (Line - 1)); + else + break; + } + + j = start; + colour(10, 0); + printf("\n%-2d : ", start); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) + return; + + total = Line - start; + end = Line; + Line++; + start = Line; + + for (i = 0; i < total + 1; i++) { + strcpy(Message[start], Message[end]); + start--; + end--; + } + + strcpy(Message[j], temp); +} + + + +void Line_Edit_Replace() +{ + int edit; + char temp[81]; + + while (TRUE) { + while (TRUE) { + colour(10, 0); + /* Enter line # to replace */ + printf("\n\n%s(1 - %d): ", (char *) Language(185), (Line - 1) ); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) + return; + + edit = atoi(temp); + + colour(10, 0); + if(edit > Line) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d) ", (char *) Language(178), (Line - 1)); + else + break; + } + + Enter(1); + /* Line reads: */ + pout(15, 0, (char *) Language(186)); + Enter(1); + + colour(10, 0); + printf("%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s\n\n", Message[edit]); + + colour(10, 0); + printf("%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) { + Enter(1); + /* Unchanged. */ + pout(15, 0, (char *) Language(187)); + Enter(1); + } else + strcpy(Message[edit], temp); + + Enter(1); + /* Line now reads: */ + pout(15, 0, (char *) Language(188)); + Enter(1); + + colour(10, 0); + printf("%d : ", edit); + + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Message[edit]); + } +} + + + +void Line_Edit_Text() +{ + int edit; + char temp[81]; + char temp1[81]; + + while (TRUE) { + while (TRUE) { + colour(10, 0); + /* Enter line # to edit */ + printf("\n\n%s(1 - %d): ", (char *) Language(194), (Line - 1)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) + return; + + edit = atoi(temp); + + colour(10, 0); + if(edit > Line) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d) ", (char *) Language(178), (Line - 1) ); + else + break; + } + + Enter(1); + /* Line reads: */ + pout(15, 0, (char *) Language(186)); + Enter(1); + colour(10, 0); + printf("%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s\n\n", Message[edit]); + + /* Text to replace: */ + pout(10, 0, (char *) Language(195)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + /* Replacement text: */ + pout(10, 0, (char *) Language(196)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp1, 80); + + strreplace(Message[edit], temp, temp1); + + Enter(1); + /* Line now reads: */ + pout(15, 0, (char *) Language(197)); + Enter(1); + colour(10, 0); + printf("%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Message[edit]); + } +} + + + +void Line_Edit_Center() +{ + int i, j, z, center; + int maxlen = 78; + char *CEnter; + char temp[81]; + + colour(15, 0); + /* Enter line # to center */ + printf("\n\n%s(1 - %d): ", (char *) Language(203), (Line - 1)); + fflush(stdout); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) + return; + + CEnter = calloc(81, sizeof(char)); + center = atoi(temp); + j = strlen(Message[center]); + if (j >= maxlen) + /* Line is maximum length and cannot be centered */ + printf("\n%s\n", (char *) Language(204)); + else { + z = 35 - (j / 2); + + for(i = 0; i < z; i++) + strcat(CEnter," "); + strcat(CEnter, Message[center]); + strcpy(Message[center], CEnter); + } + + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("\n%s\n", Message[center]); + free(CEnter); +} + + + +int Line_Edit() +{ + int i, j; + + clear(); + colour(12, 0); + /* Begin your message now, Blank line to end */ + Center((char *) Language(164)); + /* Maximum of TEXTBUFSIZE lines, 73 chars per line */ + Center((char *) Language(165)); + colour(14, 0); + printf(" ("); + for (i = 0; i < 74; i++) + printf("-"); + printf(")\n"); + + Line_Edit_Append(); + + while (TRUE) { + colour(14, 0); + /* Functions available: (Current Message: */ + printf("\n%s%d ", (char *) Language(167), (Line - 1)); + /* Lines) */ + printf("%s\n\n", (char *) Language(168)); + colour(11, 0); + /* L - List message S - Save message C - Continue message */ + printf("%s\n", (char *) Language(169)); + + /* Q - Quit message D - Delete line I - Insert line */ + printf("%s\n", (char *) Language(170)); + + /* T - Text edit E - Edit line R - Replace line */ + printf("%s\n", (char *) Language(171)); + + /* Z - Center line */ + printf("%s\n", (char *) Language(172)); + + colour(15, 0); + printf("\n%s [", (char *) Language(173)); + for (i = 0; i < 10; i++) + putchar(Keystroke(172, i)); + printf("]: "); + fflush(stdout); + + alarm_on(); + j = toupper(Getone()); + + if (j == Keystroke(172, 2)) { + /* Continue */ + pout(15, 0, (char *) Language(174)); + Enter(1); + Line_Edit_Append(); + } else + + if (j == Keystroke(172, 4)) { + /* Delete */ + pout(15, 0, (char *) Language(175)); + Enter(1); + Line_Edit_Delete(); + } else + + if (j == Keystroke(172, 7)) { + /* Edit */ + pout(15, 0, (char *) Language(180)); + Enter(1); + Line_Edit_Edit(); + } else + + if (j == Keystroke(172, 5)) { + /* Insert */ + pout(15, 0, (char *) Language(182)); + Enter(1); + Line_Edit_Insert(); + } else + + if (j == Keystroke(172, 0)) { + pout(15, 0, (char *) Language(184)); + Enter(2); + + for(i = 1; i < Line; i++) { + colour(10, 0); + printf("%d: ", i); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s\n", Message[i]); + } + } else + + if (j == Keystroke(172, 8)) { + /* Replace */ + pout(15, 0, (char *) Language(362)); + Enter(1); + Line_Edit_Replace(); + } else + + if (j == Keystroke(172, 3)) { + /* Quit */ + pout(15, 0, (char *) Language(189)); + Enter(2); + + /* Are you sure [y/N] */ + printf("%s", (char *) Language(190)); + fflush(stdout); + alarm_on(); + + if (toupper(Getone()) == Keystroke(190, 0)) { + /* Yes */ + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(356)); + Enter(1); + /* Message aborted. */ + pout(15, 0, (char *) Language(191)); + Enter(2); + + fflush(stdout); + sleep(1); + return FALSE; + } + + colour(CFG.HiliteF, CFG.HiliteB); + /* No */ + printf("%s\n", (char *) Language(192)); + } else + + if (j == Keystroke(172, 6)) { + /* Text Edit */ + pout(15, 0, (char *) Language(193)); + Line_Edit_Text(); + } else + + if (j == Keystroke(172, 1)) { + /* Save */ + pout(15, 0, (char *) Language(198)); + Enter(1); + fflush(stdout); + + if (Line > 1) + return TRUE; + + return FALSE; + } else + + if (j == Keystroke(172, 9)) { + /* Center */ + pout(15, 0, (char *) Language(376)); + Enter(1); + Line_Edit_Center(); + } + } +} + + diff --git a/mbsebbs/lineedit.h b/mbsebbs/lineedit.h new file mode 100644 index 00000000..71894eca --- /dev/null +++ b/mbsebbs/lineedit.h @@ -0,0 +1,7 @@ +#ifndef _LINEEDIT_H +#define _LINEEDIT_H + +int Line_Edit(void); /* The message line editor */ + +#endif + diff --git a/mbsebbs/mail.c b/mbsebbs/mail.c new file mode 100644 index 00000000..93238a8c --- /dev/null +++ b/mbsebbs/mail.c @@ -0,0 +1,2163 @@ +/***************************************************************************** + * + * File ..................: bbs/mail.c + * Purpose ...............: Message reading and writing. + * Last modification date : 28-Jun-2001 + * Todo ..................: Implement message groups. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************** + * + * JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner, + * Mats Birch, Mats Wallin. + * ALL RIGHTS RESERVED. + * + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/msgtext.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "mail.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "timeout.h" +#include "oneline.h" +#include "exitinfo.h" +#include "lineedit.h" +#include "fsedit.h" +#include "filesub.h" +#include "msgutil.h" +#include "pop3.h" +#include "email.h" + + + +/* + * Global variables + */ +unsigned long LastNum; /* Last read message number */ +int Kludges = FALSE; /* Show kludges or not */ +int Line = 1; /* Line counter in editor */ +char *Message[TEXTBUFSIZE +1];/* Message compose text buffer */ +FILE *qf; /* Quote file */ +extern int do_mailout; + + +/* + * Internal prototypes + */ + +void ShowMsgHdr(void); /* Show message header */ +int Read_a_Msg(unsigned long Num, int);/* Read a message */ +int Export_a_Msg(unsigned long Num);/* Export message to homedir */ +int ReadPanel(void); /* Read panel bar */ +int Save_Msg(int, faddr *); /* Save a message */ +void Reply_Msg(int); /* Reply to message */ +void Delete_MsgNum(unsigned long); /* Delete specified message */ +int CheckUser(char *); /* Check if user exists */ +int IsMe(char *); /* Test if this is my userrecord */ + + +/****************************************************************************/ + + +/* + * More prompt, returns 1 if user decides not to look any further. + */ +int LC(int Lines) +{ + int z; + + iLineCount += Lines; + + if (iLineCount >= exitinfo.iScreenLen && iLineCount < 1000) { + iLineCount = 1; + + pout(CFG.MoreF, CFG.MoreB, (char *) Language(61)); + fflush(stdout); + alarm_on(); + z = toupper(Getone()); + + if (z == Keystroke(61, 1)) { + printf("\n"); + return(1); + } + + if (z == Keystroke(61, 2)) + iLineCount = 50000; + + Blanker(strlen(Language(61))); + } + + return(0); +} + + + +/* + * Check if posting is allowed + */ +int Post_Allowed(void); +int Post_Allowed(void) +{ + if (msgs.MsgKinds == RONLY) { + /* Message area is Readonly */ + pout(12, 0, (char *) Language(437)); + fflush(stdout); + sleep(3); + return FALSE; + } + return TRUE; +} + + + +/* + * Check if netmail may be send crash or immediate. + */ +int Crash_Option(faddr *); +int Crash_Option(faddr *Dest) +{ + node *Nlent; + int rc = 0; + unsigned short point; + + if (exitinfo.Security.level < CFG.iCrashLevel) + return 0; + + point = Dest->point; + Dest->point = 0; + + if (((Nlent = getnlent(Dest)) != NULL) && (Nlent->addr.zone)) { + if (Nlent->oflags & OL_CM) { + /* Crash [y/N]: */ + pout(3, 0, (char *)Language(461)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(461, 0)) { + rc = 1; + printf("%c", Keystroke(461, 0)); + } else + printf("%c", Keystroke(461, 1)); + } else { + /* Warning: node is not CM, send Immediate [y/N]: */ + pout(3, 0, (char *)Language(462)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(462, 0)) { + rc = 2; + printf("%c", Keystroke(462, 0)); + } else + printf("%c", Keystroke(462, 1)); + } + fflush(stdout); + } + + Dest->point = point; + return rc; +} + + + +/* + * Ask if message must be private, only allowed in areas which allow + * both public and private. Private areas are forced to private. + */ +int IsPrivate(void); +int IsPrivate(void) +{ + int rc = FALSE; + + if (msgs.MsgKinds == BOTH) { + Enter(1); + /* Private [y/N]: */ + pout(3, 0, (char *) Language(163)); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(163, 0)) { + rc = TRUE; + printf("%c", Keystroke(163, 0)); + } else { + printf("%c", Keystroke(163, 1)); + } + fflush(stdout); + } + + /* + * Allways set the private flag in Private areas. + */ + if (msgs.MsgKinds == PRIVATE) + rc = TRUE; + + return rc; +} + + + +void Check_Attach(void); +void Check_Attach(void) +{ + char *Attach, *dospath; + struct stat sb; + + /* + * This is a dangerous option! Every file on the system to which the + * bbs has read access and is in the range of paths translatable by + * Unix to DOS can be attached to the netmail. + */ + if ((msgs.Type == NETMAIL) && (exitinfo.Security.level >= CFG.iAttachLevel)) { + + Attach = calloc(PATH_MAX, sizeof(char)); + while (TRUE) { + Enter(1); + /* Attach file [y/N]: */ + pout(3, 0, (char *)Language(463)); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(463, 0)) { + + printf("%c", Keystroke(463, 0)); + Enter(1); + /* Please enter filename: */ + pout(14, 0, (char *)Language(245)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + sprintf(Attach, "%s/", CFG.uxpath); + printf("%s", Attach); + fflush(stdout); + GetstrP(Attach, 71, strlen(Attach)); + if (strcmp(Attach, "") == 0) + break; + + if ((stat(Attach, &sb) == 0) && (S_ISREG(sb.st_mode))) { + dospath = xstrcpy(Unix2Dos(Attach)); + if (strncasecmp(Attach, CFG.uxpath, strlen(CFG.uxpath)) == 0) { + Syslog('+', "FileAttach \"%s\"", Attach); + if (strlen(CFG.dospath)) + strcpy(Msg.Subject, dospath); + else + sprintf(Msg.Subject, "%s", Attach); + Msg.FileAttach = TRUE; + Enter(1); + colour(11, 0); + /* File */ /* will be attached */ + printf("%s %s %s", (char *)Language(464), Msg.Subject, Language(465)); + Enter(1); + fflush(stdout); + sleep(2); + break; + } else { + Enter(1); + colour(10, 0); + /* File not within */ + printf("%s \"%s\"", Language(466), CFG.uxpath); + Enter(1); + Pause(); + } + } else { + Enter(1); + /* File does not exist, please try again ... */ + pout(10, 0, (char *)Language(296)); + Enter(1); + Pause(); + } + } else { + break; + } /* if attach */ + } /* while true */ + free(Attach); + } +} + + + +/* + * Comment to sysop + */ +void SysopComment(char *Cmt) +{ + unsigned long tmp; + char *temp; + FILE *fp; + + tmp = iMsgAreaNumber; + + /* + * Make sure that the .quote file is empty. + */ + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((fp = fopen(temp, "w")) != NULL) + fclose(fp); + free(temp); + + SetMsgArea(CFG.iSysopArea -1); + sprintf(Msg.From, "%s", CFG.sysop_name); + sprintf(Msg.Subject, "%s", Cmt); + Reply_Msg(FALSE); + + SetMsgArea(tmp); +} + + + +/* + * Edit a message. Call the users preffered editor. + */ +int Edit_Msg() +{ + if (exitinfo.FsMsged) + return Fs_Edit(); + else + return Line_Edit(); +} + + + +/* + * Post a message, called from the menu or ReadPanel(). + */ +void Post_Msg() +{ + int i, x; + char *FidoNode; + faddr *Dest = NULL; + node *Nlent; + unsigned short point; + + Line = 1; + WhosDoingWhat(READ_POST); + SetMsgArea(iMsgAreaNumber); + + clear(); + if (!Post_Allowed()) + return; + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + Message[i] = (char *) calloc(81, sizeof(char)); + Line = 1; + + Msg_New(); + + colour(9, 0); + /* Posting message in area: */ + printf("\n%s\"%s\"\n", (char *) Language(156), sMsgAreaDesc); + pout(14, 0, (char *) Language(157)); + + if (msgs.Type == NEWS) { + if (CFG.EmailMode != E_PRMISP) { + /* + * If not permanent connected to the internet, use Fido style addressing. + */ + Dest = fido2faddr(CFG.EmailFidoAka); + strcpy(Msg.From, exitinfo.sUserName); + tlcap(Msg.From); + } else { + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, CFG.sysdomain, exitinfo.sUserName); + for (i = 0; i < strlen(Msg.From); i++) { + if (Msg.From[i] == ' ') + Msg.From[i] = '_'; + if (Msg.From[i] == '@') + break; + } + } + } else { + strcpy(Msg.From, exitinfo.sUserName); + tlcap(Msg.From); + } + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Msg.From); + Syslog('b', "Setting From: %s", Msg.From); + + if (msgs.Type != NEWS) { + while (TRUE) { + Enter(1); + /* To : */ + pout(14, 0, (char *) Language(158)); + + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + Getname(Msg.To, 35); + + if ((strcmp(Msg.To, "")) == 0) { + for(i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + return; + } + + if ((strcasecmp(Msg.To, "sysop")) == 0) + strcpy(Msg.To, CFG.sysop_name); + + /* + * Localmail and Echomail may be addressed to All + */ + if ((msgs.Type == LOCALMAIL) || (msgs.Type == ECHOMAIL)) { + if (strcasecmp(Msg.To, "all") == 0) + x = TRUE; + else { + /* + * Local users must exist in the userbase. + */ + if (msgs.Type == LOCALMAIL) { + /* Verifying user ... */ + pout(3, 0, (char *) Language(159)); + x = CheckUser(Msg.To); + } else + x = TRUE; + } + } else if (msgs.Type == NETMAIL) { + x = FALSE; + pout(14, 0, (char *)"Address : "); + FidoNode = calloc(61, sizeof(char)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrC(FidoNode, 60); + + if ((Dest = parsefnode(FidoNode)) != NULL) { + point = Dest->point; + Dest->point = 0; + if (((Nlent = getnlent(Dest)) != NULL) && (Nlent->addr.zone)) { + colour(14, 0); + if (point) + printf("Boss : "); + else + printf("Node : "); + Dest->point = point; + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s in %s", Nlent->name, Nlent->location); + colour(14, 0); + printf(" Is this correct Y/N: "); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + + if (toupper(Getone()) == 'Y') { + Enter(1); + sprintf(Msg.ToAddress, "%s", ascfnode(Dest, 0x1f)); + x = TRUE; + switch (Crash_Option(Dest)) { + case 1: Msg.Crash = TRUE; + break; + case 2: Msg.Immediate = TRUE; + break; + } + } + } else { + Dest->point = point; + printf("\r"); + pout(3, 0, (char *) Language(241)); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(241, 0)) { + x = TRUE; + Syslog('+', "Node %s not found, forced continue", FidoNode); + } + } + } else { + Syslog('m', "Can't parse address %s", FidoNode); + } + free(FidoNode); + } else { + x = FALSE; + } + + if(!x) { + printf("\r"); + /* User not found. Try again, or (Enter) to quit */ + pout(3, 0, (char *) Language(160)); + } else + break; + } + } else { + /* + * Newsmode, automatic addressing to All. + */ + strcpy(Msg.To, "All"); + } + + Enter(1); + /* Subject : */ + pout(14, 0, (char *) Language(161)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + GetstrP(Msg.Subject, 65, 0); + tlf(Msg.Subject); + + if((strcmp(Msg.Subject, "")) == 0) { + Enter(1); + /* Abort Message [y/N] ?: */ + pout(3, 0, (char *) Language(162)); + fflush(stdout); + alarm_on(); + + if (toupper(Getone()) == Keystroke(162, 0)) { + for(i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + return; + } + } + + /* + * If not addressed to "all" and the area is Private/Public we + * ask the user for the private flag. + */ + if ((strcasecmp(Msg.To, "all")) != 0) + Msg.Private = IsPrivate(); + + Check_Attach(); + + if (Edit_Msg()) + Save_Msg(FALSE, Dest); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); +} + + + +/* + * Save the message to disk. + */ +int Save_Msg(int IsReply, faddr *Dest) +{ + int i; + char *temp; + FILE *fp; + + if (Line < 2) + return TRUE; + + if (!Open_Msgbase(msgs.Base, 'w')) + return FALSE; + + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Written = Msg.Arrived; + Msg.Local = TRUE; + temp = calloc(PATH_MAX, sizeof(char)); + + if (strlen(Msg.ReplyTo) && (msgs.Type == NETMAIL)) { + /* + * Send message to internet gateway. + */ + Syslog('m', "UUCP message to %s", Msg.ReplyAddr); + sprintf(Msg.To, "UUCP"); + Add_Headkludges(Dest, IsReply); + sprintf(temp, "To: %s", Msg.ReplyAddr); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + } else { + Add_Headkludges(Dest, IsReply); + } + + /* + * Add message text + */ + for (i = 1; i < Line; i++) { + MsgText_Add2(Message[i]); + } + + Add_Footkludges(TRUE); + + /* + * Save if to disk + */ + Msg_AddMsg(); + Msg_UnLock(); + + ReadExitinfo(); + exitinfo.iPosted++; + WriteExitinfo(); + + do_mailout = TRUE; + + Syslog('+', "Msg (%ld) to \"%s\", \"%s\", in %ld", Msg.Id, Msg.To, Msg.Subject, iMsgAreaNumber + 1); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Saving message to disk */ + printf("\n%s(%ld)\n\n", (char *) Language(202), Msg.Id); + fflush(stdout); + sleep(2); + + msgs.LastPosted = time(NULL); + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r+")) != NULL) { + fseek(fp, msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize)), SEEK_SET); + fwrite(&msgs, msgshdr.recsize, 1, fp); + fclose(fp); + } + + /* + * Add quick mailscan info + */ + if (msgs.Type != LOCALMAIL) { + sprintf(temp, "%s/tmp/%smail.jam", getenv("MBSE_ROOT"), (msgs.Type == ECHOMAIL)? "echo" : "net"); + if ((fp = fopen(temp, "a")) != NULL) { + fprintf(fp, "%s %lu\n", msgs.Base, Msg.Id); + fclose(fp); + } + } + free(temp); + Msg_Close(); + + SetMsgArea(iMsgAreaNumber); + return TRUE; +} + + + +/* + * Show message header screen top for reading messages. + */ +void ShowMsgHdr() +{ + static char Buf1[35], Buf2[35], Buf3[81]; + struct tm *tm; + time_t now; + + Buf1[0] = '\0'; + Buf2[0] = '\0'; + Buf3[0] = '\0'; + + clear(); + colour(1,7); + printf(" %-70s", sMsgAreaDesc); + + colour(4,7); + printf("#%-5lu\n", Msg.Id); + + /* Date : */ + pout(14, 0, (char *) Language(206)); + colour(10, 0); + /* Use intermediate variable to prevent SIGBUS on Sparc's */ + now = Msg.Written; + tm = gmtime(&now); + printf("%02d-%02d-%d %02d:%02d:%02d", tm->tm_mday, tm->tm_mon+1, + tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec); + colour(12, 0); + if (Msg.Local) printf(" Local"); + if (Msg.Intransit) printf(" Transit"); + if (Msg.Private) printf(" Priv."); + if (Msg.Received) printf(" Rcvd"); + if (Msg.Sent) printf(" Sent"); + if (Msg.KillSent) printf(" KillSent"); + if (Msg.ArchiveSent) printf(" ArchiveSent"); + if (Msg.Hold) printf(" Hold"); + if (Msg.Crash) printf(" Crash"); + if (Msg.Immediate) printf(" Imm."); + if (Msg.Direct) printf(" Dir"); + if (Msg.Gate) printf(" Gate"); + if (Msg.FileRequest) printf(" Freq"); + if (Msg.FileAttach) printf(" File"); + if (Msg.TruncFile) printf(" TruncFile"); + if (Msg.KillFile) printf(" KillFile"); + if (Msg.ReceiptRequest) printf(" RRQ"); + if (Msg.ConfirmRequest) printf(" CRQ"); + if (Msg.Orphan) printf(" Orphan"); + if (Msg.Encrypt) printf(" Crypt"); + if (Msg.Compressed) printf(" Comp"); + if (Msg.Escaped) printf(" 7bit"); + if (Msg.ForcePU) printf(" FPU"); + if (Msg.Localmail) printf(" Localmail"); + if (Msg.Netmail) printf(" Netmail"); + if (Msg.Echomail) printf(" Echomail"); + if (Msg.News) printf(" News"); + if (Msg.Email) printf(" E-mail"); + if (Msg.Nodisplay) printf(" Nodisp"); + if (Msg.Locked) printf(" LCK"); + if (Msg.Deleted) printf(" Del"); + printf("\n"); + + /* From : */ + pout(14,0, (char *) Language(209)); + colour(10, 0); + printf("%s ", Msg.From); + if (iMsgAreaType != LOCALMAIL) { + colour(11, 0); + printf("(%s)", Msg.FromAddress); + } + printf("\n"); + + /* To : */ + pout(14,0, (char *) Language(208)); + colour(10, 0); + printf("%s ", Msg.To); + if (iMsgAreaType == NETMAIL) { + colour(11, 0); + printf("(%s)", Msg.ToAddress); + } + printf("\n"); + + /* Subject : */ + pout(14,0, (char *) Language(210)); + colour(10, 0); + printf("%s\n", Msg.Subject); + + colour(CFG.HiliteF, CFG.HiliteB); + colour(14, 1); + if (Msg.Reply) + sprintf(Buf1, "\"+\" %s %lu", (char *)Language(211), Msg.Reply); + if (Msg.Original) + sprintf(Buf2, " \"-\" %s %lu", (char *)Language(212), Msg.Original); + sprintf(Buf3, "%s%s ", Buf1, Buf2); + colour(14, 1); + printf("%78s \n", Buf3); +} + + + +/* + * Export a message to file in the users home directory. + */ +int Export_a_Msg(unsigned long Num) +{ + char *p; + int ShowMsg = TRUE; + + LastNum = Num; + iLineCount = 7; + WhosDoingWhat(READ_POST); + Syslog('+', "Export msg %d in area #%d (%s)", Num, iMsgAreaNumber + 1, sMsgAreaDesc); + + /* + * The area data is already set, so we can do the next things + */ + if (MsgBase.Total == 0) { + colour(15, 0); + /* There are no messages in this area */ + printf("\n%s\n\n", (char *) Language(205)); + sleep(3); + return FALSE; + } + + if (!Msg_Open(sMsgAreaBase)) { + WriteError("Error open JAM base %s", sMsgAreaBase); + return FALSE; + } + + if (!Msg_ReadHeader(Num)) { + perror(""); + colour(15, 0); + printf("\n%s\n\n", (char *)Language(77)); + Msg_Close(); + sleep(3); + return FALSE; + } + + if (Msg.Private) { + ShowMsg = FALSE; + if ((strcasecmp(exitinfo.sUserName, Msg.From) == 0) || (strcasecmp(exitinfo.sUserName, Msg.To) == 0)) + ShowMsg = TRUE; + if (exitinfo.Security.level >= msgs.SYSec.level) + ShowMsg = TRUE; + } + + if (!ShowMsg) { + printf("\n%s\n\n", (char *) Language(82)); + Msg_Close(); + sleep(3); + return FALSE; + } + + /* + * Export the message text to the file in the users home/wrk directory. + * Create the filename as _.msg The message is + * written in M$DOS format. + */ + p = calloc(128, sizeof(char)); + sprintf(p, "%s/%s/wrk/%d_%lu.msg", CFG.bbs_usersdir, exitinfo.Name, iMsgAreaNumber + 1, Num); + if ((qf = fopen(p, "w")) != NULL) { + free(p); + p = NULL; + if (Msg_Read(Num, 80)) { + if ((p = (char *)MsgText_First()) != NULL) + do { + if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) { + if (Kludges) { + if (p[0] == '\001') { + p[0] = 'a'; + fprintf(qf, "^%s\r\n", p); + } else + fprintf(qf, "%s\r\n", p); + } + } else + fprintf(qf, "%s\r\n", p); + } while ((p = (char *)MsgText_Next()) != NULL); + } + fclose(qf); + } else { + WriteError("$Can't open %s", p); + } + Msg_Close(); + + /* + * Report the result. + */ + colour(CFG.TextColourF, CFG.TextColourB); + printf("\n\n%s", (char *) Language(46)); + colour(CFG.HiliteF, CFG.HiliteB); + printf("%d_%lu.msg\n\n", iMsgAreaNumber + 1, Num); + Pause(); + return TRUE; +} + + + +/* + * Read a message on screen. Update the lastread pointers, + * except while scanning and reading new mail at logon. + */ +int Read_a_Msg(unsigned long Num, int UpdateLR) +{ + char *p = NULL, *fn; + int ShowMsg = TRUE; + lastread LR; + + LastNum = Num; + iLineCount = 7; + WhosDoingWhat(READ_POST); + + /* + * The area data is already set, so we can do the next things + */ + if (MsgBase.Total == 0) { + colour(15, 0); + /* There are no messages in this area */ + printf("\n%s\n\n", (char *) Language(205)); + sleep(3); + return FALSE; + } + + if (!Msg_Open(sMsgAreaBase)) { + WriteError("Error open JAM base %s", sMsgAreaBase); + return FALSE; + } + + if (!Msg_ReadHeader(Num)) { + perror(""); + colour(15, 0); + printf("\n%s\n\n", (char *)Language(77)); + Msg_Close(); + sleep(3); + return FALSE; + } + if (Msg.Private) { + ShowMsg = FALSE; + if ((strcasecmp(exitinfo.sUserName, Msg.From) == 0) || (strcasecmp(exitinfo.sUserName, Msg.To) == 0)) + ShowMsg = TRUE; + if (exitinfo.Security.level >= msgs.SYSec.level) + ShowMsg = TRUE; + } + if (!ShowMsg) { + printf("\n%s\n\n", (char *) Language(82)); + Msg_Close(); + sleep(3); + return FALSE; + } + ShowMsgHdr(); + + /* + * Fill Quote file in case the user wants to reply. Note that line + * wrapping is set lower then normal message read, to create room + * for the Quote> strings at the start of each line. + */ + fn = calloc(128, sizeof(char)); + sprintf(fn, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((qf = fopen(fn, "w")) != NULL) { + if (Msg_Read(Num, 75)) { + if ((p = (char *)MsgText_First()) != NULL) + do { + if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) { + if (Kludges) { + if (p[0] == '\001') { + p[0] = 'a'; + fprintf(qf, "^%s\n", p); + } else + fprintf(qf, "%s\n", p); + } + } else + fprintf(qf, "%s\n", p); + } while ((p = (char *)MsgText_Next()) != NULL); + } + fclose(qf); + } else { + WriteError("$Can't open %s", p); + } + free(fn); + + /* + * Show message text + */ + colour(CFG.TextColourF, CFG.TextColourB); + if (Msg_Read(Num, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) { + if (Kludges) { + colour(7, 0); + printf("%s\n", p); + if (CheckLine(CFG.TextColourF, CFG.TextColourB, FALSE)) + break; + } + } else { + colour(CFG.TextColourF, CFG.TextColourB); + if (strchr(p, '>') != NULL) + if ((strlen(p) - strlen(strchr(p, '>'))) < 10) + colour(CFG.HiliteF, CFG.HiliteB); + printf("%s\n", p); + if (CheckLine(CFG.TextColourF, CFG.TextColourB, FALSE)) + break; + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + /* + * Set the Received status on this message if it's for the user. + */ + if ((!Msg.Received) && (strlen(Msg.To) > 0) && + ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || (strcasecmp(exitinfo.sHandle, Msg.To) == 0))) { + Syslog('m', "Marking message received"); + Msg.Received = TRUE; + Msg.Read = time(NULL) - (gmt_offset((time_t)0) * 60); + if (Msg_Lock(30L)) { + Msg_WriteHeader(Num); + Msg_UnLock(); + } + } + + /* + * Update lastread pointer if needed. Netmail boards are always updated. + */ + if (Msg_Lock(30L) && (UpdateLR || msgs.Type == NETMAIL)) { + LR.UserID = grecno; + p = xstrcpy(exitinfo.sUserName); + if (Msg_GetLastRead(&LR) == TRUE) { + LR.LastReadMsg = Num; + if (Num > LR.HighReadMsg) + LR.HighReadMsg = Num; + if (LR.HighReadMsg > MsgBase.Highest) + LR.HighReadMsg = MsgBase.Highest; + LR.UserCRC = StringCRC32(tl(p)); + if (!Msg_SetLastRead(LR)) + WriteError("Error update lastread"); + } else { + /* + * Append new lastread pointer + */ + LR.UserCRC = StringCRC32(tl(p)); + LR.UserID = grecno; + LR.LastReadMsg = Num; + LR.HighReadMsg = Num; + if (!Msg_NewLastRead(LR)) + WriteError("Can't append lastread"); + } + free(p); + Msg_UnLock(); + } + + Msg_Close(); + return TRUE; +} + + + +/* + * Read Messages, called from menu + */ +void Read_Msgs() +{ + char *temp; + unsigned long Start; + lastread LR; + + colour(CFG.TextColourF, CFG.TextColourB); + /* Message area \"%s\" contains %lu messages. */ + printf("\n%s\"%s\" %s%lu %s", (char *) Language(221), sMsgAreaDesc, (char *) Language(222), MsgBase.Total, (char *) Language(223)); + + /* + * Check for lastread pointer, suggest lastread number for start. + */ + Start = MsgBase.Lowest; + if (Msg_Open(sMsgAreaBase)) { + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg + 1; + else + Start = 1; + Msg_Close(); + /* + * If we already have read the last message, the pointer is + * higher then HighMsgNum, we set it at HighMsgNum to prevent + * errors and read that message again. + */ + if (Start > MsgBase.Highest) + Start = MsgBase.Highest; + } + + colour(15, 0); + /* Please enter a message between */ + printf("\n%s(%lu - %lu)", (char *) Language(224), MsgBase.Lowest, MsgBase.Highest); + /* Message number [ */ + printf("\n%s%lu]: ", (char *) Language(225), Start); + + temp = calloc(81, sizeof(char)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if ((strcmp(temp, "")) != 0) + Start = atoi(temp); + free(temp); + + if (!Read_a_Msg(Start, TRUE)) + return; + + if (MsgBase.Total == 0) + return; + + while(ReadPanel()) {} +} + + + +/* + * The panel bar under the messages while reading + */ +int ReadPanel() +{ + int input; + + WhosDoingWhat(READ_POST); + + colour(15, 4); + if (msgs.UsrDelete || exitinfo.Security.level >= CFG.sysop_access) { + /* (A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (D)elete, (Q)uit, e(X)port */ + printf("%s", (char *) Language(214)); + } else { + /* (A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (Q)uit, e(X)port */ + printf("%s", (char *) Language(215)); + } + if (exitinfo.Security.level >= CFG.sysop_access) + printf(", (!)"); + + printf(": "); + + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + + if (input == '!') { + if (exitinfo.Security.level >= CFG.sysop_access) { + if (Kludges) + Kludges = FALSE; + else + Kludges = TRUE; + } + Read_a_Msg(LastNum, TRUE); + } else if (input == Keystroke(214, 0)) { /* (A)gain */ + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 4)) { /* (P)ost */ + Post_Msg(); + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 2)) { /* (L)ast */ + if (LastNum > MsgBase.Lowest) + LastNum--; + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 3)) { /* (R)eply */ + Reply_Msg(TRUE); + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 5)) { /* (Q)uit */ + /* Quit */ + printf("%s\n", (char *) Language(189)); + return FALSE; + + } else if (input == Keystroke(214, 7)) { /* e(X)port */ + Export_a_Msg(LastNum); + Read_a_Msg(LastNum, TRUE); + + } else if (input == '+') { + if (Msg.Reply) + LastNum = Msg.Reply; + Read_a_Msg(LastNum, TRUE); + + } else if (input == '-') { + if (Msg.Original) + LastNum = Msg.Original; + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 6)) { /* (D)elete */ + Delete_MsgNum(LastNum); + if (LastNum < MsgBase.Highest) { + LastNum++; + Read_a_Msg(LastNum, TRUE); + } else { + return FALSE; + } + } else { + /* Next */ + pout(15, 0, (char *) Language(216)); + if (LastNum < MsgBase.Highest) + LastNum++; + else + return FALSE; + Read_a_Msg(LastNum, TRUE); + } + return TRUE; +} + + + +/* + * Reply message, in Msg.From and Msg.Subject must be the + * name to reply to and the subject. IsReply is true if the + * message is a real reply, and false for forced messages such + * as "message to sysop" + */ +void Reply_Msg(int IsReply) +{ + int i, j, x; + char to[65]; + char from[65]; + char subj[72]; + char msgid[81]; + char replyto[81]; + char replyaddr[81]; + char *tmp, *buf; + char qin[6]; + faddr *Dest = NULL; + + if (!Post_Allowed()) + return; + + sprintf(from, "%s", Msg.To); + sprintf(to, "%s", Msg.From); + sprintf(replyto, "%s", Msg.ReplyTo); + sprintf(replyaddr, "%s", Msg.ReplyAddr); + Dest = parsefnode(Msg.FromAddress); + Syslog('m', "Parsed from address %s", ascfnode(Dest, 0x1f)); + + if (strncasecmp(Msg.Subject, "Re:", 3) && strncasecmp(Msg.Subject, "Re^2:", 5) && IsReply) { + sprintf(subj, "Re: %s", Msg.Subject); + } else { + sprintf(subj, "%s", Msg.Subject); + } + Syslog('m', "Reply msg to %s, subject %s", to, subj); + Syslog('m', "Msgid was %s", Msg.Msgid); + sprintf(msgid, "%s", Msg.Msgid); + + x = 0; + WhosDoingWhat(READ_POST); + clear(); + colour(1,7); + printf(" %-71s", sMsgAreaDesc); + colour(4,7); + printf("#%-5lu", MsgBase.Highest + 1); + + colour(CFG.HiliteF, CFG.HiliteB); + sLine(); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + Message[i] = (char *) calloc(81, sizeof(char)); + Msg_New(); + + sprintf(Msg.Replyid, "%s", msgid); + sprintf(Msg.ReplyTo, "%s", replyto); + sprintf(Msg.ReplyAddr, "%s", replyaddr); + + /* From : */ + sprintf(Msg.From, "%s", exitinfo.sUserName); + pout(14, 0, (char *) Language(209)); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.From); + Enter(1); + + /* To : */ + sprintf(Msg.To, "%s", to); + pout(14, 0, (char *) Language(208)); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.To); + Enter(1); + + /* Enter to keep Subject. */ + pout(12, 0, (char *) Language(219)); + Enter(1); + /* Subject : */ + pout(14, 0, (char *) Language(210)); + sprintf(Msg.Subject, "%s", subj); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.Subject); + + x = strlen(subj); + fflush(stdout); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrP(subj, 50, x); + fflush(stdout); + + if (strlen(subj)) + strcpy(Msg.Subject, subj); + tlf(Msg.Subject); + + Msg.Private = IsPrivate(); + Enter(1); + + /* + * If netmail reply and enough security level, allow crashmail. + */ + if (msgs.Type == NETMAIL) { + switch (Crash_Option(Dest)) { + case 1: Msg.Crash = TRUE; + break; + case 2: Msg.Immediate = TRUE; + break; + } + } + + Check_Attach(); + + /* + * Quote original message now, format the original users + * initials into qin. No quoting if this is a message to Sysop. + */ + Line = 1; + if (IsReply) { + sprintf(Message[1], "%s wrote to %s:", to, from); + memset(&qin, 0, sizeof(qin)); + x = TRUE; + j = 0; + for (i = 0; i < strlen(to); i++) { + if (x) { + qin[j] = to[i]; + j++; + x = FALSE; + } + if (to[i] == ' ' || to[i] == '.') + x = TRUE; + if (j == 6) + break; + } + Line = 2; + + tmp = calloc(128, sizeof(char)); + buf = calloc(128, sizeof(char)); + + sprintf(tmp, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((qf = fopen(tmp, "r")) != NULL) { + while ((fgets(buf, 128, qf)) != NULL) { + Striplf(buf); + sprintf(Message[Line], "%s> %s", (char *)qin, buf); + Line++; + if (Line == TEXTBUFSIZE) + break; + } + fclose(qf); + } else + WriteError("$Can't read %s", tmp); + + free(buf); + free(tmp); + } + + if (Edit_Msg()) + Save_Msg(IsReply, Dest); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); +} + + + +int IsMe(char *Name) +{ + char *p, *q; + int i, rc = FALSE; + + if (strlen(Name) == 0) + return FALSE; + + if (strcasecmp(Name, exitinfo.sUserName) == 0) + rc = TRUE; + + if (strcasecmp(Name, exitinfo.sHandle) == 0) + rc = TRUE; + + q = xstrcpy(Name); + if (strstr(q, (char *)"@")) { + p = strtok(q, "@"); + for (i = 0; i < strlen(p); i++) + if (p[i] == '_') + p[i] = ' '; + if (strcasecmp(p, exitinfo.sUserName) == 0) + rc = TRUE; + if (strcasecmp(p, exitinfo.sHandle) == 0) + rc = TRUE; + if (strcasecmp(p, exitinfo.Name) == 0) + rc = TRUE; + } + free(q); + return rc ; +} + + + +void QuickScan_Msgs() +{ + int FoundMsg = FALSE; + long i; + + iLineCount = 2; + WhosDoingWhat(READ_POST); + + if (MsgBase.Total == 0) { + Enter(1); + /* There are no messages in this area. */ + pout(15, 0, (char *) Language(205)); + Enter(3); + sleep(3); + return; + } + + clear(); + /* # From To Subject */ + poutCR(14, 1, (char *) Language(220)); + + if (Msg_Open(sMsgAreaBase)) { + for (i = MsgBase.Lowest; i <= MsgBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + + colour(15, 0); + printf("%-6lu", Msg.Id); + if (IsMe(Msg.From)) + colour(11, 0); + else + colour(3, 0); + printf("%s ", padleft(Msg.From, 20, ' ')); + + if (IsMe(Msg.To)) + colour(10, 0); + else + colour(2, 0); + printf("%s ", padleft(Msg.To, 20, ' ')); + colour(5, 0); + printf("%s", padleft(Msg.Subject, 31, ' ')); + printf("\n"); + FoundMsg = TRUE; + if (LC(1)) + break; + } + } + Msg_Close(); + } + + if(!FoundMsg) { + Enter(1); + /* There are no messages in this area. */ + pout(10, 0, (char *) Language(205)); + Enter(2); + sleep(3); + } + + iLineCount = 2; + Pause(); +} + + + +/* + * Called from the menu + */ +void Delete_Msg() +{ + return; +} + + + +/* + * Check linecounter for reading messages. + */ +int CheckLine(int FG, int BG, int Email) +{ + int i, x, z; + + x = strlen(Language(61)); + iLineCount++; + + if ((iLineCount >= (exitinfo.iScreenLen -1)) && (iLineCount < 1000)) { + iLineCount = 7; + + DoNop(); + pout(CFG.MoreF, CFG.MoreB, (char *) Language(61)); + + fflush(stdout); + alarm_on(); + z = tolower(Getone()); + + for (i = 0; i < x; i++) + putchar('\b'); + for (i = 0; i < x; i++) + putchar(' '); + for (i = 0; i < x; i++) + putchar('\b'); + fflush(stdout); + + switch(z) { + + case 'n': + printf("\n"); + return TRUE; + break; + case '=': + iLineCount = 1000; + } + if (Email) + ShowEmailHdr(); + else + ShowMsgHdr(); + colour(FG, BG); + } + return FALSE; +} + + + +/* + * Select message area from the list. + */ +void MsgArea_List(char *Option) +{ + FILE *pAreas; + int iAreaCount = 6, Recno = 0; + int iOldArea = 0, iAreaNum = 0; + int iGotArea = FALSE; /* Flag to check if user typed in area */ + long offset; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp,"%s/etc/mareas.data", getenv("MBSE_ROOT")); + + /* + * Save old area, incase he picks a invalid area + */ + iOldArea = iMsgAreaNumber; + + if(( pAreas = fopen(temp, "rb")) == NULL) { + WriteError("Can't open msg areas file: %s", temp); + free(temp); + fclose(pAreas); + return; + } + + /* + * Count how many records there are + */ + fread(&msgshdr, sizeof(msgshdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreaNum = (ftell(pAreas) - msgshdr.hdrsize) / (msgshdr.recsize + msgshdr.syssize); + + /* + * If there are menu options, select area direct. + */ + if (strlen(Option) != 0) { + + if (strcmp(Option, "M+") == 0) + while(TRUE) { + iMsgAreaNumber++; + if (iMsgAreaNumber >= iAreaNum) + iMsgAreaNumber = 0; + + offset = msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize)); + if(fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer there."); + } + + fread(&msgs, msgshdr.recsize, 1, pAreas); + if ((Access(exitinfo.Security, msgs.RDSec)) && (msgs.Active) && (strlen(msgs.Password) == 0)) + break; + } + + if (strcmp(Option, "M-") == 0) + while(TRUE) { + iMsgAreaNumber--; + if (iMsgAreaNumber < 0) + iMsgAreaNumber = iAreaNum -1; + + offset = msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize)); + if(fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer there."); + } + + fread(&msgs, msgshdr.recsize, 1, pAreas); + if ((Access(exitinfo.Security, msgs.RDSec)) && (msgs.Active) && (strlen(msgs.Password) == 0)) + break; + } + SetMsgArea(iMsgAreaNumber); + Syslog('+', "Msg area %lu %s", iMsgAreaNumber, sMsgAreaDesc); + free(temp); + fclose(pAreas); + return; + } + + clear(); + Enter(1); + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(231)); + Enter(2); + + fseek(pAreas, msgshdr.hdrsize, 0); + + while (fread(&msgs, msgshdr.recsize, 1, pAreas) == 1) { + /* + * Skip the echomail systems + */ + fseek(pAreas, msgshdr.syssize, SEEK_CUR); + if ((Access(exitinfo.Security, msgs.RDSec)) && (msgs.Active)) { + msgs.Name[31] = '\0'; + + colour(15,0); + printf("%5d", Recno + 1); + + colour(9,0); + printf(" %c ", 46); + + colour(3,0); + printf("%-31s", msgs.Name); + + iAreaCount++; + + if ((iAreaCount % 2) == 0) + printf("\n"); + else + printf(" "); + } + + Recno++; + + if((iAreaCount / 2) == exitinfo.iScreenLen) { + /* More (Y/n/=/Area #): */ + pout(CFG.MoreF, CFG.MoreB, (char *) Language(207)); + /* + * Ask user for Area or enter to continue + */ + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(temp, 7); + + if (toupper(temp[0]) == Keystroke(207, 1)) + break; + + if ((strcmp(temp, "")) != 0) { + iGotArea = TRUE; + break; + } + + iAreaCount = 2; + } + } + + /* + * If user type in area above during area listing + * don't ask for it again + */ + if (!iGotArea) { + Enter(1); + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(232)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + } + + /* + * Check if user pressed ENTER + */ + if ((strcmp(temp, "")) == 0) { + fclose(pAreas); + return; + } + iMsgAreaNumber = atoi(temp); + iMsgAreaNumber--; + + /* + * Do a check in case user presses Zero + */ + if (iMsgAreaNumber == -1) + iMsgAreaNumber = 0; + + offset = msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize)); + if(fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer there."); + } + fread(&msgs, msgshdr.recsize, 1, pAreas); + + /* + * Do a check if area is greater or less number than allowed, + * security acces (level, flags and age) is oke, and the area + * is active. + */ + if (iMsgAreaNumber > iAreaNum || iMsgAreaNumber < 0 || (Access(exitinfo.Security, msgs.RDSec) == FALSE) || (!msgs.Active)) { + Enter(1); + /* + * Invalid area specified - Please try again ... + */ + pout(12, 0, (char *) Language(233)); + Enter(2); + Pause(); + fclose(pAreas); + iMsgAreaNumber = iOldArea; + SetMsgArea(iMsgAreaNumber); + free(temp); + return; + } + + SetMsgArea(iMsgAreaNumber); + Syslog('+', "Msg area %lu %s", iMsgAreaNumber, sMsgAreaDesc); + + /* + * Check if msg area has a password, if it does ask user for it + */ + if((strlen(msgs.Password)) > 2) { + Enter(2); + /* Please enter Area Password: */ + pout(15, 0, (char *) Language(233)); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 20); + + if((strcmp(temp, msgs.Password)) != 0) { + Enter(1); + pout(15, 0, (char *) Language(234)); + Syslog('!', "Incorrect Message Area # %d password given: %s", iMsgAreaNumber, temp); + SetMsgArea(iOldArea); + } else { + Enter(1); + pout(15, 0, (char *) Language(235)); + Enter(2); + } + Pause(); + } + + free(temp); + fclose(pAreas); +} + + + +/* + * Function deletes a specified message. + */ +void Delete_MsgNum(unsigned long MsgNum) +{ + int Result = FALSE; + + pout(12, 0, (char *) Language(230)); + + if (Msg_Open(sMsgAreaBase)) { + if (Msg_Lock(15L)) { + Result = Msg_Delete(MsgNum); + Msg_UnLock(); + } + Msg_Close(); + } + + if (Result) + Syslog('+', "Deleted msg #%lu in Area #%d (%s)", MsgNum, iMsgAreaNumber, sMsgAreaDesc); + else + WriteError("ERROR delete msg #%lu in Area #%d (%s)", MsgNum, iMsgAreaNumber, sMsgAreaDesc); +} + + + +/* + * This Function checks to see if the user exists in the user database + * and returns a int TRUE or FALSE + */ +int CheckUser(char *To) +{ + FILE *pUsrConfig; + int Found = FALSE; + char *temp; + long offset; + unsigned long Crc; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp,"rb")) == NULL) { + perror(""); + WriteError("Can't open file %s for reading", temp); + Pause(); + free(temp); + return FALSE; + } + free(temp); + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + Crc = StringCRC32(tl(To)); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig) == 1) { + if (StringCRC32(tl(usrconfig.sUserName)) == Crc) { + Found = TRUE; + break; + } + } + + if (!Found) + Syslog('!', "User attempted to mail unknown user: %s", tlcap(To)); + + /* + * Restore users record + */ + offset = usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize); + if (fseek(pUsrConfig, offset, 0) != 0) + printf("Can't move pointer there."); + else + fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig); + fclose(pUsrConfig); + + return Found; +} + + + +/* + * Check for new mail + */ +void CheckMail() +{ + FILE *pMsgArea, *Tmp; + int x, Found = 0; + int Color, Count = 0, Reading; + int OldMsgArea; + char *temp; + char *sFileName; + unsigned long i, Start; + typedef struct _Mailrec { + long Area; + unsigned long Msg; + } _Mail; + _Mail Mail; + lastread LR; + + OldMsgArea = iMsgAreaNumber; + iMsgAreaNumber = 0; + Syslog('+', "Start checking for new mail"); + + clear(); + /* Checking your mail box ... */ + language(10, 0, 150); + Enter(2); + Color = 9; + fflush(stdout); + + /* + * Open temporary file + */ + if ((Tmp = tmpfile()) == NULL) { + WriteError("$unable to open temporary file"); + return; + } + + /* + * First check the e-mail mailbox + */ + temp = calloc(PATH_MAX, sizeof(char)); + if (exitinfo.Email && strlen(exitinfo.Password)) { + check_popmail(exitinfo.Name, exitinfo.Password); + colour(Color, 0); + printf("\re-mail Private e-mail mailbox"); + fflush(stdout); + Color++; + Count = 0; + sprintf(temp, "%s/%s/mailbox", CFG.bbs_usersdir, exitinfo.Name); + SetEmailArea((char *)"mailbox"); + if (Msg_Open(temp)) { + /* + * Check lastread pointer, if none found start + * at the begin of the messagebase. + */ + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg + 1; + else + Start = EmailBase.Lowest; + + for (i = Start; i <= EmailBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + /* + * Only check the received status of the email. The mail + * may not be direct addressed to this user (aliases database) + * but if it is in his mailbox it is always for the user. + */ + if (!Msg.Received) { + /* + * Store area and message number in temporary file. + */ + Mail.Area = -1; /* Means e-mail mailbox */ + Mail.Msg = Msg.Id + EmailBase.Lowest -1; + fwrite(&Mail, sizeof(Mail), 1, Tmp); + Count++; + Found++; + } + } + } + Msg_Close(); + } + if (Count) { + colour(CFG.TextColourF, CFG.TextColourB); + /* messages in */ + printf("\n\n%d %s private e-mail mailbox\n\n", Count, (char *)Language(213)); + Syslog('m', " %d messages in private e-mail mailbox", Count); + } + } + + /* + * Open the message base configuration + */ + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/mareas.data", getenv("MBSE_ROOT")); + if((pMsgArea = fopen(sFileName, "r+")) == NULL) { + WriteError("$Can't open: %s", sFileName); + free(temp); + free(sFileName); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, pMsgArea); + + /* + * Check all normal areas one by one + */ + while (fread(&msgs, msgshdr.recsize, 1, pMsgArea) == 1) { + fseek(pMsgArea, msgshdr.syssize, SEEK_CUR); + if ((msgs.Active) && (exitinfo.Security.level >= msgs.RDSec.level)) { + SetMsgArea(iMsgAreaNumber); + sprintf(temp, "%d", iMsgAreaNumber + 1); + colour(Color, 0); + if (Color < 15) + Color++; + else + Color = 9; + printf("\r%6s %-40s", temp, sMsgAreaDesc); + fflush(stdout); + Count = 0; + Nopper(); + + if (Msg_Open(sMsgAreaBase)) { + /* + * Check lastread pointer, if none found start + * at the begin of the messagebase. + */ + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg + 1; + else + Start = MsgBase.Lowest; + + for (i = Start; i <= MsgBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + if ((!Msg.Received) && (IsMe(Msg.To))) { + /* + * Store area and message number + * in temporary file. + */ + Mail.Area = iMsgAreaNumber; + Mail.Msg = Msg.Id + MsgBase.Lowest -1; + fwrite(&Mail, sizeof(Mail), 1, Tmp); + Count++; + Found++; + } + } + } + Msg_Close(); + } + if (Count) { + colour(CFG.TextColourF, CFG.TextColourB); + /* messages in */ + printf("\n\n%d %s %s\n\n", Count, (char *)Language(213), sMsgAreaDesc); + Syslog('m', " %d messages in %s", Count, sMsgAreaDesc); + } + } + iMsgAreaNumber++; + } + + fclose(pMsgArea); + putchar('\r'); + for (i = 0; i < 48; i++) + putchar(' '); + putchar('\r'); + + if (Found) { + colour(14, 0); + /* You have messages, read your mail now? [Y/n]: */ + printf("\n%s%d %s", (char *) Language(142), Found, (char *) Language(143)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + fflush(stdin); + alarm_on(); + + if (toupper(Getone()) != Keystroke(143,1)) { + rewind(Tmp); + Reading = TRUE; + + while ((Reading) && (fread(&Mail, sizeof(Mail), 1, Tmp) == 1)) { + if (Mail.Area == -1) { + /* + * Private e-mail + */ + Read_a_Email(Mail.Msg); + } else { + SetMsgArea(Mail.Area); + Read_a_Msg(Mail.Msg, FALSE); + } + /* (R)eply, (N)ext, (Q)uit */ + pout(CFG.CRColourF, CFG.CRColourB, (char *)Language(218)); + fflush(stdout); + fflush(stdin); + alarm_on(); + x = toupper(Getone()); + + if (x == Keystroke(218, 0)) { + Syslog('m', " Reply!"); + if (Mail.Area == -1) { + } else { + Reply_Msg(TRUE); + } + } + if (x == Keystroke(218, 2)) { + Syslog('m', " Quit check for new mail"); + iMsgAreaNumber = OldMsgArea; + fclose(Tmp); + SetMsgArea(OldMsgArea); + printf("\n\n"); + free(temp); + free(sFileName); + return; + } + } + } + } else { + language(12, 0, 144); + Enter(1); + sleep(3); + } /* if (Found) */ + + iMsgAreaNumber = OldMsgArea; + fclose(Tmp); + SetMsgArea(OldMsgArea); + printf("\n\n"); + free(temp); + free(sFileName); +} + + + +/* + * Status of all mail areas. + */ +void MailStatus() +{ + FILE *pMsgArea; + int Count = 0; + int OldMsgArea; + char temp[81]; + char *sFileName; + unsigned long i; + + sFileName = calloc(PATH_MAX, sizeof(char)); + OldMsgArea = iMsgAreaNumber; + iMsgAreaNumber = 0; + clear(); + colour(14, 1); + /* Area Type Description Messages Personal */ + printf("%-79s", (char *)Language(226)); + Enter(1); + iLineCount = 2; + fflush(stdout); + + if (exitinfo.Email) { + sprintf(temp, "%s", sMailbox); + for (i = 0; i < 3; i++) { + switch (i) { + case 0: SetEmailArea((char *)"mailbox"); + break; + case 1: SetEmailArea((char *)"archive"); + break; + case 2: SetEmailArea((char *)"trash"); + break; + } + colour(12, 0); + printf(" Email"); + colour(11, 0); + printf(" %-40s", Language(467 + i)); + colour(14, 0); + if (EmailBase.Highest) + printf(" %8lu", EmailBase.Highest - EmailBase.Lowest + 1); + else + printf(" 0"); + colour(9, 0); + if (EmailBase.Highest) + printf(" %8lu\n", EmailBase.Highest - EmailBase.Lowest + 1); + else + printf(" 0\n"); + } + iLineCount = 5; + SetEmailArea(temp); + } + + /* + * Open the message base configuration + */ + sprintf(sFileName,"%s/etc/mareas.data", getenv("MBSE_ROOT")); + if((pMsgArea = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + free(sFileName); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, pMsgArea); + + /* + * Check all areas one by one + */ + while (fread(&msgs, msgshdr.recsize, 1, pMsgArea) == 1) { + fseek(pMsgArea, msgshdr.syssize, SEEK_CUR); + if ((msgs.Active) && (exitinfo.Security.level >= msgs.RDSec.level)) { + SetMsgArea(iMsgAreaNumber); + sprintf(temp, "%d", iMsgAreaNumber + 1); + colour(15, 0); + printf("%5s", temp); + colour(12, 0); + switch(msgs.Type) { + case LOCALMAIL: + printf(" Local"); + break; + + case NETMAIL: + printf(" Net "); + break; + + case ECHOMAIL: + printf(" Echo "); + break; + + case NEWS: + printf(" News "); + break; + } + colour(11, 0); + printf(" %-40s", sMsgAreaDesc); + Count = 0; + + if (Msg_Open(sMsgAreaBase)) { + for (i = MsgBase.Lowest; i <= MsgBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + if (IsMe(Msg.To) || IsMe(Msg.From)) + Count++; + } + } + Msg_Close(); + } else + WriteError("Error open JAM %s", sMsgAreaBase); + colour(14, 0); + if (MsgBase.Highest) + printf(" %8lu", MsgBase.Highest - MsgBase.Lowest + 1); + else + printf(" 0"); + colour(9, 0); + printf(" %8d\n", Count); + if (LC(1)) + break; + } + iMsgAreaNumber++; + } + + fclose(pMsgArea); + SetMsgArea(OldMsgArea); + free(sFileName); + Pause(); +} + + + +/* + * Set message area number, set global area description and JAM path + */ +void SetMsgArea(unsigned long AreaNum) +{ + FILE *pMsgArea; + long offset; + char *sFileName; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/mareas.data", getenv("MBSE_ROOT")); + memset(&msgs, 0, sizeof(msgs)); + + if((pMsgArea = fopen(sFileName, "r")) == NULL) { + WriteError("$Can't open file: %s", sFileName); + free(sFileName); + return; + } + + fread(&msgshdr, sizeof(msgshdr), 1, pMsgArea); + offset = msgshdr.hdrsize + (AreaNum * (msgshdr.recsize + msgshdr.syssize)); + if(fseek(pMsgArea, offset, 0) != 0) { + WriteError("$Can't move pointer in %s",sFileName); + free(sFileName); + return; + } + + fread(&msgs, msgshdr.recsize, 1, pMsgArea); + strcpy(sMsgAreaDesc, msgs.Name); + strcpy(sMsgAreaBase, msgs.Base); + iMsgAreaNumber = AreaNum; + iMsgAreaType = msgs.Type; + + fclose(pMsgArea); + + /* + * Get information from the message base + */ + + if (Msg_Open(sMsgAreaBase)) { + + MsgBase.Lowest = Msg_Lowest(); + MsgBase.Highest = Msg_Highest(); + MsgBase.Total = Msg_Number(); + Msg_Close(); + } else + WriteError("Error open JAM %s", sMsgAreaBase); + free(sFileName); +} + + + diff --git a/mbsebbs/mail.h b/mbsebbs/mail.h new file mode 100644 index 00000000..cdd79b58 --- /dev/null +++ b/mbsebbs/mail.h @@ -0,0 +1,21 @@ +#ifndef _MAIL_H +#define _MAIL_H + +#define TEXTBUFSIZE 500 + +int LC(int); /* More prompt for reading messages */ +int Edit_Msg(void); /* Edit a message */ +int CheckLine(int, int, int); /* Check linecounter for read */ +void SysopComment(char *); /* Comment to Sysop */ +void Post_Msg(void); /* Post a message */ +void Read_Msgs(void); /* Read Messages */ +void QuickScan_Msgs(void); /* List Message Headers */ +void Delete_Msg(void); /* Delete a specified message */ +void MsgArea_List(char *); /* Select message area */ +void CheckMail(void); /* Check for new mail */ +void MailStatus(void); /* Mail status in areas */ +void SetMsgArea(unsigned long); /* Set message area and variables */ + + +#endif + diff --git a/mbsebbs/mball.c b/mbsebbs/mball.c new file mode 100644 index 00000000..a9af5290 --- /dev/null +++ b/mbsebbs/mball.c @@ -0,0 +1,963 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/mball.c + * Purpose ...............: Creates allfiles listings + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/mbse.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbcfg.h" +#include "../lib/clcomm.h" +#include "mball.h" + + +extern int do_quiet; /* Supress screen output */ +int do_zip = FALSE; /* Create ZIP archives */ +int do_list = FALSE; /* Create filelist */ +int do_index = FALSE; /* Create 00index files */ +extern int e_pid; /* Pid of child */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +struct tm *l_date; /* Structure for Date */ +int lastfile; /* Last file number */ + + +static char *wdays[]={(char *)"Sun",(char *)"Mon",(char *)"Tue",(char *)"Wed",(char *)"Thu",(char *)"Fri",(char *)"Sat"}; +static char *months[]={(char *)"Jan",(char *)"Feb",(char *)"Mar",(char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep",(char *)"Oct",(char *)"Nov",(char *)"Dec"}; + + + +void ProgName() +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBALL: MBSE BBS %s Allfiles Listing Creator\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + /* + * First check if a child is running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeded", e_pid); + else + WriteError("$Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode... + */ + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBALL finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +void Help() +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mball [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" i index Create \"00index\" files and WWW pages in areas\n"); + printf(" l list Create allfiles and newfiles lists\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -q -quiet Quiet mode\n"); + printf(" -z -zip Create .zip archives\n"); + colour(7, 0); + printf("\n"); + die(0); +} + + + +int main(int argc, char **argv) +{ + int i; + char *cmd; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + + InitConfig(); + TermInit(1); + time(&t_start); + umask(000); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGKILL) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line: mball"); + + for (i = 1; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + + if (!strncasecmp(argv[i], "l", 1)) + do_list = TRUE; + if (!strncasecmp(argv[i], "i", 1)) + do_index = TRUE; + if (!strncasecmp(argv[i], "-q", 2)) + do_quiet = TRUE; + if (!strncasecmp(argv[i], "-z", 2)) + do_zip = TRUE; + } + + if (!(do_list || do_index)) + Help(); + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mball", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBALL v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + colour(3, 0); + printf("\n"); + } + + if (do_list) { + Masterlist(); + if (do_zip) + MakeArc(); + } + + if (do_index) + MakeIndex(); + + if (do_list) + CreateSema((char *)"mailin"); + + if (!do_quiet) + printf("Done!\n"); + + die(0); + return 0; +} + + + +/* + * Translate ISO 8859-1 characters to named character entities + */ +void html_massage(char *, char *); +void html_massage(char *inbuf, char *outbuf) +{ + char *inptr = inbuf; + char *outptr = outbuf; + + memset(outbuf, 0, sizeof(outbuf)); + + while (*inptr) { + + switch ((unsigned char)*inptr) { + case '"': sprintf(outptr, """); break; + case '&': sprintf(outptr, "&"); break; + case '<': sprintf(outptr, "<"); break; + case '>': sprintf(outptr, ">"); break; + case 160: sprintf(outptr, " "); break; + case 161: sprintf(outptr, "¡"); break; + case 162: sprintf(outptr, "¢"); break; + case 163: sprintf(outptr, "£"); break; + case 164: sprintf(outptr, "¤"); break; + case 165: sprintf(outptr, "¥"); break; + case 166: sprintf(outptr, "¦"); break; + case 167: sprintf(outptr, "§"); break; + case 168: sprintf(outptr, "¨"); break; + case 169: sprintf(outptr, "©"); break; + case 170: sprintf(outptr, "ª"); break; + case 171: sprintf(outptr, "«"); break; + case 172: sprintf(outptr, "¬"); break; + case 173: sprintf(outptr, "­"); break; + case 174: sprintf(outptr, "®"); break; + case 175: sprintf(outptr, "¯"); break; + case 176: sprintf(outptr, "°"); break; + case 177: sprintf(outptr, "&plumn;"); break; + case 178: sprintf(outptr, "²"); break; + case 179: sprintf(outptr, "³"); break; + case 180: sprintf(outptr, "´"); break; + case 181: sprintf(outptr, "µ"); break; + case 182: sprintf(outptr, "¶"); break; + case 183: sprintf(outptr, "·"); break; + case 184: sprintf(outptr, "¸"); break; + case 185: sprintf(outptr, "&supl;"); break; + case 186: sprintf(outptr, "º"); break; + case 187: sprintf(outptr, "»"); break; + case 188: sprintf(outptr, "¼"); break; + case 189: sprintf(outptr, "½"); break; + case 190: sprintf(outptr, "¾"); break; + case 191: sprintf(outptr, "¿"); break; + case 192: sprintf(outptr, "À"); break; + case 193: sprintf(outptr, "Á"); break; + case 194: sprintf(outptr, "Â"); break; + case 195: sprintf(outptr, "Ã"); break; + case 196: sprintf(outptr, "Ä"); break; + case 197: sprintf(outptr, "Å"); break; + case 198: sprintf(outptr, "Æ"); break; + case 199: sprintf(outptr, "Ç"); break; + case 200: sprintf(outptr, "È"); break; + case 201: sprintf(outptr, "É"); break; + case 202: sprintf(outptr, "Ê"); break; + case 203: sprintf(outptr, "Ë"); break; + case 204: sprintf(outptr, "Ì"); break; + case 205: sprintf(outptr, "Í"); break; + case 206: sprintf(outptr, "Î"); break; + case 207: sprintf(outptr, "Ï"); break; + case 208: sprintf(outptr, "Ð"); break; + case 209: sprintf(outptr, "Ñ"); break; + case 210: sprintf(outptr, "Ò"); break; + case 211: sprintf(outptr, "Ó"); break; + case 212: sprintf(outptr, "Ô"); break; + case 213: sprintf(outptr, "Õ"); break; + case 214: sprintf(outptr, "Ö"); break; + case 215: sprintf(outptr, "×"); break; + case 216: sprintf(outptr, "Ø"); break; + case 217: sprintf(outptr, "Ù"); break; + case 218: sprintf(outptr, "Ú"); break; + case 219: sprintf(outptr, "Û"); break; + case 220: sprintf(outptr, "Ü"); break; + case 221: sprintf(outptr, "Ý"); break; + case 222: sprintf(outptr, "Þ"); break; + case 223: sprintf(outptr, "ß"); break; + case 224: sprintf(outptr, "à"); break; + case 225: sprintf(outptr, "á"); break; + case 226: sprintf(outptr, "â"); break; + case 227: sprintf(outptr, "ã"); break; + case 228: sprintf(outptr, "ä"); break; + case 229: sprintf(outptr, "å"); break; + case 230: sprintf(outptr, "æ"); break; + case 231: sprintf(outptr, "ç"); break; + case 232: sprintf(outptr, "è"); break; + case 233: sprintf(outptr, "é"); break; + case 234: sprintf(outptr, "ê"); break; + case 235: sprintf(outptr, "ë"); break; + case 236: sprintf(outptr, "ì"); break; + case 237: sprintf(outptr, "í"); break; + case 238: sprintf(outptr, "î"); break; + case 239: sprintf(outptr, "ï"); break; + case 240: sprintf(outptr, "ð"); break; + case 241: sprintf(outptr, "ñ"); break; + case 242: sprintf(outptr, "ò"); break; + case 243: sprintf(outptr, "ó"); break; + case 244: sprintf(outptr, "ô"); break; + case 245: sprintf(outptr, "õ"); break; + case 246: sprintf(outptr, "ö"); break; + case 247: sprintf(outptr, "÷"); break; + case 248: sprintf(outptr, "ø"); break; + case 249: sprintf(outptr, "ù"); break; + case 250: sprintf(outptr, "ú"); break; + case 251: sprintf(outptr, "û"); break; + case 252: sprintf(outptr, "ü"); break; + case 253: sprintf(outptr, "ý"); break; + case 254: sprintf(outptr, "þ"); break; + case 255: sprintf(outptr, "ÿ"); break; + default: *outptr++ = *inptr; *outptr = '\0'; break; + } + while (*outptr) + outptr++; + + inptr++; + } + *outptr = '\0'; +} + + + +char *rfcdate(time_t); +char *rfcdate(time_t now) +{ + static char buf[40]; + struct tm ptm; + + ptm = *gmtime(&now); + + sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d GMT", + wdays[ptm.tm_wday], ptm.tm_mday, months[ptm.tm_mon], + ptm.tm_year + 1900, ptm.tm_hour, ptm.tm_min, ptm.tm_sec); + return(buf); +} + + + +void pagelink(FILE *, char *, int, int); +void pagelink(FILE *fa, char *Path, int inArea, int Current) +{ + char nr[20]; + + fprintf(fa, "
\n"); + + if ((Current >= CFG.www_files_page) && (inArea >= CFG.www_files_page)) { + if (((Current / CFG.www_files_page) - 1) > 0) + sprintf(nr, "%d", (Current / CFG.www_files_page) -1); + else + nr[0] = '\0'; + fprintf(fa, "\"%s\"%s \n", + CFG.www_url, CFG.www_link2ftp, Path+strlen(CFG.ftp_base), nr, + CFG.www_icon_prev, CFG.www_name_prev, CFG.www_name_prev); + } + + fprintf(fa, "\"%s\"%s \n", + CFG.www_url, CFG.www_icon_home, CFG.www_name_home, CFG.www_name_home); + fprintf(fa, "\"%s\"%s\n", + CFG.www_url, CFG.www_link2ftp, CFG.www_icon_back, CFG.www_name_back, CFG.www_name_back); + + if ((Current < (inArea - CFG.www_files_page)) && (inArea >= CFG.www_files_page)) { + fprintf(fa, " \"%s\"%s\n", + CFG.www_url, CFG.www_link2ftp, Path+strlen(CFG.ftp_base), (Current / CFG.www_files_page) + 1, + CFG.www_icon_next, CFG.www_name_next, CFG.www_name_next); + } + + fprintf(fa, "

\n"); +} + + + +FILE *newpage(char *, char *, time_t, int, int); +FILE *newpage(char *Path, char *Name, time_t later, int inArea, int Current) +{ + char linebuf[1024], outbuf[1024]; + static FILE* fa; + + lastfile = Current; + if (Current) + sprintf(linebuf, "%s/index%d.temp", Path, Current / CFG.www_files_page); + else + sprintf(linebuf, "%s/index.temp", Path); + if ((fa = fopen(linebuf, "w")) == NULL) { + WriteError("$Can't create %s", linebuf); + } else { + sprintf(linebuf, "%s", Name); + html_massage(linebuf, outbuf); + fprintf(fa, "\n"); + fprintf(fa, "\n", rfcdate(later)); + fprintf(fa, "\n"); + fprintf(fa, "\n", CFG.www_charset); + fprintf(fa, "\n", CFG.www_author, outbuf); + fprintf(fa, "%s\n", outbuf); + fprintf(fa, "\n", CFG.www_url); + fprintf(fa, "\n\n\n"); + pagelink(fa, Path, inArea, Current); + fprintf(fa, "

File index of %s

\n", outbuf); + fprintf(fa, "\n"); + fprintf(fa, "\n"); + return fa; + } + return NULL; +} + + + +void closepage(FILE *, char *, int, int); +void closepage(FILE *fa, char *Path, int inArea, int Current) +{ + char *temp1, *temp2; + + if (fa == NULL) + return; + + temp1 = calloc(PATH_MAX, sizeof(char)); + temp2 = calloc(PATH_MAX, sizeof(char)); + fprintf(fa, "
Nr.FilenameDateSizeDownloadsDescription

\n"); + pagelink(fa, Path, inArea, lastfile); + fprintf(fa, "\n"); + fclose(fa); + if (lastfile) { + sprintf(temp1, "%s/index%d.html", Path, lastfile / CFG.www_files_page); + sprintf(temp2, "%s/index%d.temp", Path, lastfile / CFG.www_files_page); + } else { + sprintf(temp1, "%s/index.html", Path); + sprintf(temp2, "%s/index.temp", Path); + } + rename(temp2, temp1); + free(temp1); + free(temp2); + fa = NULL; +} + + + +void MakeIndex() +{ + FILE *fp, *fm, *fa, *pAreas, *pFile; + int AreaNr = 0, j, z, x = 0, Areas = 0; + int iTotal = 0, aTotal = 0, inArea = 0; + long iSize = 0L, aSize = 0; + char *sAreas, *fAreas; + char temp[81], fn[PATH_MAX], linebuf[1024], outbuf[1024]; + time_t last = 0L, later; + + sAreas = calloc(PATH_MAX, sizeof(char)); + fAreas = calloc(PATH_MAX, sizeof(char)); + later = time(NULL) + 86400; + + IsDoing("Create Indexes"); + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open File Areas File: %s", sAreas); + colour(7,0); + die(1); + } + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + if (!do_quiet) + printf("Processing index lists\n"); + + sprintf(fn, "%s/index.temp", CFG.ftp_base); + if ((fm = fopen(fn, "w")) == NULL) { + WriteError("$Can't create %s", fn); + die(0); + } + + /* + * Because these web pages are dynamic, ie. they change everytime you + * receive new files and recreates these pages, extra HTTP headers are + * send to the client about these pages. It forbids proxy servers to + * cache these pages. The pages will expire within 24 hours. The pages + * also have an author name, this is the bbs name, and a content + * description for search engines. Automatic advertising. + */ + sprintf(linebuf, "File areas at %s", CFG.bbs_name); + html_massage(linebuf, outbuf); + fprintf(fm, "\n"); + fprintf(fm, "\n", rfcdate(later)); + fprintf(fm, "\n"); + fprintf(fm, "\n", CFG.www_charset); + fprintf(fm, "\n", CFG.www_author, outbuf); + fprintf(fm, "%s\n", outbuf); + fprintf(fm, "\n", CFG.www_url); + fprintf(fm, "\n\n\n"); + fprintf(fm, "

%s

\n", outbuf); + fprintf(fm, "\n"); + fprintf(fm, "\n"); + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + AreaNr++; + + if (area.Available && !area.CDrom && + (strncmp(CFG.ftp_base, area.Path, strlen(CFG.ftp_base)) == 0)) { + + sprintf(temp, "%s/00index", area.Path); + + if ((fp = fopen(temp, "w")) == NULL) { + WriteError("$Can't create %s", temp); + } else { + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), AreaNr); + + if ((pFile = fopen (fAreas, "r")) == NULL) { + WriteError("$Can't open Area %d (%s)! Skipping ...", AreaNr, area.Name); + } else { + Areas++; + inArea = 0; + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if ((!file.Deleted) && (!file.Missing)) + inArea++; + } + fseek(pFile, 0, SEEK_SET); + + aSize = 0L; + aTotal = 0; + last = 0L; + fa = newpage(area.Path, area.Name, later, inArea, aTotal); + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if ((!file.Deleted) && (!file.Missing)) { + /* + * The next is to reduce system + * loading. + */ + x++; + iTotal++; + aTotal++; + if (CFG.slow_util && do_quiet && ((x % 3) == 0)) + usleep(1); + + for (z = 0; z <= 25; z++) { + if (strlen(file.Desc[z])) { + if (z == 0) + fprintf(fp, "%-12s %7luK %s ", file.Name, + file.Size / 1024, + StrDateDMY(file.UploadDate)); + else + fprintf(fp, " "); + if ((file.Desc[z][0] == '@') && (file.Desc[z][1] == 'X')) + fprintf(fp, "%s\n", file.Desc[z]+4); + else + fprintf(fp, "%s\n", file.Desc[z]); + } + } + + fprintf(fa, "", aTotal); + /* + * Check if this is a .gif or .jpg file, if so then + * check if a thumbnail file exists. If not try to + * create a thumbnail file to add to the html listing. + */ + if (strstr(file.Name, ".gif") || strstr(file.Name, ".jpg")) { + sprintf(linebuf, "%s/%s", area.Path, file.Name); + sprintf(outbuf, "%s/.%s", area.Path, file.Name); + if (file_exist(outbuf, R_OK)) { + if ((j = execute(CFG.www_convert, linebuf, outbuf, + (char *)"/dev/null", (char *)"/dev/null", + (char *)"/dev/null"))) { + Syslog('+', "Failed to create thumbnail for %s, rc=%d", file.Name, j); + } + } + fprintf(fa, ""); + } else { + fprintf(fa, "", + CFG.www_url, CFG.www_link2ftp, + area.Path+strlen(CFG.ftp_base), file.Name, file.Name); + } + fprintf(fa, "", StrDateDMY(file.FileDate)); + fprintf(fa, "", file.Size / 1024); + fprintf(fa, "", + file.TimesDL + file.TimesFTP + file.TimesReq); + fprintf(fa, "\n"); + aSize += file.Size; + iSize += file.Size; + if (file.FileDate > last) + last = file.FileDate; + if ((aTotal % CFG.www_files_page) == 0) { + closepage(fa, area.Path, inArea, aTotal); + fa = newpage(area.Path, area.Name, later, inArea, aTotal); + } + + } /* if (!file.deletd) */ + } + fclose(pFile); + closepage(fa, area.Path, inArea, aTotal); + } + fclose(fp); + fprintf(fm, "", + AreaNr, CFG.www_url, CFG.www_link2ftp, area.Path+strlen(CFG.ftp_base), area.Name); + fprintf(fm, "", aTotal); + if (aSize > 1048576) + fprintf(fm, "", aSize / 1048576); + else + fprintf(fm, "", aSize / 1024); + if (last == 0L) + fprintf(fm, "\n"); + else + fprintf(fm, "\n", StrDateDMY(last)); + } + } + } /* End of While Loop Checking for Areas Done */ + + fprintf(fm, "\n", + iTotal, iSize / 1048576); + fprintf(fm, "
AreaDescriptionFilesTotal sizeLast added
%d
",
+									CFG.www_url, CFG.www_link2ftp, 
+									area.Path+strlen(CFG.ftp_base), file.Name);
+								fprintf(fa, "\"%s\"", 
+									CFG.www_url, CFG.www_link2ftp,
+									area.Path+strlen(CFG.ftp_base), file.Name, file.Name);
+								fprintf(fa, "
%s
%s
%lu Kb.
%8ld
");
+							for (j = 0; j < 25; j++)
+								if (strlen(file.Desc[j])) {
+									if (j)
+										fprintf(fa, "\n");
+									sprintf(linebuf, "%s", strkconv(file.Desc[j], CHRS_DEFAULT_FTN, CHRS_DEFAULT_RFC));
+									html_massage(linebuf, outbuf);
+									fprintf(fa, "%s", outbuf);
+								}
+							fprintf(fa, "
%d%s%d%ld Mb.%ld Kb. 
%s
 Total%d%ld Mb. 

\n"); + fprintf(fm, "\"%s\"%s\n", + CFG.www_icon_home, CFG.www_name_home, CFG.www_name_home); + fprintf(fm, "\n"); + fclose(fm); + sprintf(linebuf, "%s/index.html", CFG.ftp_base); + rename(fn, linebuf); + + fclose(pAreas); + free(sAreas); + free(fAreas); + Syslog('+', "Created %d indexes with %d files", Areas, iTotal); +} + + + +void MidLine(char *txt, FILE *fp, int doit) +{ + char temp[81]; + int x, y, z; + + if (!doit) + return; + + z = strlen(txt); + x = 77 - z; + x /= 2; + strcpy(temp, ""); + + for (y = 0; y < x; y++) + strcat(temp, " "); + + strcat(temp, txt); + z = strlen(temp); + x = 77 - z; + + for (y = 0; y < x; y++) + strcat(temp, " "); + + fprintf(fp, "%c", 179); + fprintf(fp, "%s", temp); + fprintf(fp, "%c\r\n", 179); +} + + + +void TopBox(FILE *fp, int doit) +{ + int y; + + if (!doit) + return; + + fprintf(fp, "\r\n%c", 213); + for(y = 0; y < 77; y++) + fprintf(fp, "%c", 205); + fprintf(fp, "%c\r\n", 184); +} + + + +void BotBox(FILE *fp, int doit) +{ + int y; + + if (!doit) + return; + + fprintf(fp, "%c", 212); + for (y = 0; y < 77; y++) + fprintf(fp, "%c", 205); + fprintf(fp, "%c\r\n\r\n", 190); +} + + + +void Masterlist() +{ + FILE *fp, *np, *pAreas, *pFile, *pHeader; + int AreaNr = 0, z, x = 0, New; + long AllFiles = 0, AllBytes = 0, NewFiles = 0, NewBytes = 0; + int AllAreaFiles, AllAreaBytes, popdown, down; + int NewAreaFiles, NewAreaBytes; + char *sAreas, *fAreas; + char temp[81], pop[81]; + + sAreas = calloc(PATH_MAX, sizeof(char)); + fAreas = calloc(PATH_MAX, sizeof(char)); + + IsDoing("Create Allfiles list"); + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if(( pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("Can't open File Areas File: %s", sAreas); + colour(7,0); + die(1); + } + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + if (!do_quiet) + printf("Processing file areas\n"); + + if ((fp = fopen("allfiles.tmp", "a+")) == NULL) { + WriteError("$Can't open allfiles.tmp"); + die(1); + } + if ((np = fopen("newfiles.tmp", "a+")) == NULL) { + WriteError("$Can't open newfiles.tmp"); + fclose(fp); + die(1); + } + + TopBox(fp, TRUE); + TopBox(np, TRUE); + sprintf(temp, "All available files at %s", CFG.bbs_name); + MidLine(temp, fp, TRUE); + sprintf(temp, "New available files since %d days at %s", CFG.newdays, CFG.bbs_name); + MidLine(temp, np, TRUE); + BotBox(fp, TRUE); + BotBox(np, TRUE); + + sprintf(temp, "%s/etc/header.txt", getenv("MBSE_ROOT")); + if(( pHeader = fopen(temp, "r")) != NULL) { + Syslog('+', "Inserting %s", temp); + + while( fgets(temp, 80 ,pHeader) != NULL) { + Striplf(temp); + fprintf(fp, "%s\r\n", temp); + fprintf(np, "%s\r\n", temp); + } + } + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + AreaNr++; + AllAreaFiles = 0; + AllAreaBytes = 0; + NewAreaFiles = 0; + NewAreaBytes = 0; + + if (area.Available && (area.LTSec.level <= CFG.security.level)) { + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), AreaNr); + + if ((pFile = fopen (fAreas, "r")) == NULL) { + WriteError("$Can't open Area %d (%s)! Skipping ...", AreaNr, area.Name); + } else { + popdown = 0; + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if ((!file.Deleted) && (!file.Missing)) { + /* + * The next is to reduce system + * loading. + */ + x++; + if (CFG.slow_util && do_quiet && ((x % 3) == 0)) + usleep(1); + AllFiles++; + AllBytes += file.Size; + AllAreaFiles++; + AllAreaBytes += file.Size; + down = file.TimesDL + file.TimesFTP + file.TimesReq; + if (down > popdown) { + popdown = down; + sprintf(pop, "%s", file.Name); + } + if (((t_start - file.UploadDate) / 84400) <= CFG.newdays) { + NewFiles++; + NewBytes += file.Size; + NewAreaFiles++; + NewAreaBytes += file.Size; + } + } + } + + /* + * If there are files to report do it. + */ + if (AllAreaFiles) { + TopBox(fp, TRUE); + TopBox(np, NewAreaFiles); + + sprintf(temp, "Area %d - %s", AreaNr, area.Name); + MidLine(temp, fp, TRUE); + MidLine(temp, np, NewAreaFiles); + + sprintf(temp, "File Requests allowed"); + MidLine(temp, fp, area.FileReq); + MidLine(temp, np, area.FileReq && NewAreaFiles); + + sprintf(temp, "%d KBytes in %d files", AllAreaBytes / 1024, AllAreaFiles); + MidLine(temp, fp, TRUE); + sprintf(temp, "%d KBytes in %d files", NewAreaBytes / 1024, NewAreaFiles); + MidLine(temp, np, NewAreaFiles); + if (popdown) { + sprintf(temp, "Most popular file is %s", pop); + MidLine(temp, fp, TRUE); + } + + BotBox(fp, TRUE); + BotBox(np, NewAreaFiles); + + fseek(pFile, 0, SEEK_SET); + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if((!file.Deleted) && (!file.Missing)) { + New = (((t_start - file.UploadDate) / 84400) <= CFG.newdays); + sprintf(temp, "%-12s%10lu K %s [%04ld] Uploader: %s", + file.Name, file.Size / 1024, StrDateDMY(file.UploadDate), + file.TimesDL + file.TimesFTP + file.TimesReq, + strlen(file.Uploader)?file.Uploader:""); + fprintf(fp, "%s\r\n", temp); + if (New) + fprintf(np, "%s\r\n", temp); + + for (z = 0; z <= 25; z++) { + if (strlen(file.Desc[z])) { + if ((file.Desc[z][0] == '@') && (file.Desc[z][1] == 'X')) { + fprintf(fp, " %s\r\n",file.Desc[z]+4); + if (New) + fprintf(np, " %s\r\n",file.Desc[z]+4); + } else { + fprintf(fp, " %s\r\n",file.Desc[z]); + if (New) + fprintf(np, " %s\r\n",file.Desc[z]); + } + } + } + } + } + } + fclose(pFile); + } + } + } /* End of While Loop Checking for Areas Done */ + + fclose(pAreas); + + TopBox(fp, TRUE); + TopBox(np, TRUE); + sprintf(temp, "Total %ld files, %ld KBytes", AllFiles, AllBytes / 1024); + MidLine(temp, fp, TRUE); + sprintf(temp, "Total %ld files, %ld KBytes", NewFiles, NewBytes / 1024); + MidLine(temp, np, TRUE); + + MidLine((char *)"", fp, TRUE); + MidLine((char *)"", np, TRUE); + + sprintf(temp, "Created by MBSE BBS v%s (Linux) at %s", VERSION, StrDateDMY(t_start)); + MidLine(temp, fp, TRUE); + MidLine(temp, np, TRUE); + + BotBox(fp, TRUE); + BotBox(np, TRUE); + + sprintf(temp, "%s/etc/footer.txt", getenv("MBSE_ROOT")); + if(( pHeader = fopen(temp, "r")) != NULL) { + Syslog('+', "Inserting %s", temp); + + while( fgets(temp, 80 ,pHeader) != NULL) { + Striplf(temp); + fprintf(fp, "%s\r\n", temp); + fprintf(np, "%s\r\n", temp); + } + } + + fclose(fp); + fclose(np); + + if ((rename("allfiles.tmp", "allfiles.txt")) == 0) + unlink("allfiles.tmp"); + if ((rename("newfiles.tmp", "newfiles.txt")) == 0) + unlink("newfiles.tmp"); + + Syslog('+', "Allfiles: %ld, %ld MBytes", AllFiles, AllBytes / 1048576); + Syslog('+', "Newfiles: %ld, %ld MBytes", NewFiles, NewBytes / 1048576); + free(sAreas); + free(fAreas); +} + + + +void MakeArc() +{ + char *cmd; + + if (!getarchiver((char *)"ZIP")) { + WriteError("ZIP Archiver not available"); + return; + } + + cmd = xstrcpy(archiver.farc); + + if (cmd == NULL) { + WriteError("ZIP archive command not available"); + return; + } + + if (!do_quiet) + printf("Creating allfiles.zip\n"); + if (!execute(cmd, (char *)"allfiles.zip allfiles.txt", (char *)NULL, (char *)"/dev/null", + (char *)"/dev/null", (char *)"/dev/null") == 0) + WriteError("Create allfiles.zip failed"); + + if (!do_quiet) + printf("Creating newfiles.zip\n"); + if (!execute(cmd, (char *)"newfiles.zip newfiles.txt", (char *)NULL, (char *)"/dev/null", + (char *)"/dev/null", (char *)"/dev/null") == 0) + WriteError("Create newfiles.zip failed"); + free(cmd); +} + + diff --git a/mbsebbs/mball.h b/mbsebbs/mball.h new file mode 100644 index 00000000..e8f05de4 --- /dev/null +++ b/mbsebbs/mball.h @@ -0,0 +1,17 @@ +#ifndef _MBALL_H +#define _MBALL_H + + +void ProgName(void); +void die(int); +void Help(void); +void MakeIndex(void); +void MidLine(char *, FILE *, int); +void TopBox(FILE *, int); +void BotBox(FILE *, int); +void Masterlist(void); +void MakeArc(void); + + +#endif + diff --git a/mbsebbs/mbchat.c b/mbsebbs/mbchat.c new file mode 100644 index 00000000..07891ede --- /dev/null +++ b/mbsebbs/mbchat.c @@ -0,0 +1,257 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/mbchat.c + * Purpose ...............: Sysop chat utility. + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:2801/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" + + +char *ttime2(void); /* Returns current time HH:MM */ + +struct sysconfig CFG; + + +int main(int argc, char **argv) +{ + FILE *fp1, *pChatDev, *pPid, *pLog; + FILE *pDataFile; + int ch; + int iLetter = 0; + short ipid; + char *tty; + char *sStr1= (char *)""; + char pid[81]; + char pid1[20]; + char sTTY[10]; + char *sLog= (char *)""; + char *Config, *FileName, *LogName; + char *BBSpath; + +#ifdef MEMWATCH + mwInit(); +#endif + + FileName = calloc(PATH_MAX, sizeof(char)); + Config = calloc(PATH_MAX, sizeof(char)); + LogName = calloc(PATH_MAX, sizeof(char)); + + if ((BBSpath = getenv("MBSE_ROOT")) == NULL) { + printf("Could not get MBSE_ROOT environment variable\n"); + printf("Please set the environment variable ie:\n\n"); + printf("\"MBSE_ROOT=/usr/local/mbse;export MBSE_ROOT\"\n\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + sprintf(FileName, "%s/etc/config.data", BBSpath); + + if ((pDataFile = fopen(FileName, "rb")) == NULL) { + perror("\n\nFATAL ERROR: Can't open config.data for reading!!!"); + printf("Please run mbsetup to create configuration file.\n"); + printf("Or check that your MBSE_ROOT variable is set to the BBS Path!\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + fread(&CFG, sizeof(CFG), 1, pDataFile); + fclose(pDataFile); + free(Config); + free(FileName); + + if(CFG.iAutoLog) + sLog = calloc(56, sizeof(char)); + + if(argc != 2) { + printf("\nSCHAT: MBSE BBS %s Sysop chat facilty\n", VERSION); + printf(" %s\n", Copyright); + + printf("\nCommand-line parameters:\n\n"); + + printf(" %s ", *(argv)); + + printf("\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(0); + } + + printf("\f"); + + if (strncmp( (tty = *(argv+1)), "/dev/", 5 ) == 0 ) { + tty+=5; + sprintf(pid,"%s/tmp/.bbs-exitinfo.%s",BBSpath,tty); + strcpy(sTTY,""); + } else { + sprintf(pid,"%s/tmp/.bbs-exitinfo.%s",BBSpath,*(argv+1)); + strcpy(sTTY,"/dev/"); + } + + strcat(sTTY, *(argv + 1)); + + if(( fp1 = fopen(sTTY,"w")) == NULL) + perror("Error"); + + if(( pPid = fopen(pid,"r")) == NULL) { + printf("\nThere is no user on %s\n", pid); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } else { + fgets(pid1,19,pPid); + fclose(pPid); + } + + ipid = atoi(pid1); + + if(( pChatDev = fopen("/tmp/chatdev","w")) == NULL) + perror("Can't open file"); + else { + sStr1=ttyname(1); + fprintf(pChatDev,"%s", sStr1); + fclose(pChatDev); + } + + if(!CFG.iExternalChat || (strlen(CFG.sExternalChat) < 1) || \ + (access(CFG.sExternalChat, X_OK) != 0)) { + printf("Users chatting device: %s\n", sTTY); + printf("Wait until the user is ready"); + printf("Press ESC to exit chat\n\n"); + + umask(00000); + chmod("/tmp/chatdev", 00777); + chmod(sStr1, 00777); + + sleep(2); + + Setraw(); + + sleep(2); + + while (1) { + ch = getc(stdin); + ch &= '\377'; + if (ch == '\033') + break; + putchar(ch); + putc(ch, fp1); + + if(CFG.iAutoLog) { + if(ch != '\b') + iLetter++; /* Count the letters user presses for logging */ + sprintf(sLog, "%s%c", sLog, ch); + } + + if (ch == '\n') { + ch = '\r'; + putchar(ch); + putc(ch, fp1); + } + + if (ch == '\r') { + ch = '\n'; + putchar(ch); + putc(ch, fp1); + } + + if (ch == '\b') { + ch = ' '; + putchar(ch); + putc(ch, fp1); + ch = '\b'; + putchar(ch); + putc(ch, fp1); + + if(CFG.iAutoLog) + sLog[--iLetter] = '\0'; + } + + /* Check if log chat is on and if so log chat to disk */ + if(CFG.iAutoLog) { + if(iLetter >= 55 || ch == '\n') { + iLetter = 0; + sprintf(LogName, "%s/log/chat.log", BBSpath); + if(( pLog = fopen(LogName, "a+")) != NULL) { + fflush(pLog); + fprintf(pLog, "%s [%s]: %s\n", CFG.sysop_name, ttime2(), sLog); + fclose(pLog); + strcpy(sLog, ""); + } else + perror("\nCan't open chat.log"); + } + } + } /* while chatting */ +// fprintf(fp1, "The sysop ended the chat, press a key.\n"); + } else { + system(CFG.sExternalChat); + printf("\n\n"); + } + + fclose(fp1); + sleep(2); + Unsetraw(); + sleep(2); + unlink("/tmp/chatdev"); + unlink("/tmp/.BusyChatting"); + fclose(fp1); + printf("Done chatting.\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(0); +} + + + +/* + * This function returns the date for today, to test against other functions + * HH:MM (HOUR-MINUTE) + */ +char *ttime2() +{ + struct tm *l_date; /* Structure for Date */ + time_t Time_Now; + static char Ttime2[9]; + + time(&Time_Now); + l_date = localtime(&Time_Now); + + sprintf(Ttime2, "%02d:%02d", l_date->tm_hour,l_date->tm_min); + + return(Ttime2); +} + + diff --git a/mbsebbs/mbfbgen.c b/mbsebbs/mbfbgen.c new file mode 100644 index 00000000..7ec5c63f --- /dev/null +++ b/mbsebbs/mbfbgen.c @@ -0,0 +1,332 @@ +/***************************************************************************** + * + * File ..................: mbfbgen.c + * Purpose ...............: mbfbgen generates file databases from the old + * style files.bbs. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" + + +struct stat statfile; +struct FILERecord file; + + +int main(void) +{ + FILE *pAreas, *pFilesBBS, *pDataBase; + int i, j = 0, k = 0, x; + int Append = FALSE, Doit, Files = 0, TotalFiles = 0; + long offset; + long TotalAreas = 0, StartArea, EndArea, recno = 0; + char sFileName[PATH_MAX]; + char temp[81]; + char sDataBase[PATH_MAX]; + char sString1[256]; + char sUploader[36]; + char *token = NULL; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + + InitConfig(); + TermInit(1); + umask(002); + system("clear"); + colour(15, 0); + printf("\nMBFBGEN: MBSE BBS %s FileBase Generator Utility\n", VERSION); + colour(14, 0); + printf(" %s\n\n", Copyright); + colour(7, 0); + + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"fbgen", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBFBGEN v%s", VERSION); + + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(temp,"r")) == NULL) { + WriteError("$Can't open %s", temp); + printf("Can't open %s\n", temp); + ExitClient(1); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + TotalAreas++; + } + fclose(pAreas); + + recno = 0; + + colour(3, 0); + printf("Total File Areas : %ld\n", TotalAreas); + printf("File Record Size : %d\n", (int)sizeof(file)); + + printf("\nStart at area [1]: "); + colour(10, 0); + fgets(temp, 10, stdin); + if ((strcmp(temp, "")) == 0) + StartArea = 1L; + else + StartArea = atoi(temp); + + colour(3, 0); + printf("\nStop at area [%ld]: ", TotalAreas); + colour(10, 0); + fgets(temp, 10, stdin); + if ((strcmp(temp, "")) == 0) + EndArea = TotalAreas; + else + EndArea = atoi(temp); + + if ((StartArea < 1L) || (StartArea > TotalAreas)) { + colour(12, 0); + printf("\007\nIllegal \"Start\" area %ld\n", StartArea); + colour(7, 0); + ExitClient(0); + } + if ((EndArea < StartArea) || (EndArea > TotalAreas)) { + colour(12, 0); + printf("\007\nIllegal \"End\" area %ld\n", EndArea); + colour(7, 0); + ExitClient(0); + } + + colour(3, 0); + printf("\nDefault is [Sysop]\n"); + printf("Name of Uploader for files: "); + colour(10, 0); + fgets(sUploader, 35, stdin); + for (i = 0; i < strlen(sUploader); i++) + if (sUploader[i] == '\n') + sUploader[i] = '\0'; + if ((strcmp(sUploader, "")) == 0) + sprintf(sUploader, "Sysop"); + + colour(7, 0); + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(temp,"r")) == NULL) { + WriteError("$Can't open %s", temp); + printf("Can't open %s\n", temp); + ExitClient(1); + } + fread(&areahdr, sizeof(areahdr), 1, pAreas); + recno = StartArea; + + Syslog('+', "From %ld to %ld, Uploader: \"%s\"", StartArea, EndArea, sUploader); + colour(14, 0); + printf("\n\n"); + + while (TRUE) { + + offset = areahdr.hdrsize + ((recno -1) * areahdr.recsize); + if (fseek(pAreas, offset, 0) != 0) { + WriteError("$Can't seek in fareas.data"); + printf("Can't seek in fareas.data\n"); + ExitClient(1); + } + fread(&area, areahdr.recsize, 1, pAreas); + + sprintf(sDataBase,"%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), recno); + + /* + * Try to find files.bbs at 2 places, in the subdirectory + * with the files, and at the path given in the setup. + */ + sprintf(sFileName,"%s/files.bbs", area.Path); + if ((pFilesBBS = fopen(sFileName,"r")) == NULL) { + sprintf(sFileName, "%s", area.FilesBbs); + if ((pFilesBBS = fopen(sFileName, "r")) == NULL) + WriteError("$Can't process area: %ld %s", recno, area.Name); + } + + if (pFilesBBS != NULL) { + Files = 0; + + while (fgets(sString1,255,pFilesBBS) != NULL) { + + if ((sString1[0] != ' ') && (sString1[0] != '\t')) { + /* + * New file entry, check if there hase been a file + * that is not saved yet. + */ + if (Append) { + if ((pDataBase = fopen(sDataBase,"a+")) == NULL) { + WriteError("$Can't open %s", sDataBase); + ExitClient(1); + } else { + fwrite(&file, sizeof(file), 1, pDataBase); + fclose(pDataBase); + } + Append = FALSE; + } + + Files++; + TotalFiles++; + printf("\rArea: %-6ld Fileno: %-6d Total: %-6d", recno, Files, TotalFiles); + fflush(stdout); + + memset(&file, 0, sizeof(file)); + + token = tl(strtok(sString1, " ,\t")); + strcpy(file.Name, token); + strcpy(file.LName, token); + token = strtok(NULL,"\0"); + i = strlen(token); + j = k = 0; + for (x = 0; x < i; x++) { + if ((token[x] == '\n') || (token[x] == '\r')) + token[x] = '\0'; + } + Doit = FALSE; + for (x = 0; x < i; x++) { + if (!Doit) { + if (isalnum(token[x])) + Doit = TRUE; + } + if (Doit) { + if (k > 42) { + if (token[x] == ' ') { + file.Desc[j][k] = '\0'; + j++; + k = 0; + } else { + if (k == 49) { + file.Desc[j][k] = '\0'; + k = 0; + j++; + } + file.Desc[j][k] = token[x]; + k++; + } + } else { + file.Desc[j][k] = token[x]; + k++; + } + } + } + + sprintf(temp,"%s/%s", area.Path, file.Name); + if (stat(temp,&statfile) != 0) { + WriteError("Cannot locate file on disk! Skipping... -> %s\n",temp); + Append = FALSE; + } + + Append = TRUE; + file.Size = statfile.st_size; + file.FileDate = statfile.st_mtime; + file.Crc32 = file_crc(temp, FALSE); + + strcpy(file.Uploader,sUploader); + time(&file.UploadDate); + } else { + /* + * Add multiple description lines + */ + token = strtok(sString1, "\0"); + i = strlen(token); + j++; + k = 0; + Doit = FALSE; + for (x = 0; x < i; x++) { + if ((token[x] == '\n') || (token[x] == '\r')) + token[x] = '\0'; + } + for (x = 0; x < i; x++) { + if (Doit) { + if (k > 42) { + if (token[x] == ' ') { + file.Desc[j][k] = '\0'; + j++; + k = 0; + } else { + if (k == 49) { + file.Desc[j][k] = '\0'; + k = 0; + j++; + } + file.Desc[j][k] = token[x]; + k++; + } + } else { + file.Desc[j][k] = token[x]; + k++; + } + } else { + /* + * Skip until + or | is found + */ + if ((token[x] == '+') || (token[x] == '|')) + Doit = TRUE; + } + } + } + } /* End of files.bbs */ + + /* + * Flush the last file to the database + */ + if (Append) { + if ((pDataBase = fopen(sDataBase, "a+")) == NULL) { + WriteError("$Can't open %s", sDataBase); + ExitClient(1); + } else { + fwrite(&file, sizeof(file), 1, pDataBase); + fclose(pDataBase); + } + Append = FALSE; + } + fclose(pFilesBBS); + } + Syslog('+', "Area %ld added %ld files", recno, Files); + recno++; + if (recno > EndArea) + break; + } + fclose(pAreas); + + colour(3, 0); + printf("\r \rAdded total %d files\n", TotalFiles); + colour(7, 0); + + Syslog('+', "Added total %ld files", TotalFiles); + Syslog(' ', "MBFBGEN Finished"); + ExitClient(0); + return 0; +} + + diff --git a/mbsebbs/mblang.c b/mbsebbs/mblang.c new file mode 100644 index 00000000..b4514f19 --- /dev/null +++ b/mbsebbs/mblang.c @@ -0,0 +1,136 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/mblang.c + * Purpose ...............: Language Compiler + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" + + +int main(int argc, char **argv) +{ + FILE *fp, *fp1; + int i, j, lines; + char *temp, *temp1; + +#ifdef MEMWATCH + mwInit(); +#endif + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + printf("\nMBLANG: MBSE BBS %s Quick Language Data File Creator\n", VERSION); + printf(" %s\n", Copyright); + + if (argc < 3) { + printf("\nUsage: %s [language data file] [language text file]\n\n", *(argv)); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + sprintf(temp1, "%s", *(argv + 1)); + unlink(temp1); + + sprintf(temp, "%s", *(argv + 2)); + if ((fp1 = fopen(temp, "r")) == NULL) { + printf("\nUnable to open %s\n", temp); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + sprintf(temp1, "%s", *(argv + 1)); + if ((fp = fopen(temp1, "a+")) == NULL) { + printf("\nUnable to open %s\n", temp1); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + lines = 0; + while (fgets(temp, 115, fp1) != NULL) { + + memset(&ldata, 0, sizeof(ldata)); + + /* + * Take the response keys part + */ + for(i = 0; i < strlen(temp); i++) { + if(temp[i] == '|') + break; + ldata.sKey[i] = temp[i]; + } + if (i > 29) { + printf("\nKey part in line %d too long (%d chars)", lines, i); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + /* + * Take the prompt string part + */ + j = 0; + for (i = i+1; i < strlen(temp); i++) { + if (temp[i] == '\n') + break; + ldata.sString[j] = temp[i]; + j++; + } + if (j > 84) { + printf("\nLanguage string in line %d too long (%d chars)", lines, j); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + fwrite(&ldata, sizeof(ldata), 1, fp); + lines++; + } + + fclose(fp); + fclose(fp1); + free(temp); + free(temp1); + + printf("\nCompiled %d language lines\n", lines); + +#ifdef MEMWATCH + mwTerm(); +#endif + return 0; +} + + diff --git a/mbsebbs/mbpasswd.c b/mbsebbs/mbpasswd.c new file mode 100644 index 00000000..f2e995ff --- /dev/null +++ b/mbsebbs/mbpasswd.c @@ -0,0 +1,663 @@ +/***************************************************************************** + * + * File ..................: mbpasswd.c + * Purpose ...............: setuid root version of passwd + * Last modification date : 27-Jun-2001 + * Shadow Suite (c) ......: Julianne Frances Haugh + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(SHADOW_PASSWORD) +#include +#endif + +#include "encrypt.h" +#include "rad64.h" +#include "myname.h" +#include "xmalloc.h" +#include "pwio.h" +#include "shadowio.h" +#include "mbpasswd.h" + + +#ifndef AGING +#if defined(SHADOW_PASSWORD) +#define AGING 1 +#endif +#else +#if !defined(SHADOW_PASSWORD) +#undef AGING +#endif +#endif + +static int do_update_age = 0; +#ifndef PAM +static char crypt_passwd[128]; /* The "old-style" password, if present */ +static int do_update_pwd = 0; +#endif + + +#ifdef SHADOW_PASSWORD +static void check_password(const struct passwd *, const struct spwd *); +#else /* !SHADOW_PASSWORD */ +static void check_password(const struct passwd *); +#endif /* !SHADOW_PASSWORD */ + +#ifndef DAY +#define DAY (24L*3600L) +#endif + +#define WEEK (7*DAY) +#define SCALE DAY + + +/* + * string to use for the pw_passwd field in /etc/passwd when using + * shadow passwords - most systems use "x" but there are a few + * exceptions, so it can be changed here if necessary. --marekm + */ +#ifndef SHADOW_PASSWD_STRING +#define SHADOW_PASSWD_STRING "x" +#endif + + +/* + * Global variables + */ + +static char *name; /* The name of user whose password is being changed */ +static char *myname; /* The current user's name */ +static int force; /* Force update of locked passwords */ + + + +static void fail_exit(int status) +{ + pw_unlock(); +#ifdef SHADOWPWD + spw_unlock(); +#endif + exit(status); +} + + + +static void oom(void) +{ + fprintf(stderr, "mbpasswd: out of memory\n"); + fail_exit(3); +} + + + +/* + * insert_crypt_passwd - add an "old-style" password to authentication string + * result now malloced to avoid overflow, just in case. --marekm + */ +static char * +insert_crypt_passwd(const char *string, char *passwd) +{ +#ifdef AUTH_METHODS + if (string && *string) { + char *cp, *result; + + result = xmalloc(strlen(string) + strlen(passwd) + 1); + cp = result; + while (*string) { + if (string[0] == ';') { + *cp++ = *string++; + } else if (string[0] == '@') { + while (*string && *string != ';') + *cp++ = *string++; + } else { + while (*passwd) + *cp++ = *passwd++; + while (*string && *string != ';') + string++; + } + } + *cp = '\0'; + return result; + } +#endif + return xstrdup(passwd); +} + + + +static char *update_crypt_pw(char *cp) +{ + if (do_update_pwd) + cp = insert_crypt_passwd(cp, crypt_passwd); + + return cp; +} + + + +/* + * pwd_init - ignore signals, and set resource limits to safe + * values. Call this before modifying password files, so that + * it is less likely to fail in the middle of operation. + */ +void pwd_init(void) +{ + struct rlimit rlim; + +#ifdef RLIMIT_CORE + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); +#endif + rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; +#ifdef RLIMIT_AS + setrlimit(RLIMIT_AS, &rlim); +#endif +#ifdef RLIMIT_CPU + setrlimit(RLIMIT_CPU, &rlim); +#endif +#ifdef RLIMIT_DATA + setrlimit(RLIMIT_DATA, &rlim); +#endif +#ifdef RLIMIT_FSIZE + setrlimit(RLIMIT_FSIZE, &rlim); +#endif +#ifdef RLIMIT_NOFILE + setrlimit(RLIMIT_NOFILE, &rlim); +#endif +#ifdef RLIMIT_RSS + setrlimit(RLIMIT_RSS, &rlim); +#endif +#ifdef RLIMIT_STACK + setrlimit(RLIMIT_STACK, &rlim); +#endif + signal(SIGALRM, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); +#endif +#ifdef SIGTTOU + signal(SIGTTOU, SIG_IGN); +#endif + + umask(077); +} + + + +/* + * isexpired - determine if account is expired yet + * + * isexpired calculates the expiration date based on the + * password expiration criteria. + */ +#ifdef SHADOW_PASSWORD +int isexpired(const struct passwd *pw, const struct spwd *sp) +{ +#else +int isexpired(const struct passwd *pw) +{ +#endif + long now; + + now = time ((time_t *) 0) / SCALE; + +#ifdef SHADOW_PASSWORD + + if (!sp) + sp = pwd_to_spwd(pw); + + /* + * Quick and easy - there is an expired account field + * along with an inactive account field. Do the expired + * one first since it is worse. + */ + if (sp->sp_expire > 0 && now >= sp->sp_expire) + return 3; + + /* + * Last changed date 1970-01-01 (not very likely) means that + * the password must be changed on next login (passwd -e). + * + * The check for "x" is a workaround for RedHat NYS libc bug - + * if /etc/shadow doesn't exist, getspnam() still succeeds and + * returns sp_lstchg==0 (must change password) instead of -1! + */ + if (sp->sp_lstchg == 0 && !strcmp(pw->pw_passwd, SHADOW_PASSWD_STRING)) + return 1; + if (sp->sp_lstchg > 0 && sp->sp_max >= 0 && sp->sp_inact >= 0 && + now >= sp->sp_lstchg + sp->sp_max + sp->sp_inact) + return 2; + + /* + * The last and max fields must be present for an account + * to have an expired password. A maximum of >10000 days + * is considered to be infinite. + */ + if (sp->sp_lstchg == -1 || + sp->sp_max == -1 || sp->sp_max >= (10000L*DAY/SCALE)) + return 0; + + /* + * Calculate today's day and the day on which the password + * is going to expire. If that date has already passed, + * the password has expired. + */ + if (now >= sp->sp_lstchg + sp->sp_max) + return 1; +#endif + return 0; +} + + + +/* + * check_password - test a password to see if it can be changed + * + * check_password() sees if the invoker has permission to change the + * password for the given user. + */ +#ifdef SHADOW_PASSWORD +static void check_password(const struct passwd *pw, const struct spwd *sp) +{ +#else +static void check_password(const struct passwd *pw) +{ +#endif + time_t now, last, ok; + int exp_status; + +#ifdef SHADOW_PASSWORD + exp_status = isexpired(pw, sp); +#else + exp_status = isexpired(pw); +#endif + + time(&now); + +#ifdef SHADOW_PASSWORD + /* + * If the force flag is set (for new users) this check is skipped. + */ + if (force == 1) + return; + + /* + * Expired accounts cannot be changed ever. Passwords + * which are locked may not be changed. Passwords where + * min > max may not be changed. Passwords which have + * been inactive too long cannot be changed. + */ + if (sp->sp_pwdp[0] == '!' || exp_status > 1 || + (sp->sp_max >= 0 && sp->sp_min > sp->sp_max)) { + fprintf (stderr, "The password for %s cannot be changed.\n", sp->sp_namp); + syslog(LOG_WARNING, "password locked for %s", sp->sp_namp); + closelog(); + exit (1); + } + + /* + * Passwords may only be changed after sp_min time is up. + */ + + last = sp->sp_lstchg * SCALE; + ok = last + (sp->sp_min > 0 ? sp->sp_min * SCALE : 0); +#else /* !SHADOW_PASSWORD */ + if (pw->pw_passwd[0] == '!' || exp_status > 1) { + fprintf (stderr, "The password for %s cannot be changed.\n", pw->pw_name); + syslog(LOG_WARNING, "password locked for %s", pw->pw_name); + closelog(); + exit (1); + } + last = 0; + ok = 0; +#endif /* !SHADOW_PASSWORD */ + if (now < ok) { + fprintf(stderr, "Sorry, the password for %s cannot be changed yet.\n", pw->pw_name); + syslog(LOG_WARNING, "now < minimum age for `%s'", pw->pw_name); + closelog(); + exit (1); + } +} + + + +/* + * pwd_to_spwd - create entries for new spwd structure + * + * pwd_to_spwd() creates a new (struct spwd) containing the + * information in the pointed-to (struct passwd). + * + * This function is borrowed from the Shadow Password Suite. + */ +#ifdef SHADOW_PASSWORD +struct spwd *pwd_to_spwd(const struct passwd *pw) +{ + static struct spwd sp; + + /* + * Nice, easy parts first. The name and passwd map directly + * from the old password structure to the new one. + */ + sp.sp_namp = pw->pw_name; + sp.sp_pwdp = pw->pw_passwd; + + /* + * Defaults used if there is no pw_age information. + */ + sp.sp_min = 0; + sp.sp_max = (10000L * DAY) / SCALE; + sp.sp_lstchg = time((time_t *) 0) / SCALE; + + /* + * These fields have no corresponding information in the password + * file. They are set to uninitialized values. + */ + sp.sp_warn = -1; + sp.sp_expire = -1; + sp.sp_inact = -1; + sp.sp_flag = -1; + + return &sp; +} +#endif + + + +/* + * new_password - validate old password and replace with new + * (both old and new in global "char crypt_passwd[128]") + */ +static int new_password(const struct passwd *pw, char *newpasswd) +{ + char *cp; /* Pointer to getpass() response */ + char pass[200]; /* New password */ +#ifdef HAVE_LIBCRACK_HIST + int HistUpdate P_((const char *, const char *)); +#endif + + sprintf(pass, "%s", newpasswd); + + /* + * Encrypt the password, then wipe the cleartext password. + */ + cp = pw_encrypt(pass, crypt_make_salt()); + bzero(pass, sizeof pass); + +#ifdef HAVE_LIBCRACK_HIST + HistUpdate(pw->pw_name, crypt_passwd); +#endif + STRFCPY(crypt_passwd, cp); + return 0; +} + + + +static void update_noshadow(int shadow_locked) +{ + const struct passwd *pw; + struct passwd *npw; + + /* + * call this with shadow_locked != 0 to avoid calling lckpwdf() + * twice (which will fail). XXX - pw_lock(), pw_unlock(), + * spw_lock(), spw_unlock() really should track the lock count + * and call lckpwdf() only before the first lock, and ulckpwdf() + * after the last unlock. + */ + if (!(shadow_locked ? pw_lock() : pw_lock_first())) { + fprintf(stderr, "Cannot lock the password file; try again later.\n"); + syslog(LOG_WARNING, "can't lock password file"); + exit(5); + } + if (!pw_open(O_RDWR)) { + fprintf(stderr, "Cannot open the password file.\n"); + syslog(LOG_ERR, "can't open password file"); + fail_exit(3); + } + pw = pw_locate(name); + if (!pw) { + fprintf(stderr, "mbpasswd: user %s not found in /etc/passwd\n", name); + fail_exit(1); + } + npw = __pw_dup(pw); + if (!npw) + oom(); + npw->pw_passwd = update_crypt_pw(npw->pw_passwd); + if (!pw_update(npw)) { + fprintf(stderr, "Error updating the password entry.\n"); + syslog(LOG_ERR, "error updating password entry"); + fail_exit(3); + } + if (!pw_close()) { + fprintf(stderr, "Cannot commit password file changes.\n"); + syslog(LOG_ERR, "can't rewrite password file"); + fail_exit(3); + } + pw_unlock(); +} + + + +#ifdef SHADOW_PASSWORD +static void update_shadow(void) +{ + const struct spwd *sp; + struct spwd *nsp; + + if (!spw_lock_first()) { + fprintf(stderr, "Cannot lock the password file; try again later.\n"); + syslog(LOG_WARNING, "can't lock password file"); + exit(5); + } + if (!spw_open(O_RDWR)) { + fprintf(stderr, "Cannot open the password file.\n"); + syslog(LOG_ERR, "can't open password file"); + fail_exit(3); + } + sp = spw_locate(name); + if (!sp) { +#if 0 + fprintf(stderr, "%s: user %s not found in /etc/shadow\n", + Prog, name); + fail_exit(1); +#else + /* Try to update the password in /etc/passwd instead. */ + spw_unlock(); + update_noshadow(1); + return; +#endif + } + nsp = __spw_dup(sp); + if (!nsp) + oom(); + nsp->sp_pwdp = update_crypt_pw(nsp->sp_pwdp); + if (do_update_age) + nsp->sp_lstchg = time((time_t *) 0) / SCALE; + + if (!spw_update(nsp)) { + fprintf(stderr, "Error updating the password entry.\n"); + syslog(LOG_ERR, "error updating password entry"); + fail_exit(3); + } + if (!spw_close()) { + fprintf(stderr, "Cannot commit password file changes.\n"); + syslog(LOG_ERR, "can't rewrite password file"); + fail_exit(3); + } + spw_unlock(); +} +#endif /* SHADOWPWD */ + + + +/* + * Function will set a new password in the users password file. + * Note that this function must run setuid root! + */ +int main(int argc, char *argv[]) +{ + const struct passwd *pw; + const struct group *gr; +#ifdef SHADOW_PASSWORD + const struct spwd *sp; +#endif + char *cp; + + /* + * Get my username + */ + pw = get_my_pwent(); + if (!pw) { + fprintf(stderr, "mbpasswd: Cannot determine your user name.\n"); + exit(1); + } + myname = xstrdup(pw->pw_name); + + /* + * Get my groupname, this must be "bbs", other users may not + * use this program, not even root. + */ + gr = getgrgid(pw->pw_gid); + if (!gr) { + fprintf(stderr, "mbpasswd: Cannot determine group name.\n"); + exit(1); + } + if (strcmp(gr->gr_name, (char *)"bbs")) { + fprintf(stderr, "mbpasswd: You are not a member of group \"bbs\".\n"); + exit(1); + } + +// NOOT dit programma moet kontroleren of het is aangeroepen door mbsebbs. +// ook kontroleren of de originele uid en gid correct zijn. +// Gewone stervelingen mogen dit niet kunnen starten. +// Dit programma is een groot security gat. + + if (argc != 4) { + printf("\nmbpasswd commandline:\n\n"); + printf("mbpasswd [-opt] [username] [newpassword]\n"); + printf("options are: -n normal password change\n"); + printf(" -f forced password change\n"); + exit(1); + } + + if (strncmp(argv[1], "-f", 2) == 0) + force = 1; + else + force = 0; + + /* + * Check stringlengths + */ + if (strlen(argv[2]) > 16) { + fprintf(stderr, "mbpasswd: Username too long\n"); + exit(1); + } + if (strlen(argv[3]) > 16) { + fprintf(stderr, "mbpasswd: Password too long\n"); + exit(1); + } + + name = strdup(argv[2]); + if ((pw = getpwnam(name)) == NULL) { + fprintf(stderr, "mbpasswd: Unknown user %s\n", name); + exit(1); + } + + openlog("mbpasswd", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH); + +#ifdef SHADOW_PASSWORD + sp = getspnam(name); + if (!sp) + sp = pwd_to_spwd(pw); + + cp = sp->sp_pwdp; +#else + cp = pw->pw_passwd; +#endif + + /* + * See if the user is permitted to change the password. + * Otherwise, go ahead and set a new password. + */ +#ifdef SHADOW_PASSWORD + check_password(pw, sp); +#else + check_password(pw); +#endif + + if (new_password(pw, argv[3])) { + fprintf(stderr, "The password for %s is unchanged.\n", name); + closelog(); + exit(1); + } + do_update_pwd = 1; + do_update_age = 1; + + /* + * Before going any further, raise the ulimit to prevent + * colliding into a lowered ulimit, and set the real UID + * to root to protect against unexpected signals. Any + * keyboard signals are set to be ignored. + */ + pwd_init(); + + if (setuid(0)) { + fprintf(stderr, "Cannot change ID to root.\n"); + syslog(LOG_ERR, "can't setuid(0)"); + closelog(); + exit(1); + } + +#ifdef SHADOW_PASSWORD + if (spw_file_present()) + update_shadow(); + else +#endif + update_noshadow(0); + + syslog(LOG_INFO, "password for `%s' changed by user `%s'", name, myname); + closelog(); + exit(0); +} + + diff --git a/mbsebbs/mbpasswd.h b/mbsebbs/mbpasswd.h new file mode 100644 index 00000000..e76aebeb --- /dev/null +++ b/mbsebbs/mbpasswd.h @@ -0,0 +1,30 @@ +#ifndef _MBUSERADD_H +#define _MBUSERADD_H + + + /* danger - side effects */ +#define STRFCPY(A,B) \ + (strncpy((A), (B), sizeof(A) - 1), (A)[sizeof(A) - 1] = '\0') + + +/* + * Function prototypes + */ +struct passwd *get_my_pwent(void); +static int new_password (const struct passwd *, char *); +static void fail_exit(int); +static void oom(void); +void pwd_init(void); +char *crypt_make_salt(void); +char *pw_encrypt(const char *, const char *); +int i64c(int); +char *l64a(long); +static void update_noshadow(int); + +#ifdef SHADOW_PASSWORD +struct spwd *pwd_to_spwd(const struct passwd *); +static void update_shadow(void); +#endif + +#endif + diff --git a/mbsebbs/mbsebbs.c b/mbsebbs/mbsebbs.c new file mode 100644 index 00000000..b56a2c39 --- /dev/null +++ b/mbsebbs/mbsebbs.c @@ -0,0 +1,241 @@ +/***************************************************************************** + * + * File ..................: bbs/mbsebbs.c + * Purpose ...............: Main startup + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "mbsebbs.h" +#include "user.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "menu.h" +#include "misc.h" +#include "bye.h" +#include "timeout.h" + +extern int do_quiet; /* Logging quiet flag */ +extern char *Passwd; +time_t t_start; + + + +int main(int argc, char **argv) +{ + FILE *pTty; + char *p, *tty; + int i; + char temp[PATH_MAX]; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + printf("Loading MBSE BBS ...\n"); + pTTY = calloc(15, sizeof(char)); + tty = ttyname(1); + + /* + * Set the users device to writable by other bbs users, so they + * can send one-line messages + */ + chmod(tty, 00666); + + /* + * Get MBSE_ROOT Path and load Config into Memory + */ + FindMBSE(); + if (!strlen(CFG.startname)) { + printf("FATAL: No bbs startname, edit mbsetup 1.1.10\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + /* + * Set uid and gid to the "mbse" user. + */ + if ((pw = getpwnam((char *)"mbse")) == NULL) { + perror("Can't find user \"mbse\" in /etc/passwd"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + if ((setuid(pw->pw_uid) == -1) || (setgid(pw->pw_gid) == -1)) { + perror("Can't setuid() or setgid() to \"mbse\" user"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + /* + * Set local time and statistic indexes. + */ + time(&Time_Now); + time(&t_start); + l_date = localtime(&Time_Now); + Diw = l_date->tm_wday; + Miy = l_date->tm_mon; + time(<ime); + + /* + * Initialize this client with the server. We don't know + * who is at the other end of the line, so that's what we tell. + */ + do_quiet = TRUE; + InitClient((char *)"Unknown", (char *)"mbsebbs", (char *)"Unknown", CFG.logfile, CFG.bbs_loglevel, CFG.error_log); + IsDoing("Loging in"); + + Syslog(' ', " "); + Syslog(' ', "MBSEBBS v%s", VERSION); + + if ((p = getenv("CONNECT")) != NULL) + Syslog('+', "CONNECT %s", p); + if ((p = getenv("CALLER_ID")) != NULL) + if (!strncmp(p, "none", 4)) + Syslog('+', "CALLER %s", p); + + sUnixName[0] = '\0'; + + if (argc == 3) { + iUnixMode = TRUE; + strcpy(sUnixName, argv[2]); + } else if ((getenv("LOGNAME") != NULL) && (strcmp(getenv("LOGNAME"), CFG.startname))) { + iUnixMode = TRUE; + strcpy(sUnixName, getenv("LOGNAME")); + } + + /* + * Initialize + */ + InitLanguage(); + InitMenu(); + memset(&MsgBase, 0, sizeof(MsgBase)); + + i = getpid(); + + tty = ttyname(0); + if (strncmp("/dev/", tty, 5) == 0) + sprintf(pTTY, "%s", tty+5); + else if (*tty == '/') { + tty = strrchr(ttyname(0), '/'); + ++tty; + sprintf(pTTY, "%s", tty); + } + + umask(007); + + /* + * Trap signals + */ + for(i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGBUS) || (i == SIGILL) || + (i == SIGSEGV) || (i == SIGTERM) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + /* + * Default set the terminal to ANSI mode. If your logo + * is in color, the user will see color no mather what. + */ + TermInit(1); + + sprintf(temp, "chat.%s", pTTY); + if(access(temp, F_OK) == 0) + unlink(temp); + + /* + * Now it's time to check if the bbs is open. If not, we + * log the user off. + */ + if (CheckStatus() == FALSE) { + Syslog('+', "Kicking user out, the BBS is closed"); + Quick_Bye(0); + } + + clear(); + DisplayLogo(); + + colour(14, 0); + printf("MBSE BBS v%s (Release: %s)\n", VERSION, ReleaseDate); + colour(15, 0); + printf("%s\n\n", Copyright); + + /* + * Check if this port is available. + */ + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + + if ((pTty = fopen(temp, "r")) == NULL) { + WriteError("Can't read %s", temp); + } else { + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, pTty); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, pTty) == 1) { + if (strcmp(ttyinfo.tty, pTTY) == 0) + break; + } + fclose(pTty); + + if ((strcmp(ttyinfo.tty, pTTY) != 0) || (!ttyinfo.available)) { + Syslog('+', "No BBS allowed on port \"%s\"", pTTY); + printf("No BBS on this port allowed!\n\n"); + Quick_Bye(0); + } + + /* + * Ask whether to display Connect String + */ + if(CFG.iConnectString) { + /* Connected on port */ + colour(3, 0); + printf("%s\"%s\" ", (char *) Language(348), ttyinfo.comment); + /* on */ + printf("%s %s\n", (char *) Language(135), ctime(<ime)); + } + } + + sprintf(sMailbox, "mailbox"); + colour(7, 0); + Passwd = calloc(16, sizeof(char)); + user(); + return 0; +} + diff --git a/mbsebbs/mbsebbs.h b/mbsebbs/mbsebbs.h new file mode 100644 index 00000000..db7bcade --- /dev/null +++ b/mbsebbs/mbsebbs.h @@ -0,0 +1,10 @@ +/* mbsebbs.h */ + +#ifndef _MBSEBBS_H +#define _MBSEBBS_H + +#define ReleaseDate __DATE__ + + +#endif + diff --git a/mbsebbs/mbstat.c b/mbsebbs/mbstat.c new file mode 100644 index 00000000..acb9bbd1 --- /dev/null +++ b/mbsebbs/mbstat.c @@ -0,0 +1,284 @@ +/***************************************************************************** + * + * File ..................: mbstat/mbstat.c + * Purpose ...............: Change BBS status + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbstat.h" + + +extern int do_quiet; +time_t t_start, t_end; + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbstat [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" c close Close the BBS for users\n"); + printf(" o open Open the BBS for users\n"); + printf(" s set semafore Set named semafore\n"); + printf(" w wait Wait until the BBS is free\n\n"); + colour(9,0); + printf(" Options are:\n\n"); + colour(3, 0); + printf(" -q -quiet Quiet, no screen output\n"); + colour(7, 0); + die(0); +} + + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBSTAT: MBSE BBS %s Status Changer\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); + colour(3, 0); +} + + + +void die(int onsig) +{ + signal(onsig, SIG_IGN); + + if (onsig) + WriteError("$Terminated on signal %d", onsig); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + + time(&t_end); + Syslog(' ', "MBSTAT finished in %s", t_elapsed(t_start, t_end)); + + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i; + char *cmd, *semafore = NULL; + int do_open = FALSE; + int do_close = FALSE; + int do_wait = FALSE; + int do_sema = FALSE; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + time(&t_start); + + /* + * Catch or ignore signals + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM) || + (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + cmd = xstrcpy((char *)"Command line: mbstat"); + + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (!strncmp(tl(argv[i]), "w", 1)) + do_wait = TRUE; + if (!strncmp(tl(argv[i]), "o", 1)) + do_open = TRUE; + if (!strncmp(tl(argv[i]), "c", 1)) + do_close = TRUE; + if (!strncmp(tl(argv[i]), "s", 1)) { + do_sema = TRUE; + i++; + semafore = xstrcpy(tl(argv[i])); + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + } + if (!strncmp(tl(argv[i]), "-q", 2)) + do_quiet = TRUE; + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbstat", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + usleep(1); + + Syslog(' ', " "); + Syslog(' ', "MBSTAT v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + colour(3, 0); + printf("\n"); + } + + if (do_close) + do_open = FALSE; + + if (do_open) { + Open(); + do_close = FALSE; + do_wait = FALSE; + } + + if (do_close) + Close(); + + if (do_wait) + Wait(); + + if (do_sema) + Semafore(semafore); + + if (!(do_open || do_close || do_wait || do_sema)) + Help(); + + usleep(1); + die(0); + return 0; +} + + + +int Semafore(char *semafore) +{ + char buf[81]; + + strcpy(buf, SockR("SECR:1,%s;", semafore)); + if (strncmp(buf, "100:0;", 6) == 0) { + Syslog('+', "Semafore \"%s\" is set", semafore); + if (!do_quiet) + printf("Semafore \"%s\" is set\n", semafore); + return TRUE; + } else { + Syslog('+', "Failed to set \"%s\" semafore", semafore); + printf("Failed to set \"%s\" semafore\n", semafore); + return FALSE; + } +} + + + +int Close(void) +{ + char buf[81]; + + strcpy(buf, SockR("SCLO:0;")); + if (strncmp(buf, "100:0;", 6) == 0) { + Syslog('+', "The BBS is closed"); + if (!do_quiet) + printf("The BBS is closed\n"); + return TRUE; + } else { + printf("Failed to close the BBS\n"); + return FALSE; + } +} + + + +int Open(void) +{ + char buf[81]; + + strcpy(buf, SockR("SOPE:0;")); + if (strncmp(buf, "100:0;", 6) == 0) { + Syslog('+', "The BBS is open"); + if (!do_quiet) + printf("The BBS is open\n"); + return TRUE; + } else { + printf("Failed to open the BBS\n"); + return FALSE; + } +} + + + +int Wait(void) +{ + int Waiting = 3600; + char buf[PATH_MAX]; + + sprintf(buf, "%s/sema/upsdown", getenv("MBSE_ROOT")); + if (file_exist(buf, R_OK)) + Waiting = 30; + + Syslog('+', "Waiting for the BBS to become free, timout %d seconds", Waiting); + while (Waiting) { + strcpy(buf, SockR("SFRE:0;")); + if (strncmp(buf, "100:0;", 6) == 0) { + Syslog('+', "The BBS is free"); + if (!do_quiet) + printf("The BBS is free. \n"); + return TRUE; + } + if (!do_quiet) { + buf[strlen(buf) -1] = '\0'; + printf("\r%s\r", buf+6); + fflush(stdout); + } + sleep(1); + Waiting--; + } + + WriteError("Wait for BBS free timeout, aborting"); + return FALSE; +} + + diff --git a/mbsebbs/mbstat.h b/mbsebbs/mbstat.h new file mode 100644 index 00000000..195c189c --- /dev/null +++ b/mbsebbs/mbstat.h @@ -0,0 +1,14 @@ +#ifndef _MBSTAT_H +#define _MBSTAT_H + + +void Help(void); +void ProgName(void); +void die(int); +int Semafore(char *); +int Open(void); +int Close(void); +int Wait(void); + +#endif + diff --git a/mbsebbs/mbtoberep.c b/mbsebbs/mbtoberep.c new file mode 100644 index 00000000..c7f6a279 --- /dev/null +++ b/mbsebbs/mbtoberep.c @@ -0,0 +1,102 @@ +/***************************************************************************** + * + * File ..................: mbtoberep/mbtoberep.c + * Purpose ...............: Show contents of toberep.data + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" + + +int main(int argc, char **argv) +{ + char *BBSpath; + char *temp; + FILE *fp; + struct _filerecord rep; + int i; + +#ifdef MEMWATCH + mwInit(); +#endif + if ((BBSpath = getenv("MBSE_ROOT")) == NULL) { + printf("MBSE_ROOT variable not set\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/toberep.data", BBSpath); + + if ((fp = fopen(temp, "r")) == NULL) { + printf("File %s not found\n", temp); + free(temp); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + while (fread(&rep, sizeof(rep), 1, fp) == 1) { + printf("File echo %s\n", rep.Echo); + printf("Comment %s\n", rep.Comment); + printf("Group %s\n", rep.Group); + printf("File name %s\n", rep.Name); + printf("FIle size %lu\n", rep.Size); + printf("File size Kb %lu\n", rep.SizeKb); + printf("File date %s", ctime(&rep.Fdate)); + printf("File CRC %s\n", rep.Crc); + printf("Origin system %s\n", rep.Origin); + printf("From system %s\n", rep.From); + printf("Replace %s\n", rep.Replace); + printf("Magic %s\n", rep.Magic); + printf("Cost %ld\n", rep.Cost); + printf("Announce "); + if (rep.Announce) + printf("yes\n"); + else + printf("no\n"); + printf("Description %s\n", rep.Desc); + for (i = 0; i < rep.TotLdesc; i++) { + printf(" %2d %s\n", (int)strlen(rep.LDesc[i]), rep.LDesc[i]); + } + printf("\n\n"); + } + + fclose(fp); + free(temp); +#ifdef MEMWATCH + mwTerm(); +#endif + return 0; +} + + + diff --git a/mbsebbs/mbuser.c b/mbsebbs/mbuser.c new file mode 100644 index 00000000..46db78b1 --- /dev/null +++ b/mbsebbs/mbuser.c @@ -0,0 +1,361 @@ +/***************************************************************************** + * + * File ..................: mbuser/mbuser.c + * Purpose ...............: User Pack Util + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbuser.h" + + +extern int e_pid; /* External pid */ +extern int do_quiet; /* Quiet flag */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +int Days, Level; /* Kill days and up to level */ +struct userhdr usrhdr; /* Database header */ +struct userrec usr; /* Database record */ +mode_t oldmask; /* Old umask value */ + + +int main(int argc, char **argv) +{ + int i, pack = FALSE; + char *cmd; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + Days = 0; + Level = 0; + + time(&t_start); + + if (argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line:"); + + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (strncasecmp(tl(argv[i]), "-q", 2) == 0) + do_quiet = TRUE; + if (strncasecmp(tl(argv[i]), "p", 1) == 0) + pack = TRUE; + if (strncasecmp(tl(argv[i]), "k", 1) == 0) { + if (argc <= (i + 2)) + Help(); + i++; + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + Days = atoi(argv[i]); + i++; + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + Level = atoi(argv[i]); + + if ((Days == 0) || (Level == 0)) + Help(); + } + } + + if ((Days + Level + pack) == 0) + Help(); + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbuser", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + Syslog(' ', " "); + Syslog(' ', "MBUSER v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!diskfree(CFG.freespace)) + ExitClient(101); + + oldmask = umask(027); + if (!do_quiet) + colour(3, 0); + UserPack(Days, Level, pack); + umask(oldmask); + + time(&t_end); + Syslog(' ', "MBUSER finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) + colour(7, 0); + ExitClient(0); + return 0; +} + + + +/* + * Program header + */ +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBUSER: MBSE BBS %s - User maintenance utility\n", VERSION); + colour(14, 0); + printf(" %s\n\n", Copyright); + colour(7, 0); +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbuser [commands] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" kill [n] [l] Kill users not called in \"n\" days below level \"l\"\n"); + printf(" pack Pack the userbase\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -quiet Quiet mode, (no screen output)\n\n"); + + colour(7, 0); + printf("\n"); + ExitClient(1); +} + + + +/* + * Userpack routine + */ +void UserPack(int days, int level, int pack) +{ + FILE *fin, *fout; + char *fnin, *fnout; + long oldsize, curpos; + int updated, delete = 0, rc, highest = 0, record = 0, sysop = FALSE; + + fnin = calloc(PATH_MAX, sizeof(char)); + fnout = calloc(PATH_MAX, sizeof(char)); + sprintf(fnin, "%s/etc/users.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/users.temp", getenv("MBSE_ROOT")); + + /* + * First copy the users database, all packing will be done + * on a the copy. + */ + if ((fin = fopen(fnin, "r")) == NULL) { + WriteError("Can't open %s", fnin); + free(fnin); + free(fnout); + return; + } + if ((fout = fopen(fnout, "w+")) == NULL) { + WriteError("Can't create %s", fnout); + fclose(fin); + free(fnin); + free(fnout); + return; + } + fread(&usrhdr, sizeof(usrhdr), 1, fin); + oldsize = usrhdr.recsize; + updated = FALSE; + + /* + * First count records and blanks at the end. Check if the sysop name + * in the main configuration exists in the userdatabase. + */ + while (fread(&usr, oldsize, 1,fin) == 1) { + delete++; + if (!usr.Deleted && strlen(usr.sUserName)) { + highest = (ftell(fin) / oldsize); + if (!strcmp(usr.sUserName, CFG.sysop_name) && !strcmp(usr.Name, CFG.sysop)) + sysop = TRUE; + } + } + if (highest != delete) { + Syslog('+', "Blank records at the end, truncating userbase"); + updated = TRUE; + } + if (!sysop) + WriteError("No valid Sysop Fidoname and/or Unixname found in userbase, check setup!"); + + fseek(fin, usrhdr.hdrsize, SEEK_SET); + + if (oldsize != sizeof(usr)) { + updated = TRUE; + Syslog('+', "Userbase recordsize is changed, making update"); + } + + usrhdr.hdrsize = sizeof(usrhdr); + usrhdr.recsize = sizeof(usr); + fwrite(&usrhdr, sizeof(usrhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each read + * so that if the record format changed, the new fields will + * be empty by default. The blank records at the end of the + * database are dropped. + */ + memset(&usr, 0, sizeof(usr)); + while (fread(&usr, oldsize, 1,fin) == 1) { + record++; + fwrite(&usr, sizeof(usr), 1, fout); + memset(&usr, 0, sizeof(usr)); + if (CFG.slow_util && do_quiet) + usleep(1); + } + fclose(fin); + delete = 0; + + /* + * Handle packing for days below level + */ + if ((days) && (level)) { + fseek(fout, sizeof(usrhdr), SEEK_SET); + curpos = sizeof(usrhdr); + + while (fread(&usr, sizeof(usr), 1, fout) == 1) { + /* + * Wow, killing on the second exact!. Don't kill + * the guest accounts. + */ + if ((((t_start - usr.tLastLoginDate) / 86400) > days) && + (usr.Security.level < level) && (!usr.Guest) && + (usr.sUserName[0] != '\0') && (!usr.NeverDelete)) { + Syslog('+', "Mark user %s", usr.sUserName); + if (!do_quiet) { + printf("Mark user %s\n", usr.sUserName); + fflush(stdout); + } + delete++; + updated = TRUE; + fseek(fout, - sizeof(usr), SEEK_CUR); + /* + * Just mark for deletion + */ + usr.Deleted = TRUE; + fwrite(&usr, sizeof(usr), 1, fout); + } + if (CFG.slow_util && do_quiet) + usleep(1); + } + Syslog('+', "Marked %d users to delete", delete); + } + + /* + * Pack the userbase if told so + */ + if (pack) { + Syslog('+', "Packing userbase"); + delete = 0; + fseek(fout, sizeof(usrhdr), SEEK_SET); + while (fread(&usr, sizeof(usr), 1, fout) == 1) { + if (CFG.slow_util && do_quiet) + usleep(1); + + if (usr.Deleted) { + if (!do_quiet) { + printf("Delete user %s\n", usr.Name); + fflush(stdout); + } + if (usr.Name[0] != '\0') { + if ((setuid(0) == -1) || (setgid(0) == -1)) { + WriteError("Cannot setuid(root) or setgid(root)"); + WriteError("Cannot delete unix account %s", usr.Name); + } else { + rc = execute((char *)"/usr/sbin/userdel ", usr.Name, NULL, + (char *)"/dev/null",(char *)"/dev/null",(char *)"/dev/null"); + if (chdir(CFG.bbs_usersdir) == 0) + rc = execute((char *)"/bin/rm -Rf ", usr.Name, NULL, + (char *)"/dev/null",(char *)"/dev/null",(char *)"/dev/null"); + } + } + + fseek(fout, - sizeof(usr), SEEK_CUR); + /* + * Blank the deleted records for reuse. + */ + memset(&usr, 0, sizeof(usr)); + fwrite(&usr, sizeof(usr), 1, fout); + delete++; + updated = TRUE; + } + } + Syslog('+', "Deleted %d records", delete); + } + + if (updated) { + /* + * Copy file back to the original file, truncate any + * deleted records at the end. + */ + fseek(fout, 0, SEEK_SET); + if ((fin = fopen(fnin, "w")) == NULL) { + WriteError("Can't open %s", fnin); + free(fnin); + free(fnout); + return; + } + fread(&usrhdr, sizeof(usrhdr), 1, fout); + fwrite(&usrhdr, sizeof(usrhdr), 1, fin); + record = 0; + + while (fread(&usr, sizeof(usr), 1,fout) == 1) { + record++; + fwrite(&usr, sizeof(usr), 1, fin); + if (record >= highest) + break; + } + fclose(fin); + fclose(fout); + Syslog('+', "Userbase is updated, written %d records", record); + } + unlink(fnout); + free(fnin); + free(fnout); +} + + + diff --git a/mbsebbs/mbuser.h b/mbsebbs/mbuser.h new file mode 100644 index 00000000..6f69e12e --- /dev/null +++ b/mbsebbs/mbuser.h @@ -0,0 +1,9 @@ +#ifndef _MBUSER_H +#define _MBUSER_H + +void ProgName(void); +void Help(void); +void UserPack(int, int, int); + +#endif + diff --git a/mbsebbs/mbuseradd.c b/mbsebbs/mbuseradd.c new file mode 100644 index 00000000..74d36c83 --- /dev/null +++ b/mbsebbs/mbuseradd.c @@ -0,0 +1,265 @@ +/***************************************************************************** + * + * File ..................: mbuseradd.c + * Purpose ...............: setuid root version of useradd + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mbuseradd.h" + + + + +int execute(char *cmd, char *file, char *in, char *out, char *err) +{ + char buf[PATH_MAX]; + char *vector[16]; + int i; + int pid, status, rc, sverr; + + sprintf(buf, "%s %s", cmd, file); + + i=0; + vector[i++] = strtok(buf, " \t\n"); + while ((vector[i++] = strtok(NULL," \t\n")) && (i < 16)); + vector[15] = NULL; + fflush(stdout); + fflush(stderr); + + if ((pid = fork()) == 0) { + if (in) { + close(0); + if (open(in, O_RDONLY) != 0) { + perror(""); + fprintf(stderr, "mbuseradd: Reopen of stdin to %s failed\n", in); + exit(-1); + } + } + if (out) { + close(1); + if (open(out, O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { + perror(""); + fprintf(stderr, "mbuseradd: Reopen of stdout to %s failed\n", out); + exit(-1); + } + } + if (err) { + close(2); + if (open(err, O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { + perror(""); + fprintf(stderr, "mbuseradd: Reopen of stderr to %s failed\n", err); + exit(-1); + } + } + rc = execv(vector[0],vector); + fprintf(stderr, "mbuseradd: Exec \"%s\" returned %d\n", vector[0], rc); + exit(-1); + } + + do { + rc = wait(&status); + sverr = errno; + } while (((rc > 0) && (rc != pid)) || ((rc == -1) && (sverr == EINTR))); + + if (rc == -1) { + fprintf(stderr, "mbuseradd: Wait returned %d, status %d,%d\n", rc, status >> 8, status & 0xff); + return -1; + } + + return status; +} + + + +void makedir(char *path, mode_t mode, uid_t owner, gid_t group) +{ + if (mkdir(path, mode) != 0) { + perror(""); + fprintf(stderr, "mbuseradd: Can't create %s\n", path); + exit(2); + } + if ((chown(path, owner, group)) == -1) { + perror(""); + fprintf(stderr, "mbuseradd: Unable to change ownership of %s\n", path); + exit(2); + } +} + + + +/* + * Function will create the users name in the passwd file + * Note that this function must run setuid root! + */ +int main(int argc, char *argv[]) +{ + char *PassEnt, *temp, *shell; + int i; + struct passwd *pwent, *pwuser; + FILE *fp; + + if (setuid(0) == -1 || setgid(1) == -1) { + perror(""); + fprintf(stderr, "mbuseradd: Unable to setuid(root) or setgid(root)\n"); + fprintf(stderr, "Make sure that this program is set to -rwsr-sr-x\n"); + fprintf(stderr, "Owner must be root and group root\n"); + exit(1); + } + + if (argc != 5) + Help(); + + for (i = 1; i < 5; i++) { + if (strlen(argv[i]) > 80) { + fprintf(stderr, "mbuseradd: Argument %d is too long\n", i); + exit(1); + } + } + + PassEnt = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + shell = calloc(PATH_MAX, sizeof(char)); + + /* + * Build command to add user entry to the /etc/passwd and /etc/shadow + * files. We use the systems own useradd program. + */ + if ((access("/usr/bin/useradd", R_OK)) == 0) + strcpy(temp, "/usr/bin/useradd"); + else if ((access("/bin/useradd", R_OK)) == 0) + strcpy(temp, "/bin/useradd"); + else if ((access("/usr/sbin/useradd", R_OK)) == 0) + strcpy(temp, "/usr/sbin/useradd"); + else if ((access("/sbin/useradd", R_OK)) == 0) + strcpy(temp, "/sbin/useradd"); + else { + fprintf(stderr, "mbuseradd: Can't find useradd\n"); + exit(1); + } + + sprintf(shell, "%s/bin/mbsebbs", getenv("MBSE_ROOT")); + + sprintf(PassEnt, "%s -c \"%s\" -d %s/%s -g %s -s %s %s", + temp, argv[3], argv[4], argv[2], argv[1], shell, argv[2]); + fflush(stdout); + fflush(stdin); + + if (system(PassEnt) != 0) { + perror("mbuseradd: Failed to create unix account\n"); + exit(1); + } + + /* + * Now create directories and files for this user. + */ + if ((pwent = getpwnam((char *)"mbse")) == NULL) { + perror("mbuseradd: Can't get password entry for \"mbse\"\n"); + exit(2); + } + + /* + * Check bbs users base home directory + */ + if ((access(argv[4], R_OK)) != 0) + makedir(argv[4], 0770, pwent->pw_uid, pwent->pw_gid); + + /* + * Now create users home directory. Check for an existing directory, + * some systems have already created a home directory. If one is found + * it is removed to create a fresh one. + */ + sprintf(temp, "%s/%s", argv[4], argv[2]); + if ((access(temp, R_OK)) == 0) { + if ((access("/bin/rm", X_OK)) == 0) + strcpy(shell, "/bin/rm"); + else if ((access("/usr/bin/rm", X_OK)) == 0) + strcpy(shell, "/usr/bin/rm"); + else { + fprintf(stderr, "mbuseradd: Can't find rm\n"); + exit(2); + } + sprintf(PassEnt, " -Rf %s", temp); + fflush(stdout); + fflush(stdin); + i = execute(shell, PassEnt, (char *)"/dev/tty", (char *)"/dev/tty", (char *)"/dev/tty"); + + if (i != 0) { + fprintf(stderr, "mbuseradd: Unable remove old home directory\n"); + exit(2); + } + } + + /* + * Create users home directory. + */ + pwuser = getpwnam(argv[2]); + makedir(temp, 0770, pwuser->pw_uid, pwent->pw_gid); + + /* + * Create Maildir and subdirs for Qmail. + */ + sprintf(temp, "%s/%s/Maildir", argv[4], argv[2]); + makedir(temp, 0700, pwuser->pw_uid, pwent->pw_gid); + sprintf(temp, "%s/%s/Maildir/cur", argv[4], argv[2]); + makedir(temp, 0700, pwuser->pw_uid, pwent->pw_gid); + sprintf(temp, "%s/%s/Maildir/new", argv[4], argv[2]); + makedir(temp, 0700, pwuser->pw_uid, pwent->pw_gid); + sprintf(temp, "%s/%s/Maildir/tmp", argv[4], argv[2]); + makedir(temp, 0700, pwuser->pw_uid, pwent->pw_gid); + + free(shell); + free(PassEnt); + free(temp); + + exit(0); +} + + + +void Help() +{ + fprintf(stderr, "\nmbuseradd commandline:\n\n"); + fprintf(stderr, "mbuseradd [gid] [name] [comment] [usersdir]\n"); + exit(1); +} + + diff --git a/mbsebbs/mbuseradd.h b/mbsebbs/mbuseradd.h new file mode 100644 index 00000000..963f8fa6 --- /dev/null +++ b/mbsebbs/mbuseradd.h @@ -0,0 +1,10 @@ +#ifndef _MBUSERADD_H +#define _MBUSERADD_H + + +int execute(char *, char *, char *, char *, char *); +void makedir(char *, mode_t, uid_t, gid_t); +void Help(void); + +#endif + diff --git a/mbsebbs/menu.c b/mbsebbs/menu.c new file mode 100644 index 00000000..afa4f7f2 --- /dev/null +++ b/mbsebbs/menu.c @@ -0,0 +1,672 @@ +/***************************************************************************** + * + * File ..................: bbs/menu.c + * Purpose ...............: Display and handle the menus. + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "oneline.h" +#include "mail.h" +#include "bbslist.h" +#include "change.h" +#include "bank.h" +#include "chat.h" +#include "file.h" +#include "funcs.h" +#include "funcs4.h" +#include "misc.h" +#include "nextuser.h" +#include "safe.h" +#include "timeout.h" +#include "menu.h" +#include "page.h" +#include "pinfo.h" +#include "bye.h" +#include "timecheck.h" +#include "exitinfo.h" +#include "language.h" +#include "offline.h" +#include "email.h" + + +/* + * Menu stack, 50 levels deep. + */ +char Menus[50][15]; +int MenuLevel; +int MenuError; + + +void InitMenu() +{ + int i; + + for (i = 0; i < 50; i++) + memset(Menus[i], 0, 51); + MenuLevel = 0; + MenuError = 0; + sprintf(Menus[0], "%s", CFG.default_menu); +} + + + +void menu() +{ + FILE *pMenuFile; + int iFoundKey = FALSE, Key; + char *Input, *Semfile; + char *sMenuPathFileName; + + Input = calloc(81, sizeof(char)); + sMenuPathFileName = calloc(PATH_MAX, sizeof(char)); + + /* + * Loop forever, this is what a BBS should do until a user logs out. + */ + while (TRUE) { + + WhosDoingWhat(BROWSING); + + /* + * Open menufile, first users language menu, if it fails + * try to open the default menu. + */ + sprintf(sMenuPathFileName,"%s/%s", lang.MenuPath, Menus[MenuLevel]); + if ((pMenuFile = fopen(sMenuPathFileName, "r")) == NULL) { + sprintf(sMenuPathFileName,"%s/%s", CFG.bbs_menus, Menus[MenuLevel]); + pMenuFile = fopen(sMenuPathFileName,"r"); + if (pMenuFile != NULL) + Syslog('+', "Menu %s (Default)", Menus[MenuLevel]); + } else { + Syslog('+', "Menu %s (%s)", Menus[MenuLevel], lang.Name); + } + + if (pMenuFile == NULL) { + clear(); + WriteError("Can't open menu file: %s", sMenuPathFileName); + MenuError++; + + /* + * Is this the last attempt to open the default menu? + */ + if (MenuError == 10) { + WriteError("FATAL ERROR: Too many menu errors"); + printf("Too many menu errors, notifying Sysop\n\n"); + sleep(3); + die(SIGILL); + } + + /* + * Switch back to the default menu + */ + MenuLevel = 0; + strcpy(Menus[0], CFG.default_menu); + } else { + /* + * Do all autoexec menus first + */ + while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) { + if (menus.AutoExec && Access(exitinfo.Security, menus.MenuSecurity) && (UserAge >= menus.Age)) + DoMenu(menus.MenuType); + } + + /* + * Check if the BBS closed down for Zone Mail Hour or + * system shutdown. If so, we run the Goodbye show. + */ + if (CheckStatus() == FALSE) { + fclose(pMenuFile); + Syslog('+', "Kicking user out, the BBS is closed."); + sleep(3); + Good_Bye(0); + } + + /* + * Check the upsdown semafore + */ + Semfile = calloc(PATH_MAX, sizeof(char)); + sprintf(Semfile, "%s/sema/upsdown", getenv("MBSE_ROOT")); + if (file_exist(Semfile, R_OK) == 0) { + fclose(pMenuFile); + Syslog('+', "Kicking user out, upsdown semafore detected"); + printf("System power failure, closing the bbs\n\n"); + free(Semfile); + sleep(3); + Good_Bye(0); + } + free(Semfile); + + /* + * Check if SysOp wants to chat to user everytime user + * gets prompt. Make sure /tmp/chatdev exists before + * before calling chat(). Make sure if a second user + * logs in, that .BusyChatting does exist. + */ + if(CFG.iChatPromptChk && (access("/tmp/chatdev", R_OK) == 0) && (access("/tmp/.BusyChatting", F_OK) != 0)) + Chat(); + + /* + * Check users timeleft + */ + TimeCheck(); + + alarm_on(); + + if (exitinfo.HotKeys) { + fflush(stdout); + Key = Getone(); + sprintf(Input, "%c", Key); + printf("\n"); + } else { + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(Input, 80); + } + + if((strcmp(Input, "")) != 0) { + + fseek(pMenuFile, 0, SEEK_SET); + + while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) { + + if ((strcmp(tu(Input), menus.MenuKey)) == 0) { + if ((Access(exitinfo.Security, menus.MenuSecurity)) && (UserAge >= menus.Age)) { + Syslog('b', "Menu[%d] %d=(%s), Opt: '%s'", MenuLevel, menus.MenuType, menus.TypeDesc, menus.OptionalData); + if (menus.MenuType == 13) { + /* + * Terminate call, cleanup here + */ + free(Input); + free(sMenuPathFileName); + fclose(pMenuFile); + } + DoMenu(menus.MenuType); + iFoundKey = TRUE; + break; + } + } + } + } + fclose(pMenuFile); + + } /* If menu open */ + } /* while true */ +} + + + +void DoMenu(int Type) +{ + int Strlen, i, x; + char *DisplayF; + char *sPrompt; + char *sPromptBak; + char *temp; + + DisplayF = calloc(81, sizeof(char)); + sPrompt = calloc(81, sizeof(char)); + sPromptBak = calloc(81, sizeof(char)); + temp = calloc(81, sizeof(char)); + + TimeCheck(); + + switch(Type) { + case 1: + /* Goto another menu */ + strncpy(Menus[MenuLevel], menus.OptionalData, 14); + break; + + case 2: + /* Gosub another menu */ + if (MenuLevel < 49) { + MenuLevel++; + strncpy(Menus[MenuLevel], menus.OptionalData, 14); + } else + Syslog('?', "More than 50 menu levels"); + break; + + case 3: + /* Return from gosub */ + if (MenuLevel > 0) + MenuLevel--; + break; + + case 4: + /* Return to top menu */ + MenuLevel = 0; + break; + + case 5: + /* Display .a?? file with controlcodes */ + DisplayFile(menus.OptionalData); + break; + + case 6: + /* Show menu prompt */ + Strlen = strlen(menus.OptionalData); + for(x = 0; x < Strlen; x++) { + if( menus.OptionalData[x] == '~') { + strcat(sPrompt, sUserTimeleft); + } else { + sprintf(temp, "%c", menus.OptionalData[x]); + strcat(sPrompt, temp); + } + } + strcpy(sPromptBak, sPrompt); + strcpy(sPrompt, ""); + Strlen = strlen(sPromptBak); + for(x = 0; x < Strlen; x++) { + if( *(sPromptBak + x) == '@') + strcat(sPrompt, sAreaDesc); + else + if ( *(sPromptBak + x) == '^') + strcat(sPrompt, sMsgAreaDesc); + else + if ( *(sPromptBak + x) == '#') + sprintf(sPrompt, "%s%s", sPrompt, (char *) GetLocalHM()); + + else { + sprintf(temp, "%c", *(sPromptBak + x)); + strcat(sPrompt, temp); + } + } + pout(15, 0, sPrompt); + break; + + case 7: + /* Run external program */ + ExtDoor(menus.OptionalData, menus.NoDoorsys, menus.Y2Kdoorsys, menus.Comport); + break; + + case 8: + /* Show product information */ + cr(); + break; + + case 9: + /* display todays callers */ + LastCallers(menus.OptionalData); + break; + + case 10: + /* display userlist */ + UserList(menus.OptionalData); + break; + + case 11: + /* display time statistics */ + TimeStats(); + break; + + case 12: + /* page sysop for chat */ + Page_Sysop(menus.OptionalData); + break; + + case 13: + /* terminate call */ + free(DisplayF); + free(sPrompt); + free(sPromptBak); + free(temp); + Good_Bye(0); + break; + + case 14: + /* make a log entry */ + LogEntry(menus.OptionalData); + break; + + case 15: + /* print text to screen */ + if (exitinfo.Security.level >= menus.MenuSecurity.level) { + for(i = 0; i < strlen(menus.OptionalData); i++) + if(*(menus.OptionalData + i) == '@') + *(menus.OptionalData + i) = '\n'; + printf("%s\n", menus.OptionalData); + } + break; + + case 16: + /* who's currently online */ + WhosOn(menus.OptionalData); + Pause(); + break; + + case 17: + /* comment to sysop */ + SysopComment((char *)"Comment to Sysop"); + break; + + case 18: + /* send on-line message */ + SendOnlineMsg(menus.OptionalData); + break; + + case 19: + /* display Textfile with more */ + MoreFile(menus.OptionalData); + break; + + case 20: + /* display a?? file with controlcode and wait for enter */ + DisplayFileEnter(menus.OptionalData); + break; + + case 22: + /* nextuser door */ + nextuser(); + break; + + case 23: + /* timebank door */ + Bank(); + break; + + case 24: + /* voting door Not anymore */ + break; + + case 25: + /* safe cracker door */ + Safe(); + break; + + case 101: + FileArea_List(menus.OptionalData); + break; + + case 102: + File_List(); + break; + + case 103: + ViewFile(); + break; + + case 104: + Download(); + break; + + case 105: + File_RawDir(menus.OptionalData); + break; + + case 106: + KeywordScan(); + break; + + case 107: + FilenameScan(); + break; + + case 108: + NewfileScan(TRUE); + break; + + case 109: + Upload(); + break; + + case 110: + EditTaglist(); + break; + + case 111: /* View file in homedir */ + break; + + case 112: + DownloadDirect(menus.OptionalData, TRUE); + break; + + case 113: + Copy_Home(); + break; + + case 114: + List_Home(); + break; + + case 115: + Delete_Home(); + break; + + /* 116 Unpack file in homedir */ + + /* 117 Pack files in homedir */ + + case 118: + Download_Home(); + break; + + case 119: + Upload_Home(); + break; + + case 201: + MsgArea_List(menus.OptionalData); + break; + + case 202: + Post_Msg(); + break; + + case 203: + Read_Msgs(); + break; + + case 204: + CheckMail(); + break; + + case 205: + QuickScan_Msgs(); + break; + + case 206: + Delete_Msg(); + break; + + case 207: + MailStatus(); + break; + + case 208: + OLR_TagArea(); + break; + + case 209: + OLR_UntagArea(); + break; + + case 210: + OLR_ViewTags(); + break; + + case 211: + OLR_RestrictDate(); + break; + + case 212: + OLR_Upload(); + break; + + case 213: + OLR_DownBW(); + break; + + case 214: + OLR_DownQWK(); + break; + + case 215: + OLR_DownASCII(); + break; + + case 216: + Read_Email(); + break; + + case 217: + Write_Email(); + break; + + case 218: + Trash_Email(); + break; + + case 219: + Choose_Mailbox(menus.OptionalData); + break; + + case 220: + QuickScan_Email(); + break; + + case 301: + Chg_Protocol(); + break; + + case 302: + Chg_Password(); + break; + + case 303: + Chg_Location(); + break; + + case 304: + Chg_Graphics(); + break; + + case 305: + Chg_VoicePhone(); + break; + + case 306: + Chg_DataPhone(); + break; + + case 307: + Chg_News(); + break; + + case 308: + Chg_ScreenLen(); + break; + + case 309: + Chg_DOB(); + break; + + case 310: + Chg_Language(FALSE); + break; + + case 311: + Chg_Hotkeys(); + break; + + case 312: + Chg_Handle(); + break; + + case 313: + Chg_MailCheck(); + break; + + case 314: + Chg_Disturb(); + break; + + case 315: + Chg_FileCheck(); + break; + + case 316: + Chg_FsMsged(); + break; + + case 401: + Oneliner_Add(); + break; + + case 402: + Oneliner_List(); + break; + + case 403: + Oneliner_Show(); + break; + + case 404: + Oneliner_Delete(); + break; + + case 405: + Oneliner_Print(); + break; + + case 501: + BBS_Add(); + break; + + case 502: + BBS_List(); + break; + + case 503: + BBS_Show(); + break; + + case 504: + BBS_Delete(); + break; + + case 506: + BBS_Search(); + break; + + default: + Enter(1); + pout(15, 0, (char *) Language(339)); + Enter(2); + Syslog('?', "Option: %s -> Unknown Menu Type: %d on %s", menus.MenuKey, Type, Menus[MenuLevel]); + Pause(); + } + + free(DisplayF); + free(sPrompt); + free(sPromptBak); + free(temp); +} + diff --git a/mbsebbs/menu.h b/mbsebbs/menu.h new file mode 100644 index 00000000..a925d779 --- /dev/null +++ b/mbsebbs/menu.h @@ -0,0 +1,9 @@ +#ifndef _MENU_H +#define _MENU_H + +void InitMenu(void); +void menu(void); +void DoMenu(int); + +#endif + diff --git a/mbsebbs/misc.c b/mbsebbs/misc.c new file mode 100644 index 00000000..08756485 --- /dev/null +++ b/mbsebbs/misc.c @@ -0,0 +1,446 @@ +/***************************************************************************** + * + * File ..................: bbs/misc.c + * Purpose ...............: Misc functions + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "timeout.h" +#include "exitinfo.h" + + +extern pid_t mypid; /* Pid of this program */ + + +int MoreFile(char *filename) +{ + char Buf[80]; + static FILE *fptr; + int lines; + int input; + int ignore = FALSE; + int maxlines; + + maxlines = lines = exitinfo.iScreenLen - 2; + + if ((fptr = fopen(filename,"r")) == NULL) { + printf("%s%s\n", (char *) Language(72), filename); + return(0); + } + + printf("\n"); + + while (fgets(Buf,80,fptr) != NULL) { + if ( (lines != 0) || (ignore) ) { + lines--; + printf("%s",Buf); + } + + if (strlen(Buf) == 0) { + fclose(fptr); + return(0); + } + if (lines == 0) { + fflush(stdin); + /* More (Y/n/=) */ + printf(" %sY\x08", (char *) Language(61)); + fflush(stdout); + alarm_on(); + input = toupper(getchar()); + + if ((input == Keystroke(61, 0)) || (input == '\r')) + lines = maxlines; + + if (input == Keystroke(61, 1)) { + fclose(fptr); + return(0); + } + + if (input == Keystroke(61, 2)) + ignore = TRUE; + else + lines = maxlines; + } + printf("\n\n"); + Pause(); + } + fclose(fptr); + return 1; +} + + + +int GetLastUser() +{ + FILE *pCallerLog; + char *sDataFile; + + sDataFile = calloc(PATH_MAX, sizeof(char)); + sprintf(sDataFile, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + + if((pCallerLog = fopen(sDataFile, "r+")) == NULL) + WriteError("GetLastUser: Can't open file: %s", sDataFile); + else { + fread(&SYSINFO, sizeof(SYSINFO), 1, pCallerLog); + + /* Get lastcaller in memory */ + strcpy(LastCaller, SYSINFO.LastCaller); + + /* Set next lastcaller (this user) */ + if(!usrconfig.Hidden) + strcpy(SYSINFO.LastCaller,exitinfo.sUserName); + + SYSINFO.SystemCalls++; + switch(ttyinfo.type) { + case POTS: + SYSINFO.Pots++; + break; + + case ISDN: + SYSINFO.ISDN++; + break; + + case NETWORK: + SYSINFO.Network++; + break; + + case LOCAL: + SYSINFO.Local++; + break; + } + + rewind(pCallerLog); + fwrite(&SYSINFO, sizeof(SYSINFO), 1, pCallerLog); + + fclose(pCallerLog); + } + free(sDataFile); + return 1; +} + + + +int ChkFiles() +{ + FILE *pCallerLog, *pUsersFile; + char *sDataFile; + time_t Now; + char *temp; + + sDataFile = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(sDataFile, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + + /* + * Check if users.data exists, if not create a new one. + */ + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if((pUsersFile = fopen(temp,"rb")) == NULL) { + if((pUsersFile = fopen(temp,"wb")) == NULL) { + WriteError("$Can't create %s", temp); + ExitClient(1); + } else { + usrconfighdr.hdrsize = sizeof(usrconfighdr); + usrconfighdr.recsize = sizeof(usrconfig); + fwrite(&usrconfighdr, sizeof(usrconfighdr), 1, pUsersFile); + fclose(pUsersFile); + } + } + + /* + * Check if sysinfo.data exists, if not, create a new one. + */ + if((pCallerLog = fopen(sDataFile, "rb")) == NULL) { + if((pCallerLog = fopen(sDataFile, "wb")) == NULL) + WriteError("$ChkFiles: Can't create %s", sDataFile); + else { + memset((char *)&SYSINFO, 0, sizeof(SYSINFO)); + time(&Now); + SYSINFO.StartDate = Now; + + rewind(pCallerLog); + fwrite(&SYSINFO, sizeof(SYSINFO), 1, pCallerLog); + fclose(pCallerLog); + } + } + free(temp); + free(sDataFile); + return 1; +} + + + +void DisplayLogo() +{ + FILE *pLogo; + char *sString, *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + sString = calloc(81, sizeof(char)); + + sprintf(temp, "%s/%s", CFG.bbs_txtfiles, CFG.welcome_logo); + if((pLogo = fopen(temp,"rb")) == NULL) + WriteError("$DisplayLogo: Can't open %s", temp); + else { + while( fgets(sString,80,pLogo) != NULL) + printf("%s", sString); + fclose(pLogo); + } + free(sString); + free(temp); +} + + + +/* + * Update a variable in the exitinfo file. + */ +void Setup(char *Option, char *variable) +{ + ReadExitinfo(); + strcpy(Option, variable); + WriteExitinfo(); +} + + + +void GetLastCallers() +{ + FILE *pGLC; + char *sFileName; + char sFileDate[9]; + char sDate[9]; + struct stat statfile; + + /* + * First check if we passed midnight, in that case we + * create a fresh file. + */ + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/lastcall.data", getenv("MBSE_ROOT")); + stat(sFileName, &statfile); + + sprintf(sFileDate,"%s", StrDateDMY(statfile.st_mtime)); + sprintf(sDate,"%s", (char *) GetDateDMY()); + + if ((strcmp(sDate,sFileDate)) != 0) { + unlink(sFileName); + Syslog('+', "Erased old lastcall.data"); + } + + /* + * Check if file exists, if not create the file and + * write the fileheader. + */ + if ((pGLC = fopen(sFileName, "r")) == NULL) { + if ((pGLC = fopen(sFileName, "w")) != NULL) { + LCALLhdr.hdrsize = sizeof(LCALLhdr); + LCALLhdr.recsize = sizeof(LCALL); + fwrite(&LCALLhdr, sizeof(LCALLhdr), 1, pGLC); + Syslog('+', "Created new lastcall.data"); + } + fclose(pGLC); + } + + if(( pGLC = fopen(sFileName,"a+")) == NULL) { + WriteError("$Can't open %s", sFileName); + return; + } else { + ReadExitinfo(); + memset(&LCALL, 0, sizeof(LCALL)); + sprintf(LCALL.UserName,"%s", exitinfo.sUserName); + sprintf(LCALL.Handle,"%s", exitinfo.sHandle); + sprintf(LCALL.TimeOn,"%s", (char *) GetLocalHM()); + sprintf(LCALL.Device,"%s", pTTY); + LCALL.SecLevel = exitinfo.Security.level; + LCALL.Calls = exitinfo.iTotalCalls; + sprintf(LCALL.Speed, "%s", ttyinfo.speed); + + /* If true then set hidden so it doesn't display in lastcallers function */ + LCALL.Hidden = exitinfo.Hidden; + + sprintf(LCALL.Location,"%s", exitinfo.sLocation); + + rewind(pGLC); /* ???????????? */ + fwrite(&LCALL, sizeof(LCALL), 1, pGLC); + fclose(pGLC); + } + free(sFileName); +} + + + +/* Gets Date for GetLastCallers(), returns DD:Mmm */ +char *GLCdate() +{ + static char GLcdate[15]; + + time(&Time_Now); + l_date = localtime(&Time_Now); + sprintf(GLcdate,"%02d-", l_date->tm_mday); + + strcat(GLcdate,GetMonth(l_date->tm_mon+1)); + return(GLcdate); +} + + + +/* + * Display last callers screen. + */ +void LastCallers(char *OpData) +{ + FILE *pLC; + int LineCount = 5; + int count = 0; + char *sFileName; + char *Heading; + char *Underline; + int i, x; + struct lastcallers lcall; + struct lastcallershdr lcallhdr; + + sFileName = calloc(PATH_MAX, sizeof(char)); + Heading = calloc(81, sizeof(char)); + Underline = calloc(81, sizeof(char)); + + clear(); + + sprintf(sFileName,"%s/etc/lastcall.data", getenv("MBSE_ROOT")); + if((pLC = fopen(sFileName,"r")) == NULL) + WriteError("$LastCallers: Can't open %s", sFileName); + else { + fread(&lcallhdr, sizeof(lcallhdr), 1, pLC); + colour(15, 0); + /* Todays callers to */ + sprintf(Heading, "%s%s", (char *) Language(84), CFG.bbs_name); + Center(Heading); + + x = strlen(Heading); + + for(i = 0; i < x; i++) + sprintf(Underline, "%s%c", Underline, exitinfo.GraphMode ? 196 : 45); + + colour(12, 0); + Center(Underline); + + printf("\n"); + + /* # User Name Device timeOn Calls Location */ + pout(10, 0, (char *) Language(85)); + Enter(1); + + colour(2, 0); + fLine(79); + + while (fread(&lcall, lcallhdr.recsize, 1, pLC) == 1) { + if(!lcall.Hidden) { + count++; + + colour(15,0); + printf("%-5d", count); + + colour(11, 0); + if((strcmp(OpData, "/H")) == 0) { + if((strcmp(lcall.Handle, "") != 0 && *(lcall.Handle) != ' ')) + printf("%-20s", lcall.Handle); + else + printf("%-20s", lcall.UserName); + } else + printf("%-20s", lcall.UserName); + + colour(9, 0); + printf("%-8s", lcall.Device); + + colour(13, 0); + printf("%-8s", lcall.TimeOn); + + colour(14, 0); + printf("%-7d", lcall.Calls); + + colour(12, 0); + printf("%-32s\n", lcall.Location); + + LineCount++; + if (LineCount == exitinfo.iScreenLen) { + Pause(); + LineCount = 0; + } + } /* End of check if user is sysop */ + } + + colour(2, 0); + fLine(79); + + fclose(pLC); + printf("\n"); + Pause(); + } + free(sFileName); + free(Heading); + free(Underline); +} + + + +/* + * Check for a personal message, this will go via mbsed. If there + * is a message, it will be displayed, else nothing happens. + */ +void Check_PM(void) +{ + static char buf[128]; + char resp[128]; + + sprintf(buf, "CIPM:1,%d;", mypid); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:0;", 6) == 0) + return; + + strcpy(resp, strtok(buf, ":")); + strcpy(resp, strtok(NULL, ",")); + colour(CYAN, BLACK); + /* ** Message ** from */ + printf("\n\n\007%s %s:\n", (char *)Language(434), strtok(NULL, ",")); + printf("%s\n", strtok(NULL, ";")); + Pause(); + } +} + + + diff --git a/mbsebbs/misc.h b/mbsebbs/misc.h new file mode 100644 index 00000000..1f5adb4a --- /dev/null +++ b/mbsebbs/misc.h @@ -0,0 +1,15 @@ +#ifndef _MISC_H +#define _MISC_H + +void Setup(char *, char *); /* This function replaces a string in the users file */ +int GetLastUser(void); +void LastCallers(char *); +void GetLastCallers(void); +char *GLCdate(void); /* Returns current date DD-Mmm */ +void DisplayLogo(void); +int ChkFiles(void); +int MoreFile(char *); +void Check_PM(void); /* Check for personal message */ + +#endif + diff --git a/mbsebbs/msgutil.c b/mbsebbs/msgutil.c new file mode 100644 index 00000000..7d513384 --- /dev/null +++ b/mbsebbs/msgutil.c @@ -0,0 +1,279 @@ +/***************************************************************************** + * + * File ..................: bbs/msgutil.c + * Purpose ...............: Utilities for message handling. + * Last modification date : 18-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "oneline.h" +#include "msgutil.h" + + + +int BaseWrite = FALSE; + +static char *wdays[]={(char *)"Sun",(char *)"Mon",(char *)"Tue",(char *)"Wed", + (char *)"Thu",(char *)"Fri",(char *)"Sat"}; + +static char *months[]={(char *)"Jan",(char *)"Feb",(char *)"Mar", + (char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep", + (char *)"Oct",(char *)"Nov",(char *)"Dec"}; + + + +char *rfcdate(time_t now) +{ + static char buf[40]; + struct tm ptm, gtm; + char sign; + int hr, min; + long offset; + + if (!now) + time(&now); + ptm = *localtime(&now); + + /* + * To get the timezone, compare localtime with GMT. + */ + gtm = *gmtime(&now); + + /* + * Assume we are never more than 24 hours away. + */ + offset = gtm.tm_yday - ptm.tm_yday; + if (offset > 1) + offset = -24; + else if (offset < -1) + offset = 24; + else + offset *= 24; + + /* + * Scale in the hours and minutes; ignore seconds. + */ + offset += gtm.tm_hour - ptm.tm_hour; + offset *= 60; + offset += gtm.tm_min - ptm.tm_min; + + if (offset <= 0) + { + sign='+'; + offset=-offset; + } + else sign='-'; + hr=offset/60L; + min=offset%60L; + + sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d", + wdays[gtm.tm_wday],gtm.tm_mday,months[gtm.tm_mon], + gtm.tm_year+1900,gtm.tm_hour,gtm.tm_min,gtm.tm_sec, + sign,hr,min); + return(buf); +} + + + +/* + * Open specified message base for read or write. + */ +int Open_Msgbase(char *Base, int Mode) +{ + BaseWrite = FALSE; + + if (!Msg_Open(Base)) + return FALSE; + + if (Mode != 'w') + return TRUE; + + if (!Msg_Lock(30L)) { + Msg_Close(); + return FALSE; + } + + BaseWrite = TRUE; + return TRUE; +} + + + +/* + * Close current messagebase. + */ +void Close_Msgbase() +{ + if (BaseWrite) { + Msg_UnLock(); + BaseWrite = FALSE; + } + Msg_Close(); +} + + + +void Add_Headkludges(faddr *dest, int IsReply) +{ + char *temp, *temp2; + unsigned long crc = -1; + time_t tt; + int i; + faddr *Node; + + temp = calloc(128, sizeof(char)); + + switch (msgs.Type) { + case LOCALMAIL: Msg.Localmail = TRUE; + break; + + case NETMAIL: Msg.Netmail = TRUE; + sprintf(Msg.FromAddress, "%s", aka2str(msgs.Aka)); + sprintf(Msg.ToAddress, "%s", ascfnode(dest, 0x1f)); + + if (msgs.Aka.point) { + sprintf(temp, "\001FMPT %d", msgs.Aka.point); + MsgText_Add2(temp); + } + + if (dest->point) { + sprintf(temp, "\001TOPT %d", dest->point); + MsgText_Add2(temp); + } + + sprintf(temp, "\001INTL %d:%d/%d %d:%d/%d", dest->zone, dest->net, dest->node, msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node); + MsgText_Add2(temp); + + break; + + case ECHOMAIL: Msg.Echomail = TRUE; + sprintf(Msg.FromAddress, "%s", aka2str(msgs.Aka)); + break; + + case NEWS: /* + * Header style is the same as GoldED does. + */ + Msg.News = TRUE; + sprintf(temp, "\001Date: %s", rfcdate(Msg.Written)); + MsgText_Add2(temp); + Node = fido2faddr(msgs.Aka); + temp2 = xstrcpy(Msg.From); + for (i = 0; i < strlen(temp2); i++) + if (temp2[i] == ' ') + temp2[i] = '_'; + sprintf(temp, "\001From: %s@%s (%s)", temp2, ascinode(Node, 0x2f), Msg.From); + MsgText_Add2(temp); + sprintf(temp, "\001Subject: %s", Msg.Subject); + MsgText_Add2(temp); + sprintf(temp, "\001Sender: %s@%s (%s)", temp2, ascinode(Node, 0x2f), Msg.From); + MsgText_Add2(temp); + free(temp2); + tidy_faddr(Node); + MsgText_Add2((char *)"\001To: All"); + MsgText_Add2((char *)"\001MIME-Version: 1.0"); + MsgText_Add2((char *)"\001Content-Type: text/plain"); + MsgText_Add2((char *)"\001Content-Transfer-Encoding: 8bit"); + sprintf(temp, "\001X-Mailreader: MBSE BBS %s", VERSION); + MsgText_Add2(temp); + break; + } + + sprintf(temp, "\001CHRS: %s", getchrs(msgs.Ftncode)); + MsgText_Add2(temp); + sprintf(temp, "\001MSGID: %s %08lx", aka2str(msgs.Aka), sequencer()); + MsgText_Add2(temp); + Msg.MsgIdCRC = upd_crc32(temp, crc, strlen(temp)); + + if (IsReply) { + sprintf(temp, "\001REPLY: %s", Msg.Replyid); + MsgText_Add2(temp); + crc = -1; + Msg.ReplyCRC = upd_crc32(temp, crc, strlen(temp)); + } else + Msg.ReplyCRC = 0xffffffff; + + sprintf(temp, "\001PID: MBSE-BBS %s", VERSION); + MsgText_Add2(temp); + (void)time(&tt); + sprintf(temp, "\001TZUTC: %s", gmtoffset(tt)); + MsgText_Add2(temp); + free(temp); +} + + + +/* + * Add bottom message kludges. The flag Quote is false if this is called + * from Offline Reader, the user then may or may have not added a quote. + */ +void Add_Footkludges(int Quote) +{ + char *temp; + char *aka; + + temp = calloc(128, sizeof(char)); + aka = calloc(32, sizeof(char)); + + if (msgs.Quotes && Quote) { + Syslog('m', " Add quote"); + MsgText_Add2((char *)""); + sprintf(temp, "... %s", Oneliner_Get()); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + } + + sprintf(temp, "--- MBSE BBS v%s (Linux)", VERSION); + MsgText_Add2(temp); + + if (msgs.Type == ECHOMAIL) { + /* RANDOM ORIGIN LINES IMPLEMENTEREN */ + if (msgs.Aka.point) + sprintf(aka, "(%d:%d/%d.%d)", msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node, msgs.Aka.point); + else + sprintf(aka, "(%d:%d/%d)", msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node); + + if (strlen(msgs.Origin)) + sprintf(temp, " * Origin: %s %s", msgs.Origin, aka); + else + sprintf(temp, " * Origin: %s %s", CFG.origin, aka); + MsgText_Add2(temp); + } + + free(aka); + free(temp); +} + + + diff --git a/mbsebbs/msgutil.h b/mbsebbs/msgutil.h new file mode 100644 index 00000000..7d4143d4 --- /dev/null +++ b/mbsebbs/msgutil.h @@ -0,0 +1,14 @@ +#ifndef _MSGUTIL_H +#define _MSGUTIL_H + + +char *rfcdate(time_t); /* Create RFC style date */ +int Open_Msgbase(char *, int); /* Open msgbase for read/write */ +void Close_Msgbase(void); /* Close msgbase */ +void Add_Headkludges(faddr *, int); /* Header part of kludges */ +void Add_Footkludges(int); /* Footer part of kludges */ +void Sema_Mailout(void); /* Set mailout semafore */ + + +#endif + diff --git a/mbsebbs/myname.c b/mbsebbs/myname.c new file mode 100644 index 00000000..8c9e4120 --- /dev/null +++ b/mbsebbs/myname.c @@ -0,0 +1,72 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/myname.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 25-Jul-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * myname.c - determine the current username and get the passwd entry + * + * Copyright (C) 1996 Marek Michalkiewicz + * + * This code may be freely used, modified and distributed for any purpose. + * There is no warranty, if it breaks you have to keep both pieces, etc. + * If you improve it, please send me your changes. Thanks! + */ + +#include "../config.h" +#include +#include +#include + + +struct passwd *get_my_pwent(void) +{ + struct passwd *pw; + const char *cp = getlogin(); + uid_t ruid = getuid(); + + /* + * Try getlogin() first - if it fails or returns a non-existent + * username, or a username which doesn't match the real UID, fall + * back to getpwuid(getuid()). This should work reasonably with + * usernames longer than the utmp limit (8 characters), as well as + * shared UIDs - but not both at the same time... + * + * XXX - when running from su, will return the current user (not + * the original user, like getlogin() does). Does this matter? + */ + if (cp && *cp && (pw = getpwnam(cp)) && pw->pw_uid == ruid) + return pw; + + return getpwuid(ruid); +} + + diff --git a/mbsebbs/myname.h b/mbsebbs/myname.h new file mode 100644 index 00000000..8e4ca5aa --- /dev/null +++ b/mbsebbs/myname.h @@ -0,0 +1,7 @@ +#ifndef _MYNAME_H +#define _MYNAME_H + +struct passwd *get_my_pwent(void); + +#endif + diff --git a/mbsebbs/newuser.c b/mbsebbs/newuser.c new file mode 100644 index 00000000..c4b8cd39 --- /dev/null +++ b/mbsebbs/newuser.c @@ -0,0 +1,518 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/newuser.c + * Purpose ...............: New User login under Unix, creates both + * BBS and unix accounts. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "funcs4.h" +#include "pwcheck.h" +#include "newuser.h" +#include "language.h" +#include "timeout.h" +#include "change.h" +#include "bye.h" + + +extern int do_quiet; /* No logging to the screen */ +extern pid_t mypid; /* Pid of this program */ +char UnixName[9]; /* Unix Name */ +extern int ieLogin; /* IEMSI Login Successfull */ +extern int ieRows; /* Rows on screen */ +extern int ieHOT; /* Use Hotkeys */ +extern char *ieHandle; /* Users Handle */ +extern char *ieLocation; /* Users Location */ +extern char *Passwd; /* Plain password */ + + +int newuser(char *FullName) +{ + FILE *pUsrConfig; + int i, x, Found, iLang, recno = 0; + unsigned long crc; + char temp[PATH_MAX]; + char *temp1, *temp2; + char *Phone1, *Phone2; + long offset; + struct userrec us; + + IsDoing("New user login"); + Syslog('+', "Newuser registration"); + clear(); + iLang = Chg_Language(TRUE); + + Enter(1); + /* MBSE BBS - NEW USER REGISTRATION */ + language(3, 0, 37); + Enter(2); + + Syslog('+', "Name entered: %s", FullName); + + memset(&usrconfig, 0, sizeof(usrconfig)); + memset(&exitinfo, 0, sizeof(exitinfo)); + + temp1 = calloc(81, sizeof(char)); + temp2 = calloc(81, sizeof(char)); + Phone1 = calloc(81, sizeof(char)); + Phone2 = calloc(81, sizeof(char)); + + usrconfig.iLanguage = iLang; + usrconfig.FsMsged = TRUE; + + while (TRUE) { + do { + alarm_on(); + Enter(1); + /* Use this name: */ + language(14, 0, 38); + printf("%s [Y/n]? ", FullName); + fflush(stdout); + fflush(stdin); + GetstrC(temp, 80); + + if ((strcasecmp(temp, "y") == 0) || (strcmp(temp, "") == 0)) + sprintf(temp, "%s", FullName); + else { + do { + Syslog('+', "User chose to use a different name"); + Enter(1); + /* Please enter your First and Last name: */ + language(3, 0, 0); + fflush(stdout); + alarm_on(); + Getname(temp, 35); + if (CheckName(temp)) + printf("\n%s\n", (char *) Language(149)); + /* + * Do a check to see if name exists + */ + } while ((CheckName(temp) || strchr(temp, ' ') == NULL)); + } + } while (BadNames(temp) || *(temp) == '\n'); + + /* + * Used to get users full name for other functions + */ + strcpy(FullName, tlcap(temp)); + UserCity(mypid, FullName, (char *)"Unknown"); + + while (1) { + Enter(1); + /* Please enter your BBS password, this can be the same as the unix password */ + printf("%s\n\n", (char *) Language(388)); + /* Please enter new password : */ + language(11, 0, 39); + fflush(stdout); + alarm_on(); + Getpass(temp1); + if((x = strlen(temp1)) >= CFG.password_length) { + Enter(1); + /* Please enter password again : */ + language(11, 0, 40); + fflush(stdout); + alarm_on(); + Getpass(temp2); + if((i = strcmp(temp1,temp2)) != 0) { + Enter(2); + /* Your passwords do not match! Try again. */ + language(12, 0, 41); + Enter(1); + } else { + crc = StringCRC32(tu(temp1)); + break; + } + } else { + Enter(2); + /* Your password must contain at least */ + language(12, 0, 42); + printf("%d ", CFG.password_length); + /* characters! Try again. */ + language(15, 0, 43); + Enter(1); + } + } + memset(Passwd, 0, 16); + sprintf(Passwd, "%s", temp2); + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + sprintf(usrconfig.Password, "%s", temp2); + usrconfig.iPassword = crc; + alarm_on(); + sprintf(UnixName, "%s", (char *) NameCreate(NameGen(FullName), FullName, temp2)); + break; + } + + strcpy(usrconfig.sUserName, FullName); + strcpy(usrconfig.Name, UnixName); + Time_Now = time(NULL); + l_date = localtime(&Time_Now); + ltime = time(NULL); + + if(CFG.iAnsi) { + Enter(2); + /* Do you want ANSI and graphics mode [Y/n]: */ + language(7, 0, 44); + + alarm_on(); + i = toupper(getchar()); + + if (i == Keystroke(44, 0) || i == '\n') + usrconfig.GraphMode = TRUE; + else + usrconfig.GraphMode = FALSE; + } else { + usrconfig.GraphMode = TRUE; /* Default set it to ANSI */ + Enter(1); + } + exitinfo.GraphMode = usrconfig.GraphMode; + TermInit(exitinfo.GraphMode); + + if (CFG.iVoicePhone) { + while (1) { + Enter(1); + /* Please enter you Voice Number */ + language(10, 0, 45); + Enter(1); + + pout(10, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + GetPhone(temp, 16); + + if (strlen(temp) < 6) { + Enter(1); + language(12, 0, 47); + Enter(1); + } else { + strcpy(usrconfig.sVoicePhone, temp); + strcpy(Phone1, temp); + break; + } + } + } /* End of first if statement */ + + if (CFG.iDataPhone) { + while (TRUE) { + Enter(1); + /* Please enter you Data Number */ + language(10, 0, 48); + Enter(1); + + pout(10, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + alarm_on(); + GetPhone(temp, 16); + + /* + * If no dataphone, copy voicephone. + */ + if (strcmp(temp, "") == 0) { + strcpy(usrconfig.sDataPhone, usrconfig.sVoicePhone); + break; + } + + if( strlen(temp) < 6) { + Enter(1); + /* Please enter a proper phone number */ + language(12, 0, 47); + Enter(1); + } else { + strcpy(usrconfig.sDataPhone, temp); + strcpy(Phone2, temp); + break; + } + } + } /* End of if Statement */ + + if(!CFG.iDataPhone) + printf("\n"); + + if (ieLogin && (strlen(ieLocation) >= CFG.CityLen) && (strlen(ieLocation) < 24)) { + strcpy(usrconfig.sLocation, ieLocation); + } else { + while (TRUE) { + Enter(1); + /* Enter your location */ + pout(14, 0, (char *) Language(49)); + colour(CFG.InputColourF, CFG.InputColourB); + alarm_on(); + if (CFG.iCapLocation) { /* Cap Location is turn on, Capitalise first letter */ + fflush(stdout); + GetnameNE(temp, 24); + } else + GetstrC(temp, 80); + + if( strlen(temp) < CFG.CityLen) { + Enter(1); + /* Please enter a longer location */ + language(12, 0, 50); + Enter(1); + printf("%s%d)", (char *) Language(74), CFG.CityLen); + Enter(1); + } else { + strcpy(usrconfig.sLocation, temp); + UserCity(mypid, FullName, temp); + break; + } + } + } + + if(CFG.iHandle) { + Enter(1); + /* Enter a handle (Enter to Quit): */ + pout(12, 0, (char *) Language(412)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + Getname(temp, 34); + + if(strcmp(temp, "") == 0) + strcpy(usrconfig.sHandle, ""); + else + strcpy(usrconfig.sHandle, temp); + } + + /* + * Note, the users database always contains the english sex + */ + if(CFG.iSex) { + while (TRUE) { + Enter(1); + /* What is your sex? (M)ale or (F)emale: */ + language(9, 0, 51); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(51, 0)) { + /* Male */ + sprintf(usrconfig.sSex, "Male"); + pout(CFG.InputColourF, CFG.InputColourB, (char *) Language(52)); + Enter(1); + break; + } else + if (i == Keystroke(51, 1)) { + /* Female */ + sprintf(usrconfig.sSex, "Female"); + pout(CFG.InputColourF, CFG.InputColourB, (char *) Language(53)); + Enter(1); + break; + } else { + Enter(2); + /* Please answer M or F */ + language(12, 0, 54); + Enter(1); + } + } + } else /* End of if Statement */ + sprintf(usrconfig.sSex, "Unknown"); /* If set off, set to Unknown */ + + while (TRUE) { + Enter(1); + /* Please enter your Date of Birth DD-MM-YYYY: */ + pout(3, 0, (char *) Language(56)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + GetDate(temp, 10); + + sprintf(temp1, "%c%c%c%c", temp[6], temp[7], temp[8], temp[9]); + sprintf(temp2, "%02d", l_date->tm_year); + iLang = atoi(temp2) + 1900; + sprintf(temp2, "%04d", iLang); + + Syslog('-', "DOB: test %s %s", temp1, temp2); + + if ((strcmp(temp1,temp2)) == 0) { + Enter(1); + /* Sorry you entered this year by mistake. */ + pout(12, 0, (char *) Language(57)); + Enter(1); + } else + if((strlen(temp)) != 10) { + Enter(1); + /* Please enter the correct date format */ + pout(12, 0, (char *) Language(58)); + Enter(1); + } else { + strcpy(usrconfig.sDateOfBirth,temp); + break; + } + } + + usrconfig.tFirstLoginDate = ltime; /* Set first login date to current date */ + usrconfig.tLastLoginDate = (time_t)0; /* To force setting new limits */ + strcpy(usrconfig.sExpiryDate,"00-00-0000"); + usrconfig.ExpirySec = CFG.newuser_access; + usrconfig.Security = CFG.newuser_access; + usrconfig.Email = CFG.GiveEmail; + + if (ieLogin) + usrconfig.HotKeys = ieHOT; + else { + if (CFG.iHotkeys) { + while (TRUE) { + Enter(1); + /* Would you like hot-keyed menus [Y/n]: */ + pout(12, 0, (char *) Language(62)); + colour(CFG.InputColourF, CFG.InputColourB); + alarm_on(); + GetstrC(temp, 8); + + if ((toupper(temp[0]) == Keystroke(62, 0)) || (strcmp(temp,"") == 0)) { + usrconfig.HotKeys = TRUE; + break; + } + if (toupper(temp[0]) == Keystroke(62, 1)) { + usrconfig.HotKeys = FALSE; + break; + } else { + /* Please answer Y or N */ + pout(15, 0, (char *) Language(63)); + } + } + } /* End of if Statement */ + else + usrconfig.HotKeys = TRUE; /* Default set it to Hotkeys */ + } + + usrconfig.iTimeLeft = 20; /* Set Timeleft in users file to 20 */ + + Enter(1); + if (ieLogin) + usrconfig.iScreenLen = ieRows; + else { + /* Please enter your Screen Length [24]: */ + pout(13, 0, (char *) Language(64)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + Getnum(temp, 3); + + if(strlen(temp) == 0) + usrconfig.iScreenLen = 24; + else + usrconfig.iScreenLen = atoi(temp); + } + + alarm_on(); + + usrconfig.tLastPwdChange = ltime; /* Days Since Last Password Change */ + usrconfig.iLastFileArea = 1; + + sprintf(usrconfig.sProtocol, "%s", (char *) Language(65)); + usrconfig.DoNotDisturb = FALSE; + usrconfig.MailScan = TRUE; + usrconfig.ieFILE = TRUE; + usrconfig.ieNEWS = TRUE; + usrconfig.Cls = TRUE; + usrconfig.More = TRUE; + usrconfig.ieASCII8 = TRUE; + + /* + * Search a free slot in the users datafile + */ + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp, "r+")) == NULL) { + WriteError("Can't open file: %s", temp); + ExitClient(1); + } + + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + offset = ftell(pUsrConfig); + Found = FALSE; + + while ((fread(&us, usrconfighdr.recsize, 1, pUsrConfig) == 1) && (!Found)) { + if (us.sUserName[0] == '\0') { + Found = TRUE; + } else { + offset = ftell(pUsrConfig); + recno++; + } + } + + if (Found) + fseek(pUsrConfig, offset, SEEK_SET); + else + fseek(pUsrConfig, 0, SEEK_END); + + fwrite(&usrconfig, sizeof(usrconfig), 1, pUsrConfig); + fclose(pUsrConfig); + + Enter(2); + /* Your user account has been created: */ + pout(14, 0, (char *) Language(67)); + Enter(2); + + /* Login Name : */ + pout(9, 0, (char *) Language(68)); + colour(11, 0); + printf("%s (%s)\n", FullName, UnixName); + /* Password : */ + pout(9, 0, (char *) Language(69)); + pout(3, 0, (char *)"<"); + /* not displayed */ + pout(15, 0, (char *) Language(70)); + pout(3, 0, (char *)">\n\n"); + fflush(stdout); + fflush(stdin); + + if(CFG.iVoicePhone) { + if(TelephoneScan(Phone1, FullName)) + Syslog('!', "Duplicate phone numbers found"); + } + + if(CFG.iDataPhone) { + if(TelephoneScan(Phone2, FullName)) + Syslog('!', "Duplicate phone numbers found"); + } + + free(temp1); + free(temp2); + free(Phone1); + free(Phone2); + + Syslog('+', "Completed new-user procedure"); + /* New user registration completed. */ + pout(10, 0, (char *) Language(71)); + Enter(2); + alarm_on(); + Pause(); + alarm_off(); + printf("\n"); + return recno; +} + + diff --git a/mbsebbs/newuser.h b/mbsebbs/newuser.h new file mode 100644 index 00000000..36b2cbe8 --- /dev/null +++ b/mbsebbs/newuser.h @@ -0,0 +1,9 @@ +#ifndef _NEWUSER_H +#define _NEWUSER_H + + +int newuser(char *); /* Newuser function */ + + +#endif + diff --git a/mbsebbs/nextuser.c b/mbsebbs/nextuser.c new file mode 100644 index 00000000..2b189dab --- /dev/null +++ b/mbsebbs/nextuser.c @@ -0,0 +1,360 @@ +/***************************************************************************** + * + * File ..................: bbs/nextuser.c + * Purpose ...............: Message to next User door + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/ansi.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "nextuser.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "timeout.h" + + +int iLoop, iLine = 1; + +char sFrom[81]; +char To[81]; +char Subject[81]; + +int finish(void); +void addlines(void); + +char *sLiNE[11]; + + + +void nextuser(void) +{ + int i; + + for (i = 0; i < 11; i++) + *(sLiNE + i) = (char *) calloc(81, sizeof(char)); + + addlines(); + while (TRUE) { + if (finish() == TRUE) + break; + } + + for (i = 0; i < 11; i++) + free(*(sLiNE + i)); +} + + + +void addlines(void) +{ + iLine = 1; + clear(); + + /* Message to Nextuser Door */ + pout(15, 0, (char *) Language(107)); + Enter(2); + + Syslog('+', "%s ran Nextuser Door", exitinfo.sUserName); + + /* The FROM, TO and SUBJECT fields are optional. */ + pout(14, 0, (char *) Language(108)); + Enter(1); + + Enter(1); + /* From: */ + pout(12, 0, (char *) Language(109)); + colour(9, 0); + fflush(stdout); + Getname(sFrom, 50); + + /* To: */ + pout(12, 0, (char *) Language(110)); + colour(9, 0); + fflush(stdout); + Getname(To, 50); + + /* Subject: */ + pout(12, 0, (char *) Language(111)); + colour(9, 0); + fflush(stdout); + GetstrC(Subject, 80); + + Enter(2); + /* Type up to 10 lines 74 Characters per line */ + pout(10 , 0, (char *) Language(112)); + Enter(1); + + colour(14, 0); + printf(" Õ"); + for(iLoop = 0; iLoop <= 75; iLoop++) + printf("Í"); + printf("¸"); + + while (1) { + colour(12, 0); + printf("%d: ", iLine); + colour(9, 0); + fflush(stdout); + GetstrC(*(sLiNE + iLine), 75); + + if ((strcmp(*(sLiNE + iLine), "")) == 0) + return; + + iLine++; + if(iLine >= 11) + break; + } + + pout(14, 0, (char *)" Ô"); + for(iLoop = 0; iLoop <= 75; iLoop++) + printf("Í"); + printf("¾"); +} + + + +/* Save Abort File */ +int finish(void) +{ + FILE *pTextFileANS, *pTextFileASC; + int iStrLen, i, x, NLChk = FALSE; + char *temp, *temp1; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + while (TRUE) { + Enter(1); + poutCR(15, 0, (char *) Language(113)); + Enter(1); + /* (L)ist, (R)eplace text, (E)dit line, (A)bort, (S)ave */ + pout(15, 1, (char *) Language(114)); + Enter(2); + + /* Select: */ + pout(15, 0, (char *) Language(115)); + + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(114, 3)) { + /* Aborting... */ + pout(15, 0, (char *) Language(116)); + Enter(1); + Enter(1); + pout(15, 0, (char *) Language(117)); + poutCR(15, 0, CFG.bbs_name); + sleep(2); + Syslog('+', "User aborted message and exited door"); + free(temp); + free(temp1); + return TRUE; + } else + + if (i == Keystroke(114, 2)) { + /* Edit which line: */ + printf("\n %s", (char *) Language(118)); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) + break; + + i = atoi(temp); + if( i > iLine - 1) { + /* Line does not exist. */ + printf("%s\n", (char *) Language(119)); + break; + } + x = strlen(sLiNE[i]); + printf("%d : %s", i, *(sLiNE + i)); + fflush(stdout); + GetstrP(sLiNE[i],74, x); + } else + + if (i == Keystroke(114, 0)) { + colour(14, 0); + printf("\n\n Õ"); + for (iLoop = 0; iLoop <= 75; iLoop++) + printf("Í"); + printf("¸"); + + for(i = 1; i < iLine; i++) { + colour(12, 0); + printf("%d: ", i); + colour(9, 0); + printf("%s\n", *(sLiNE + i)); + } + + colour(14, 0); + printf(" Ô"); + for (iLoop = 0; iLoop <= 75; iLoop++) + printf("Í"); + printf("¾\n"); + } else + + if (i == Keystroke(114, 4)) { + /* Open TextFile for Writing NextUser Info */ + sprintf(temp, "%s/%s.ans", CFG.bbs_txtfiles, CFG.sNuScreen); + sprintf(temp1, "%s/%s.ans.bak", CFG.bbs_txtfiles, CFG.sNuScreen); + rename(temp, temp1); + + if((pTextFileANS = fopen(temp, "w")) == NULL) { + perror(""); + WriteError("NextUser: Can't open file: %s", temp); + return TRUE; + } + + sprintf(temp, "%s/%s.asc", CFG.bbs_txtfiles, CFG.sNuScreen); + if(( pTextFileASC = fopen(temp, "w")) == NULL) { + perror(""); + WriteError("NextUser: Can't open file: %s", temp); + return TRUE; + } + + fprintf(pTextFileANS,"%s%s%s%s",ANSI_CLEAR,ANSI_NORMAL,ANSI_WHITE,ANSI_BOLD); + + if((iStrLen = strlen(sFrom)) > 1) { + fprintf(pTextFileANS,"%s\x1B[1;4HFrom:%s %s\n",ANSI_RED,ANSI_BLUE,sFrom); + fprintf(pTextFileASC,"\n From: %s\n", sFrom); + Syslog('+', " From: %s", sFrom); + NLChk = TRUE; + } + + if((iStrLen = strlen(To)) > 1) { + fprintf(pTextFileANS,"%s\x1B[2;6HTo:%s %s\n",ANSI_RED,ANSI_BLUE,To); + fprintf(pTextFileASC," To: %s\n", To); + Syslog('+', " To: %s", To); + NLChk = TRUE; + } + + if((iStrLen = strlen(Subject)) > 1) { + fprintf(pTextFileANS,"%sSubject:%s %s\n\n",ANSI_RED,ANSI_BLUE,Subject); + fprintf(pTextFileASC,"Subject: %s\n\n", Subject); + Syslog('+', "Subject: %s", Subject); + NLChk = TRUE; + } + + if(!NLChk) { + fprintf(pTextFileANS, "\n"); + fprintf(pTextFileASC, "\n"); + } + + fprintf(pTextFileANS,"%sÕ",ANSI_YELLOW); + for(iLoop = 0; iLoop <= 75; iLoop++) { + fprintf(pTextFileANS,"Í"); + fprintf(pTextFileASC,"="); + } + fprintf(pTextFileANS,"¸\n"); + fprintf(pTextFileASC,"\n"); + + for(i = 0; i < iLine; i++) { + if((iStrLen = strlen( *(sLiNE + i) )) > 0) { + fprintf(pTextFileANS," %s%s\n",ANSI_BLUE, *(sLiNE + i)); + fprintf(pTextFileASC," %s\n", *(sLiNE + i)); + } + } + + Enter(2); + pout(12, 0, (char *) Language(340)); + fprintf(pTextFileANS,"%sÔ",ANSI_YELLOW); + for(iLoop = 0; iLoop <= 75; iLoop++) { + fprintf(pTextFileANS,"Í"); + fprintf(pTextFileASC,"="); + } + fprintf(pTextFileANS,"¾\n"); + fprintf(pTextFileASC,"\n"); + + fprintf(pTextFileANS,"%s%s",ANSI_RED,CFG.sNuQuote); + fprintf(pTextFileASC,"%s", CFG.sNuQuote); + + fclose(pTextFileANS); + fclose(pTextFileASC); + colour(9, 0); + /* Returning to */ + printf("\n%s%s\n", (char *) Language(117), CFG.bbs_name); + + Syslog('+', "User Saved Nextuser message and exited door"); + free(temp); + free(temp1); + return TRUE; + } else + + if (i == Keystroke(114, 1)) { + /* Edit which line: */ + colour(15, 0); + printf("\n%s", (char *) Language(118)); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) + break; + + i = atoi(temp); + + if( i > iLine - 1) { + /* Line does not exist. */ + printf("\n%s", (char *) Language(119)); + break; + } + + Enter(1); + /* Line reads: */ + colour(15, 0); + poutCR(15, 0, (char *) Language(186)); + printf("%2d: %s\n", i, *(sLiNE + i)); + + Enter(1); + /* Text to replace: */ + pout(15, 0, (char *) Language(195)); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) + break; + + /* Replacement text: */ + pout(15, 0, (char *) Language(196)); + GetstrC(temp1, 80); + + if((strcmp(temp1, "")) == 0) + break; + + strreplace(*(sLiNE + i), temp, temp1); + } else + printf("\n"); + } + free(temp); + free(temp1); + return FALSE; +} + diff --git a/mbsebbs/nextuser.h b/mbsebbs/nextuser.h new file mode 100644 index 00000000..24903597 --- /dev/null +++ b/mbsebbs/nextuser.h @@ -0,0 +1,7 @@ +#ifndef _NEXTUSER_H +#define _NEXTUSER_H + +void nextuser(void); + +#endif + diff --git a/mbsebbs/offline.c b/mbsebbs/offline.c new file mode 100644 index 00000000..6d1581e1 --- /dev/null +++ b/mbsebbs/offline.c @@ -0,0 +1,2910 @@ +/***************************************************************************** + * + * File ..................: bbs/offline.c + * Purpose ...............: Offline Reader + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/mbse.h" +#include "../lib/records.h" +#ifndef BIG_ENDIAN +#define BIG_ENDIAN +#endif +#include "../lib/bluewave.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "mail.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "file.h" +#include "filesub.h" +#include "exitinfo.h" +#include "timeout.h" +#include "msgutil.h" +#include "pop3.h" +#include "offline.h" + + + +long Total, TotalPersonal, Current, Personal; +unsigned long TotalPack; +unsigned short BarWidth; +lastread LR; +static char TempStr[128]; +extern int do_mailout; + + +typedef struct _msg_high { + struct _msg_high *next; + unsigned long Area; + unsigned long LastMsg; + unsigned long Personal; +} msg_high; + + + +/* + * Internal prototypes. + */ +void AddArc(char *, char *); +void tidy_high(msg_high **); +void fill_high(msg_high **, unsigned long, unsigned long, unsigned long); +void UpdateLR(msg_high *, FILE *); +void Add_Kludges(fidoaddr, int, char *); +int OLR_Prescan(void); +void DrawBar(char *); +unsigned long BlueWave_PackArea(unsigned long, long); +void BlueWave_Fetch(void); +unsigned long QWK_PackArea(unsigned long, long); +void QWK_Fetch(void); +float IEEToMSBIN(float); +float MSBINToIEE(float); +char *StripSpaces(char *, int); +unsigned long ASCII_PackArea(unsigned long, long); + + + +/**************************************************************************** + * + * Global Functions + */ + + +void AddArc(char *Temp, char *Pktname) +{ + execute((char *)archiver.marc, Pktname, Temp, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); + unlink(Temp); + printf("."); + fflush(stdout); +} + + + +void tidy_high(msg_high **hdp) +{ + msg_high *tmp, *old; + + for (tmp = *hdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *hdp = NULL; +} + + + +/* + * Add an area to the array + */ +void fill_high(msg_high **hdp, unsigned long Area, unsigned long Last, unsigned long Pers) +{ + msg_high *tmp; + + Syslog('M', "fill_high Area %lu Msg %lu, Pers %lu", Area, Last, Pers); + + tmp = (msg_high *)malloc(sizeof(msg_high)); + tmp->next = *hdp; + tmp->Area = Area; + tmp->LastMsg = Last; + tmp->Personal = Pers; + *hdp = tmp; +} + + + +void UpdateLR(msg_high *mhl, FILE *mf) +{ + char *p; + msg_high *tmp; + + colour(14, 0); + /* Updating lastread pointer */ + printf("%s\n", (char *)Language(449)); + colour(13, 0); + + for (tmp = mhl; tmp; tmp = tmp->next) { + printf("."); + fflush(stdout); + fseek(mf, ((tmp->Area -1) * (msgshdr.recsize + msgshdr.syssize)) + msgshdr.hdrsize, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, mf); + if (Msg_Open(msgs.Base)) { + if (Msg_Lock(30L)) { + if (tmp->Personal) + Syslog('?', "Personal messages to update"); + + LR.UserID = grecno; + p = xstrcpy(exitinfo.sUserName); + if (Msg_GetLastRead(&LR) == TRUE) { + LR.LastReadMsg = tmp->LastMsg; + if (tmp->LastMsg > LR.HighReadMsg) + LR.HighReadMsg = tmp->LastMsg; + if (LR.HighReadMsg > Msg_Highest()) { + Syslog('?', "Highread was too high"); + LR.HighReadMsg = Msg_Highest(); + } + LR.UserCRC = StringCRC32(tl(p)); + if (!Msg_SetLastRead(LR)) + WriteError("Error update lastread"); + } else { + /* + * Append new lastread pointer + */ + LR.UserCRC = StringCRC32(tl(p)); + LR.UserID = grecno; + LR.LastReadMsg = tmp->LastMsg; + LR.HighReadMsg = tmp->LastMsg; + if (!Msg_NewLastRead(LR)) + WriteError("Can't append new lastread"); + } + free(p); + Msg_UnLock(); + } + Msg_Close(); + } + } +} + + + +/* + * Add message kludges at the start, append the message text and add + * trailing kludges, tearline and originline. + */ +void Add_Kludges(fidoaddr dest, int IsReply, char *fn) +{ + char *temp, *aka; + FILE *tp; + + temp = calloc(2048, sizeof(char)); + aka = calloc(81, sizeof(char)); + + Add_Headkludges(fido2faddr(dest), IsReply); + Syslog('m', "Kludges done, start textfile %s", fn); + + if ((tp = fopen(fn, "r")) != NULL) { + Msg_Write(tp); + fclose(tp); + } + + Syslog('m', "Add footer"); + Add_Footkludges(FALSE); + + Syslog('m', "Add message now"); + Msg_AddMsg(); + Syslog('m', "Msg added"); + + free(aka); + free(temp); +} + + + +/**************************************************************************** + * + * Offline Configuration + */ + + +/* + * Tag areas, called from menu. + */ +void OLR_TagArea() +{ + char *Msgname, *Tagname; + FILE *ma, *tf; + char *buf; + long total, Offset, Area; + int lines, input, ignore = FALSE, maxlines; + + WhosDoingWhat(OLR); + + Msgname = calloc(PATH_MAX, sizeof(char)); + Tagname = calloc(PATH_MAX, sizeof(char)); + buf = calloc(81, sizeof(char)); + + sprintf(Msgname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + sprintf(Tagname, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + + clear(); + colour(14, 0); + /* Tag Offline Reader message areas */ + printf("%s\n", (char *)Language(66)); + + do { + colour(15, 0); + /* Enter the name of the conference, or ? for a list: */ + printf("\n%s", (char *)Language(228)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(buf, 20); + + if (buf[0] == '?') { + maxlines = lines = exitinfo.iScreenLen - 1; + colour(11, 0); + /* Conference Area Msgs Description */ + printf("%s\n", (char *)Language(229)); + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + if ((tf = fopen(Tagname, "r")) != NULL) { + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (Msg_Open(msgs.Base)) { + total = Msg_Number(); + Msg_Close(); + } else + total = 0; + colour(3, 0); + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + (!olrtagrec.Tagged) && strlen(msgs.QWKname)) { + if ( (lines != 0) || (ignore) ) { + lines--; + printf("%-20.20s %-5ld %-5ld %s\n", msgs.QWKname, Area, total, msgs.Name); + } + if (lines == 0) { + fflush(stdin); + colour(15, 0); + /* More (Y/n/=) */ + printf("%s%c\x08", (char *) Language(61),Keystroke(61,0)); + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + printf("%c\r",input); + if ((input == Keystroke(61, 0)) || (input == '\r')) + lines = maxlines; + + if (input == Keystroke(61, 1)) { + break; + } + + if (input == Keystroke(61, 2)) + ignore = TRUE; + else + lines = maxlines; + colour(3, 0); + } + } + } + fclose(tf); + } + fclose(ma); + } + } else + if (buf[0] != '\0') { + if (atoi(buf) != 0) { + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Offset = msgshdr.hdrsize + ((atoi(buf)-1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(ma, Offset, SEEK_SET); + if (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname)) { + if ((tf = fopen(Tagname, "r+")) != NULL) { + fseek(tf, (atoi(buf)-1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + if (!olrtagrec.Tagged) { + olrtagrec.Tagged = TRUE; + fseek(tf, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, tf); + Syslog('+', "OLR Tagged %d %s", + atoi(buf), msgs.QWKname); + } + fclose(tf); + } + } + } + fclose(ma); + } + } else { + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + Area++; + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname)) { + if (strcasecmp(msgs.QWKname, buf) == 0) { + if ((tf = fopen(Tagname, "r+")) != NULL) { + fseek(tf, (Area-1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + if (!olrtagrec.Tagged) { + olrtagrec.Tagged = TRUE; + fseek(tf, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, tf); + Syslog('+', "OLR Tagged %d %s", + Area, msgs.QWKname); + } + fclose(tf); + } + } + } + } + fclose(ma); + } + } + } + + } while (buf[0] != '\0'); + + free(buf); + free(Tagname); + free(Msgname); +} + + + +/* + * Untag areas, called from menu. + */ +void OLR_UntagArea() +{ + char *Msgname, *Tagname, *buf; + FILE *ma, *tf; + long total, Offset, Area; + int lines, input, ignore = FALSE, maxlines; + + WhosDoingWhat(OLR); + + Msgname = calloc(PATH_MAX, sizeof(char)); + Tagname = calloc(PATH_MAX, sizeof(char)); + buf = calloc(81, sizeof(char)); + + sprintf(Msgname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + sprintf(Tagname, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + + clear(); + colour(14, 0); + /* Untag Offline Reader message areas */ + printf("%s\n", (char *)Language(256)); + + do { + colour(15, 0); + /* Enter the name of the conference, or ? for a list: */ + printf("\n%s", (char *)Language(228)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(buf, 20); + + if (buf[0] == '?') { + maxlines = lines = exitinfo.iScreenLen - 1; + colour(11, 0); + /* Conference Area Msgs Description */ + printf("%s\n", (char *)Language(229)); + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + if ((tf = fopen(Tagname, "r")) != NULL) { + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (Msg_Open(msgs.Base)) { + total = Msg_Number(); + Msg_Close(); + } else + total = 0; + colour(3, 0); + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + olrtagrec.Tagged && strlen(msgs.QWKname)) { + if ( (lines != 0) || (ignore) ) { + lines--; + printf("%-20.20s %-5ld %-5ld %s\n", msgs.QWKname, Area, total, msgs.Name); + } + if (lines == 0) { + fflush(stdin); + colour(15, 0); + /* More (Y/n/=) */ + printf("%s%c\x08", (char *) Language(61),Keystroke(61,0)); + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + printf("%c\r",input); + if ((input == Keystroke(61, 0)) || (input == '\r')) + lines = maxlines; + + if (input == Keystroke(61, 1)) { + break; + } + + if (input == Keystroke(61, 2)) + ignore = TRUE; + else + lines = maxlines; + colour(3, 0); + } + } + } + fclose(tf); + } + fclose(ma); + } + } else + if (buf[0] != '\0') { + if (atoi(buf) != 0) { + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Offset = msgshdr.hdrsize + ((atoi(buf)-1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(ma, Offset, SEEK_SET); + if (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname)) { + if ((tf = fopen(Tagname, "r+")) != NULL) { + fseek(tf, (atoi(buf)-1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + if (olrtagrec.Tagged) { + if (msgs.OLR_Forced) { + printf("Area cannot be switched off\n"); + } else { + olrtagrec.Tagged = FALSE; + fseek(tf, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, tf); + Syslog('+', "OLR Untagged %d %s", + atoi(buf), msgs.QWKname); + } + } + fclose(tf); + } + } + } + fclose(ma); + } + } else { + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + Area++; + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname)) { + if (strcasecmp(msgs.QWKname, buf) == 0) { + if ((tf = fopen(Tagname, "r+")) != NULL) { + fseek(tf, (Area-1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + if (olrtagrec.Tagged) { + if (msgs.OLR_Forced) { + printf("Area cannot be switched off\n"); + } else { + olrtagrec.Tagged = FALSE; + fseek(tf, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, tf); + Syslog('+', "OLR Untagged %d %s", + Area, msgs.QWKname); + } + } + fclose(tf); + } + } + } + } + fclose(ma); + } + } + } + + } while (buf[0] != '\0'); + + free(buf); + free(Tagname); + free(Msgname); +} + + + +void New_Hdr(void); +void New_Hdr() +{ + char *temp; + + temp = calloc(81, sizeof(char)); + clear(); + colour(14, 0); + /* New or deleted mail areas at */ + sprintf(temp, "%s%s", (char *) Language(364), CFG.bbs_name); + Center(temp); + free(temp); + printf("\n"); + colour(15, 1); + /* Area State Type Description */ + printf("%-79s\n", (char *) Language(365)); +} + + + +void New_Area(long); +void New_Area(long Area) +{ + colour(11, 0); + /* New */ + printf("%4ld %s", Area, (char *)Language(391)); + switch (msgs.Type) { + case LOCALMAIL: printf(Language(392)); /* Local */ + break; + case NETMAIL: printf(Language(393)); /* Netmail */ + break; + case ECHOMAIL: printf(Language(394)); /* Echomail */ + break; + case NEWS: printf(Language(395)); /* News */ + break; + } + printf("%s\n", msgs.Name); +} + + + +void Old_Area(long); +void Old_Area(long Area) +{ + colour(12, 0); + /* Del */ + printf("%4ld %s\n", Area, (char *)Language(397)); +} + + + +/* + * Sync tagged areas file. If CFG.NewAreas is on then we show the + * changed areas to the user. This one is called by user.c during login. + */ +void OLR_SyncTags() +{ + char *Tagname, *Msgname; + FILE *fp, *ma; + long Area; + int Changed = FALSE; + + Tagname = calloc(PATH_MAX, sizeof(char)); + Msgname = calloc(PATH_MAX, sizeof(char)); + sprintf(Tagname, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + sprintf(Msgname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(Tagname, "r+")) == NULL) { + + /* + * If the user has no .olrtagsfile yet, we silently create + * a new one. The user will not be notified of new areas + * of coarse. + */ + Syslog('m', "Creating %s", Tagname); + if ((fp = fopen(Tagname, "w")) != NULL) { + + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + memset(&olrtagrec, 0, sizeof(olrtagrec)); + if ((msgs.Active) && Access(exitinfo.Security, msgs.RDSec)) { + olrtagrec.Available = TRUE; + olrtagrec.ScanNew = TRUE; + if (msgs.OLR_Forced || msgs.OLR_Default) + olrtagrec.Tagged = TRUE; + } + fwrite(&olrtagrec, sizeof(olrtagrec), 1, fp); + fseek(ma, msgshdr.syssize, SEEK_CUR); + } + + fclose(ma); + } + } + } else { + /* + * The user has been here before... + */ + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + Area++; + + if (fread(&olrtagrec, sizeof(olrtagrec), 1, fp) == 1) { + + /* + * Check if this is a new area for the user. + */ + if ((msgs.Active) && Access(exitinfo.Security, msgs.RDSec) && (!olrtagrec.Available)) { + Syslog('m', "New msg area %ld %s", Area, msgs.Name); + fseek(fp, - sizeof(olrtagrec), SEEK_CUR); + olrtagrec.Available = TRUE; + olrtagrec.ScanNew = TRUE; + if (msgs.OLR_Forced || msgs.OLR_Default) + olrtagrec.Tagged = TRUE; + fwrite(&olrtagrec, sizeof(olrtagrec), 1, fp); + if (CFG.NewAreas) { + if (!Changed) { + New_Hdr(); + Changed = TRUE; + } + New_Area(Area); + } + } else { + /* + * Check if this area is no longer + * available for the user. + */ + if (((!msgs.Active) || (!Access(exitinfo.Security, msgs.RDSec))) && + olrtagrec.Available) { + Syslog('m', "Deleted msg area %ld", Area); + fseek(fp, - sizeof(olrtagrec), SEEK_CUR); + olrtagrec.Available = FALSE; + olrtagrec.ScanNew = FALSE; + olrtagrec.Tagged = FALSE; + fwrite(&olrtagrec, sizeof(olrtagrec), 1, fp); + if (CFG.NewAreas) { + if (!Changed) { + New_Hdr(); + Changed = TRUE; + } + Old_Area(Area); + } + } + } + + } else { + /* + * If the number if msg areas was increased, + * append a new tagrecord. + */ + memset(&olrtagrec, 0, sizeof(olrtagrec)); + if ((msgs.Active) && Access(exitinfo.Security, msgs.RDSec)) { + Syslog('m', "Append new area %ld %s", Area, msgs.Name); + olrtagrec.Available = TRUE; + olrtagrec.ScanNew = TRUE; + if (msgs.OLR_Forced || msgs.OLR_Default) + olrtagrec.Tagged = TRUE; + if (CFG.NewAreas) { + if (!Changed) { + New_Hdr(); + Changed = TRUE; + } + New_Area(Area); + } + } + fwrite(&olrtagrec, sizeof(olrtagrec), 1, fp); + } + fseek(ma, msgshdr.syssize, SEEK_CUR); + } + + fclose(ma); + } + } + + fclose(fp); + + if (Changed) { + colour(10, 0); + fLine(79); + Pause(); + } + + SetMsgArea(exitinfo.iLastMsgArea); + free(Tagname); + free(Msgname); +} + + + +/* + * View tagged areas, called from menu. + */ +void OLR_ViewTags() +{ + char *Tagname, *Msgname; + FILE *tf, *ma; + long total, Area = 0; + int lines, input, ignore = FALSE, maxlines; + + WhosDoingWhat(OLR); + + Tagname = calloc(PATH_MAX, sizeof(char)); + Msgname = calloc(PATH_MAX, sizeof(char)); + sprintf(Tagname, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + sprintf(Msgname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + + if ((tf = fopen(Tagname, "r")) == NULL) { + WriteError("$Can't open %s", Tagname); + return; + } + + if ((ma = fopen(Msgname, "r")) == NULL) { + WriteError("$Can't open %s", Msgname); + fclose(tf); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, ma); + + clear(); + colour(14, 0); + /* You have selected the following Conference(s): */ + printf ("%s\n", (char *)Language(260)); + colour(11, 0); + /* Conference Area Msgs Description */ + printf ("\n%s\n", (char *)Language(229)); + colour(3, 0); + fflush(stdout); + maxlines = lines = exitinfo.iScreenLen - 1; + + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + + if (olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + total = Msg_Number(); + Msg_Close(); + } else + total = 0; + if ( (lines != 0) || (ignore) ) { + lines--; + printf("%-20.20s %-5ld %-5ld %s\n", msgs.QWKname, Area, total, msgs.Name); + } + if (lines == 0) { + fflush(stdin); + colour(15, 0); + /* More (Y/n/=) */ + printf("%s%c\x08", (char *) Language(61),Keystroke(61,0)); + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + printf("%c\r",input); + if ((input == Keystroke(61, 0)) || (input == '\r')) + lines = maxlines; + + if (input == Keystroke(61, 1)) { + break; + } + if (input == Keystroke(61, 2)) + ignore = TRUE; + else + lines = maxlines; + colour(3, 0); + } + fflush(stdout); + } + } + + fclose(tf); + fclose(ma); + Pause(); + free(Tagname); + free(Msgname); +} + + + +/* + * Prescan all selected areas. Show the user the areas and messages in it. + */ +int OLR_Prescan() +{ + unsigned short RetVal = FALSE, Areas; + unsigned long Number; + char *Temp; + FILE *mf, *tf; + int x; + + WhosDoingWhat(OLR); + clear(); + colour(13, 0); + /* Offline Reader Download */ + printf("%s\n\n", (char *)Language(277)); + fflush(stdout); + + if (exitinfo.Email) + check_popmail(exitinfo.Name, exitinfo.Password); + + Temp = calloc(PATH_MAX, sizeof(char)); + sprintf(Temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mf = fopen(Temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + sprintf(Temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + tf = fopen(Temp, "r"); + Total = TotalPersonal = Areas = 0; + + colour(15, 1); + /* Forum Description Msgs. Pers. */ + printf("\n%s\n", (char *)Language(297)); + + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && strlen(msgs.QWKname) && olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + Areas++; + Current = Personal = 0; + colour(11, 0); + printf("%-20.20s %-41.41s ", msgs.QWKname, msgs.Name); + fflush(stdout); + + memset(&LR, 0, sizeof(LR)); + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Number = LR.HighReadMsg; + else + Number = Msg_Lowest() -1; + if (Number > Msg_Highest()) + Number = Msg_Highest(); + if (Msg_Next(&Number)) { + do { + Msg_ReadHeader(Number); + Current++; + Total++; + if ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || + (strcasecmp(Msg.To, exitinfo.sHandle) == 0)) { + Personal++; + TotalPersonal++; + } else if (msgs.Type == NETMAIL) { + Current--; + Total--; + } + } while (Msg_Next(&Number)); + } + + colour(10, 0); + printf("%5lu %5lu\n", Current, Personal); + fflush(stdout); + Msg_Close(); + } + } + } + + Syslog('+', "OLR Prescan: %u Areas, %lu Messages", Areas, Total); + + colour(9, 0); + /* Total messages found: */ + printf("\n%s %lu\n\n", (char *)Language(338), Total); + if (Total == 0L) { + colour(14, 0); + /* No messages found to download! */ + printf("%s\n\007", (char *)Language(374)); + Pause(); + } else { + if (CFG.OLR_MaxMsgs != 0 && Total > CFG.OLR_MaxMsgs) { + /* Too much messages. Only the first will be packed! */ + printf("%s %d %s\n\n\007", (char *)Language(377), CFG.OLR_MaxMsgs, (char *)Language(411)); + Total = CFG.OLR_MaxMsgs; + } + + colour(CFG.HiliteF, CFG.HiliteB); + /* Do you want to download these messages [Y/n]? */ + printf("%s", (char *)Language(425)); + fflush(stdout); + alarm_on(); + x = toupper(Getone()); + + if (x != Keystroke(425, 1)) { + RetVal = TRUE; + TotalPack = Total; + BarWidth = 0; + } + } + + if (mf != NULL) + fclose(mf); + if (tf != NULL) + fclose(tf); + + free(Temp); + return(RetVal); +} + + + +/* + * Draw progess bar + */ +void DrawBar(char *Pktname) +{ + colour(14, 0); + /* Preparing packet */ + printf("\n%s %s...\n\n", (char *)Language(445), Pktname); + colour(10, 0); + printf("0%% 10%% 20%% 30%% 40%% 50%% 60%% 70%% 80%% 90%% 100%%\n"); + printf("|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|\r"); + fflush(stdout); +} + + + +void OLR_RestrictDate() +{ + WhosDoingWhat(OLR); + + printf("Not Yet Implemented\n"); + Pause(); +} + + +/* +VOID TOffline::RestrictDate (VOID) +{ + int dd, mm, yy; + CHAR Temp[32]; + ULONG Restrict; + struct tm ltm; + class TMsgTag *MsgTag = User->MsgTag; + + memcpy (<m, localtime ((time_t *)&User->LastCall), sizeof (struct tm)); + Embedded->Printf ("\n\026\001\017Enter date of oldest message to pack, or press for %d-%02d-%d: ", ltm.tm_mday, ltm.tm_mon + 1, ltm.tm_year % 100); + Embedded->Input (Temp, 10); + + if (Embedded->AbortSession () == FALSE) { + Restrict = User->LastCall; + if (Temp[0] != '\0') { + sscanf (Temp, "%d-%d-%d", &dd, &mm, &yy); + if (yy < 90) + yy += 100; + memset (<m, 0, sizeof (struct tm)); + ltm.tm_mday = dd; + ltm.tm_mon = mm - 1; + ltm.tm_year = yy; + Restrict = mktime (<m); + } + + if (MsgTag->First () == TRUE) + do { + if (MsgTag->Tagged == TRUE) { + MsgTag->LastRead = 0L; + MsgTag->OlderMsg = Restrict; + MsgTag->Update (); + } + } while (MsgTag->Next () == TRUE); + } +} +*/ + +/* +USHORT TOffline::TooOld (ULONG Restrict, class TMsgBase *Msg) +{ + USHORT RetVal = FALSE; + struct tm ltm; + + memset (<m, 0, sizeof (struct tm)); + ltm.tm_mday = Msg->Written.Day; + ltm.tm_mon = Msg->Written.Month - 1; + ltm.tm_year = Msg->Written.Year - 1900; + if (mktime (<m) < Restrict) + RetVal = TRUE; + + return (RetVal); +} +*/ + + + +/* + * Upload offline mail. Filenames: BBSID.NEW or BBSID.REP. + * Should also do hhhhhhhh.SU0 for point uploads. + * NOTE: THE FIRST PART OF THE CODE IS FROM UPLOAD_HOME + */ +void OLR_Upload(void) +{ + char *File, *temp, *Arc; + time_t ElapstimeStart, ElapstimeFin, iTime; + int err, Strlen, RetVal = FALSE; + struct stat statbuf; + FILE *fp; + + WhosDoingWhat(OLR); + clear(); + colour(13, 0); + /* Offline Reader Upload */ + printf("%s\n", (char *)Language(439)); + + if (!ForceProtocol()) + return; + + File = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + if (!uProtBatch) { + Enter(1); + /* Please enter file to upload: */ + pout(14, 0, (char *) Language(276)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + Syslog('+', "Filename entered \"%s\"", File); + + if ((strcmp(File, "")) == 0) + return; + + if (File[0] == '.' || File[0] == '*' || File[0] == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return; + } + + Strlen = strlen(File); + Strlen--; + + if (File[Strlen] == '.' || File[Strlen] == '/' || File[Strlen] == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return; + } + + if (strncasecmp(File, CFG.bbsid, strlen(CFG.bbsid))) { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return; + } + Syslog('+', "Filename accepted"); + } + + colour(CFG.HiliteF, CFG.HiliteB); + /* Please start your upload now */ + printf("\n%s, %s\n\n", sProtAdvice, (char *) Language(283)); + if (uProtBatch) + Syslog('+', "Upload using %s", sProtName); + else + Syslog('+', "Upload \"%s\" using %s", File, sProtName); + + sprintf(temp, "%s/%s/upl", CFG.bbs_usersdir, exitinfo.Name); + + if (chdir(temp)) { + WriteError("$Can't chdir to %s", temp); + return; + } + + sprintf(temp, "%s", sProtUp); + Syslog('+', "Upload command %s", temp); + fflush(stdout); + fflush(stdin); + sleep(2); + time(&ElapstimeStart); + + /* + * Get the file + */ + Altime(7200); + alarm_set(7190); + if ((err = system(temp)) != 0) { + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("$Upload error %d, prot: %s", err, sProtUp); + } + Altime(0); + alarm_off(); + alarm_on(); + printf("\n"); + fflush(stdout); + fflush(stdin); + time(&ElapstimeFin); + + /* + * Get the upload time. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + Syslog('m', "Transfer time %ld", iTime); + Home(); + + if (!RetVal) { + sprintf(File, "%s/%s/upl/%s.NEW", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + Syslog('m', "Check %s", File); + if (stat(File, &statbuf) == 0) + RetVal = TRUE; + } + + if (!RetVal) { + File = tl(File); + Syslog('m', "Check %s", File); + if (stat(File, &statbuf) == 0) + RetVal = TRUE; + } + + if (!RetVal) { + sprintf(File, "%s/%s/upl/%s.REP", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + Syslog('m', "Check %s", File); + if (stat(File, &statbuf) == 0) + RetVal = TRUE; + } + + if (!RetVal) { + File = tl(File); + Syslog('m', "Check %s", File); + if (stat(File, &statbuf) == 0) + RetVal = TRUE; + } + + if (RetVal == FALSE) { + WriteError("Invalid OLR packed received"); + /* Invalid packet received */ + printf("%s\n\n", (char *)Language(440)); + sleep(2); + return; + } + Syslog('+', "Received OLR packet %s", File); + + if ((Arc = GetFileType(File)) == NULL) { + /* Unknown compression type */ + printf("%s\n", (char *)Language(441)); + Syslog('+', "Unknown compression type"); + Pause(); + return; + } + + Syslog('m', "File type is %s", Arc); + + sprintf(temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) + return; + + fread(&archiverhdr, sizeof(archiverhdr), 1, fp); + + while (fread(&archiver, archiverhdr.recsize, 1, fp) == 1) { + if ((strcmp(Arc, archiver.name) == 0) && archiver.available) + break; + } + fclose(fp); + + if (strcmp(Arc, archiver.name) || (!archiver.available)) { + Syslog('+', "Archiver %s not available", Arc); + /* Archiver not available */ + printf("%s\n", (char *)Language(442)); + Pause(); + return; + } + + Syslog('m', "Archiver %s", archiver.comment); + + colour(CFG.TextColourF, CFG.TextColourB); + /* Unpacking archive */ + printf("%s ", (char *) Language(201)); + fflush(stdout); + sprintf(temp, "%s %s", archiver.funarc, File); + Syslog('m', "Unarc %s", temp); + colour(CFG.HiliteF, CFG.HiliteB); + + if ((err = system(temp))) { + WriteError("$Failed %s", temp); + /* ERROR */ + printf("%s\n", (char *) Language(217)); + fflush(stdout); + Pause(); + return; + } + + /* Ok */ + printf("%s\n", (char *) Language(200)); + fflush(stdout); + unlink(File); + + /* + * Check for BlueWave files, upper and lowercase. + */ + RetVal = FALSE; + sprintf(temp, "%s/%s/%s.UPL", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.UPI", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.NET", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.REQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.PDQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.OLC", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + if (RetVal) { + Syslog('+', "OLR packet is BlueWave"); + free(File); + free(temp); + BlueWave_Fetch(); + return; + } + + sprintf(temp, "%s/%s/%s.MSG", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + if (RetVal) { + Syslog('+', "OLR packet is QWK"); + free(File); + free(temp); + QWK_Fetch(); + return; + } + + WriteError("OLR_Upload: Garbage in mailpacket, clean directory!"); + /* Unknown type mailpacket */ + printf("%s\n", (char *)Language(443)); + Pause(); + free(File); + free(temp); +} + + + +/*************************************************************************** + * + * BlueWave specific functions. + */ + + +char *Extensions[] = { + (char *)".SU0", (char *)".MO0", (char *)".TU0", (char *)".WE0", + (char *)".TH0", (char *)".FR0", (char *)".SA0" +}; + + + +/* + * Download a BlueWave mailpacket, called from menu. + */ +void OLR_DownBW() +{ + struct tm *tp; + time_t Now; + char Pktname[32]; + char *Work, *Temp; + long Area = 0; + int RetVal = FALSE, rc; + FILE *fp, *tf, *mf, *af; + INF_HEADER Inf; + INF_AREA_INFO AreaInf; + unsigned long Start, High; + msg_high *mhl = NULL; + + if (!OLR_Prescan()) + return; + + Total = TotalPersonal = 0; + clear(); + colour(9, 0); + /* BlueWave Offline download */ + printf("%s\n", (char *)Language(444)); + + Work = calloc(PATH_MAX, sizeof(char)); + Temp = calloc(PATH_MAX, sizeof(char)); + + Now = time(NULL); + tp = localtime(&Now); + Syslog('+', "Preparing BlueWave packet"); + + sprintf(Pktname, "%s%s", CFG.bbsid , Extensions[tp->tm_wday]); + Syslog('m', "Packet name %s", Pktname); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + Syslog('m', "Work path %s", Work); + + sprintf(Temp, "%s/%s.INF", Work, CFG.bbsid); + if ((fp = fopen(Temp, "w+")) == NULL) { + WriteError("$Can't create %s", Temp); + return; + } + + /* + * Write the info header. + */ + memset(&Inf, 0, sizeof(Inf)); + Inf.ver = PACKET_LEVEL; + strcpy((char *)Inf.loginname, exitinfo.sUserName); + strcpy((char *)Inf.aliasname, exitinfo.sHandle); + Inf.zone = CFG.aka[0].zone; + Inf.net = CFG.aka[0].net; + Inf.node = CFG.aka[0].node; + Inf.point = CFG.aka[0].point; + strcpy((char *)Inf.sysop, CFG.sysop_name); + strcpy((char *)Inf.systemname, CFG.bbs_name); + Inf.maxfreqs = CFG.OLR_MaxReq; + if (exitinfo.HotKeys) + Inf.uflags |= INF_HOTKEYS; + if (exitinfo.GraphMode) + Inf.uflags |= INF_GRAPHICS; + if (exitinfo.OL_ExtInfo) + Inf.uflags |= INF_EXT_INFO; + Inf.credits = exitinfo.Credit; + Inf.inf_header_len = sizeof(INF_HEADER); + Inf.inf_areainfo_len = sizeof(INF_AREA_INFO); + Inf.mix_structlen = sizeof(MIX_REC); + Inf.fti_structlen = sizeof(FTI_REC); + Inf.uses_upl_file = TRUE; + Inf.can_forward = TRUE; + strcpy((char *)Inf.packet_id, CFG.bbsid); + fwrite(&Inf, sizeof(INF_HEADER), 1, fp); + + /* + * Check to see if this stuff is compiled packed. If not the + * download packet is useless. + */ + if ((sizeof(Inf) != ORIGINAL_INF_HEADER_LEN) || + (sizeof(AreaInf) != ORIGINAL_INF_AREA_LEN)) { + WriteError("PANIC: Probably not \"packed\" compiled!"); + fclose(fp); + return; + } + + sprintf(Temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + sprintf(Temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((tf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + fclose(mf); + return; + } + + /* + * Write the areas information + */ + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec)) { + memset(&AreaInf, 0, sizeof(AreaInf)); + sprintf((char *)AreaInf.areanum, "%lu", Area); + strcpy((char *)AreaInf.echotag, msgs.QWKname); + strcpy((char *)AreaInf.title, msgs.Name); + if (olrtagrec.Tagged) { + AreaInf.area_flags |= INF_SCANNING; + RetVal = TRUE; + } + + switch(msgs.Type) { + case LOCALMAIL: + break; + + case NETMAIL: AreaInf.area_flags |= (INF_ECHO+INF_NETMAIL+INF_HASFILE); + break; + + case ECHOMAIL: AreaInf.area_flags |= INF_ECHO; + break; + +// case EMAIL: AreaInf.area_flags |= (INF_ECHO+INF_NETMAIL); +// AreaInf.network_type |= INF_NET_INTERNET; +// break; + + case NEWS: AreaInf.area_flags |= INF_ECHO; + AreaInf.network_type |= INF_NET_INTERNET; + break; + } + switch(msgs.MsgKinds) { + case BOTH: if (Access(exitinfo.Security, msgs.WRSec)) + AreaInf.area_flags |= INF_POST; + break; + + case PRIVATE: if (Access(exitinfo.Security, msgs.WRSec)) + AreaInf.area_flags |= INF_POST; + AreaInf.area_flags |= INF_NO_PUBLIC; + break; + + case PUBLIC: if (Access(exitinfo.Security, msgs.WRSec)) + AreaInf.area_flags |= INF_POST; + AreaInf.area_flags |= INF_NO_PRIVATE; + break; + + case RONLY: break; + } + + if (msgs.Aliases) + AreaInf.area_flags |= INF_ALIAS_NAME; + + fwrite(&AreaInf, sizeof(AreaInf), 1, fp); + } + } + fclose(fp); + + if (RetVal) { + Area = 0; + DrawBar(Pktname); + fseek(mf, sizeof(msgshdr), SEEK_SET); + fseek(tf, 0, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + Current = Personal = 0; + if (Msg_Highest() != 0) { + memset(&LR, 0, sizeof(LR)); + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg; + else + Start = Msg_Lowest() -1; + if (Start > Msg_Highest()) + Start = Msg_Highest(); + if (Start < Msg_Highest()) { + Syslog('m', "First %lu, Last %lu, Start %lu", Msg_Lowest(), Msg_Highest(), Start); + High = BlueWave_PackArea(Start, Area); + fill_high(&mhl, Area, High, Personal); + } + } + Syslog('+', "Area %-20s %5ld (%ld personal)", msgs.QWKname, Current, Personal); + Msg_Close(); + } + } + } + Syslog('+', "Packed %ld messages (%ld personal)", Total, TotalPersonal); + } + fclose(tf); + + rc = FALSE; + alarm_on(); + + if (Total) { + /* Packing with */ + printf("\n%s ", (char *)Language(446)); + sprintf(Temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((af = fopen(Temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, af); + while (fread(&archiver, archiverhdr.recsize, 1, af) == 1) { + if (archiver.available && (!strcmp(archiver.name, exitinfo.Archiver))) { + Syslog('+', "Archiver %s", archiver.comment); + printf("%s ", archiver.comment); + sprintf(Temp, "%s/%s.DAT", Work, CFG.bbsid); + AddArc(Temp, Pktname); + alarm_on(); + sprintf(Temp, "%s/%s.FTI", Work, CFG.bbsid); + AddArc(Temp, Pktname); + sprintf(Temp, "%s/%s.INF", Work, CFG.bbsid); + AddArc(Temp, Pktname); + sprintf(Temp, "%s/%s.MIX", Work, CFG.bbsid); + AddArc(Temp, Pktname); + sprintf(Temp, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, Pktname); + rc = DownloadDirect(Temp, FALSE); + Syslog('m', "Download result %d", rc); + unlink(Temp); + } + } + fclose(af); + } + } + + colour(CFG.HiliteF, CFG.HiliteB); + if (rc == FALSE) { + Syslog('+', "BlueWave download failed"); + /* Download failed */ + printf("%s", (char *)Language(447)); + } else { + Syslog('+', "BlueWave download successfull"); + /* Download successfull */ + printf("\r%s\n", (char *)Language(448)); + + if (mhl != NULL) + UpdateLR(mhl, mf); + } + + fclose(mf); + tidy_high(&mhl); + + free(Temp); + free(Work); + printf("\n\n"); + Pause(); +} + + + +/* + * BlueWave Fetch reply packet. + */ +void BlueWave_Fetch() +{ + char *temp; + FILE *up, *mf, *tp; + UPL_HEADER Uph; + UPL_REC Upr; + PDQ_HEADER Pdh; + PDQ_REC Pdr; + REQ_REC Req; + int i, Found; + fidoaddr dest; + + colour(9, 0); + /* Processing BlueWave reply packet */ + printf("%s\n", (char *)Language(450)); + temp = calloc(PATH_MAX, sizeof(char)); + + /* + * Process uploaded mail + */ + sprintf(temp, "%s/%s/%s.UPL", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((up = fopen(temp, "r")) == NULL) { + temp = tl(temp); + up = fopen(temp, "r"); + } + if (up != NULL) { + fread(&Uph, sizeof(UPL_HEADER), 1, up); + Syslog('+', "Processing BlueWave .UPL file"); + Syslog('+', "Client: %s %d.%d", Uph.reader_name, Uph.reader_major, Uph.reader_minor); + if (Uph.upl_header_len != sizeof(UPL_HEADER)) { + WriteError("Recordsize mismatch"); + fclose(up); + /* ERROR in packet */ + printf("%s\n", (char *)Language(451)); + Pause(); + return; + } + Syslog('+', "Login %s, Alias %s", Uph.loginname, Uph.aliasname); + /* MORE CHECKS HERE */ + + colour(CFG.TextColourF, CFG.TextColourB); + /* Import messages */ + printf("%s ", (char *)Language(452)); + colour(CFG.HiliteF, CFG.HiliteB); + fflush(stdout); + i = 0; + + memset(&Upr, 0, sizeof(UPL_REC)); + while (fread(&Upr, Uph.upl_rec_len, 1, up) == 1) { + printf("."); + fflush(stdout); + Syslog('m', " From : %s", Upr.from); + Syslog('m', " To : %s", Upr.to); + Syslog('m', " Subj : %s", Upr.subj); + Syslog('m', " Date : %ld", Upr.unix_date); + Syslog('m', " Dest : %d:%d/%d.%d", Upr.destzone, Upr.destnet, Upr.destnode, Upr.destpoint); + if (Upr.msg_attr & UPL_INACTIVE) + Syslog('m', " Message is Inactive"); + if (Upr.msg_attr & UPL_PRIVATE) + Syslog('m', " Message is Private"); + if (Upr.msg_attr & UPL_HAS_FILE) + Syslog('m', " File Attach"); + if (Upr.msg_attr & UPL_NETMAIL) + Syslog('m', " Is Netmail"); + if (Upr.msg_attr & UPL_IS_REPLY) + Syslog('m', " Is Reply"); + if (Upr.network_type) + Syslog('m', " Type : Internet"); + else + Syslog('m', " Type : Fidonet"); + Syslog('m', " File : %s", Upr.filename); + Syslog('m', " Tag : %s", Upr.echotag); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(temp, "r+")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, mf); + Found = FALSE; + + if (strlen(Upr.echotag)) { + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + if (msgs.Active && (strcasecmp(msgs.QWKname, Upr.echotag) == 0)) { + Found = TRUE; + break; + } + } + } else { + /* + * If there is no echotag, the filename is used + * this is "areanum.msgnum" so we pick the part + * before the dot and pray that it's ok. + */ + temp = strtok(strdup(Upr.filename), "."); + if (fseek(mf, ((atoi(temp) -1) * (msgshdr.recsize + msgshdr.syssize)) + msgshdr.hdrsize, SEEK_SET) == 0) + if (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + Found = TRUE; + fseek(mf, msgshdr.syssize, SEEK_CUR); + } + } + + /* SHOULD ALSO CHECK FROM FIELD */ + if (!Found) { + WriteError("No msg area, File \"%s\"", Upr.filename); + } else { + if ((Access(exitinfo.Security, msgs.WRSec)) && (msgs.MsgKinds != RONLY)) { + + if (Open_Msgbase(msgs.Base, 'w')) { + Msg_New(); + Syslog('m', "Msgbase open and locked"); + strcpy(Msg.From, Upr.from); + strcpy(Msg.To, Upr.to); + strcpy(Msg.Subject, Upr.subj); + if (Upr.msg_attr & UPL_PRIVATE) + Msg.Private = TRUE; + if (msgs.MsgKinds == PRIVATE) + Msg.Private = TRUE; + Msg.Written = Upr.unix_date; + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Local = TRUE; + dest.zone = Upr.destzone; + dest.net = Upr.destnet; + dest.node = Upr.destnode; + dest.point = Upr.destpoint; + Syslog('m', "Header fields are set, starting kludges"); + Add_Kludges(dest, FALSE, Upr.filename); + Syslog('+', "Msg (%ld) to \"%s\", \"%s\", in %s", Msg.Id, Msg.To, Msg.Subject, msgs.QWKname); + sprintf(temp, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, Upr.filename); + unlink(temp); + i++; + Close_Msgbase(); + Syslog('m', "Msgbase closed again"); + fseek(mf, - (msgshdr.recsize + msgshdr.syssize), SEEK_CUR); + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + msgs.LastPosted = time(NULL); + fwrite(&msgs, msgshdr.recsize, 1, mf); + } + } else { + /* No Write access to area */ + printf("\n%s %s\n", (char *)Language(453), msgs.Name); + WriteError("No Write Access to area %s", msgs.Name); + } + } + fclose(mf); + } + memset(&Upr, 0, sizeof(UPL_REC)); + } + printf("\n"); + colour(CFG.TextColourF, CFG.TextColourB); + if (i) { + /* Messages imported */ + printf("%d %s\n", i, (char *)Language(454)); + ReadExitinfo(); + exitinfo.iPosted += i; + WriteExitinfo(); + do_mailout = TRUE; + } + fflush(stdout); + fclose(up); + + /* + * Remove processed files. + */ + sprintf(temp, "%s/%s/%s.UPL", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + unlink(temp); + temp = tl(temp); + unlink(temp); + sprintf(temp, "%s/%s/%s.UPI", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + unlink(temp); + temp = tl(temp); + unlink(temp); + sprintf(temp, "%s/%s/%s.NET", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + unlink(temp); + temp = tl(temp); + unlink(temp); + } + + /* + * If a .UPL file was not found it is possible we received an version 2 + * reply packet. + */ + sprintf(temp, "%s/%s/%s.UPI", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((up = fopen(temp, "r")) == NULL) { + temp = tl(temp); + up = fopen(temp, "r"); + } + if (up != NULL) { + Syslog('+', "Received Version 2 .UPI packet, not supported"); + fclose(up); + } + sprintf(temp, "%s/%s/%s.NET", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((up = fopen(temp, "r")) == NULL) { + temp = tl(temp); + up = fopen(temp, "r"); + } + if (up != NULL) { + Syslog('+', "Received Version 2 .NET packet, not supported"); + fclose(up); + } + + /* + * Process offline configuration + */ + sprintf(temp, "%s/%s/%s.PDQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((tp = fopen(temp, "r")) == NULL) { + temp = tl(temp); + tp = fopen(temp, "r"); + } + if (tp != NULL) { + colour(9, 0); + /* Processing Offline Configuration */ + printf("%s\n", (char *)Language(455)); + Syslog('+', "Processing offline configuration"); + + fread(&Pdh, sizeof(PDQ_HEADER), 1, tp); + for (i = 0; i < 10; i++) + if (strlen(Pdh.keywords[i])) + Syslog('m', " Kwrd %2d : %s", i+1, Pdh.keywords[i]); + for (i = 0; i < 10; i++) + if (strlen(Pdh.filters[i])) + Syslog('m', " Filt %2d : %s", i+1, Pdh.filters[i]); + for (i = 0; i < 3; i++) + if (strlen(Pdh.macros[i])) + Syslog('m', " Macro %d : %s", i+1, Pdh.macros[i]); + Syslog('m', " Pwtype : %d", Pdh.passtype); + Syslog('m', " Flags : %08x", Pdh.flags); + + /* + * If the changes flag is set there are records with + * active areas. Reset all areas first and then set + * the active areas back on. + */ + if (Pdh.flags & PDQ_AREA_CHANGES) { + Syslog('m', " New Area Configuration present"); + i = 0; + + sprintf(temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((up = fopen(temp, "r+")) != NULL) { + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(temp, "r")) != NULL) { + + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + while (fread(&olrtagrec, sizeof(olrtagrec), 1, up) == 0) { + fread(&msgs, msgshdr.recsize, 1, mf); + fseek(mf, msgshdr.syssize, SEEK_CUR); + if (!msgs.OLR_Forced) + olrtagrec.Tagged = FALSE; + fseek(up, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, up); + } + + while (fread(&Pdr, sizeof(PDQ_REC), 1, tp) == 1) { + if (strlen(Pdr.echotag)) { + fseek(mf, msgshdr.hdrsize, SEEK_SET); + fseek(up, 0, SEEK_SET); + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, up); + if ((strcmp(msgs.QWKname, Pdr.echotag) == 0) && + (msgs.Active) && + (Access(exitinfo.Security, msgs.RDSec))) { + Syslog('m', " Area %s", Pdr.echotag); + olrtagrec.Tagged = TRUE; + fseek(up, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, up); + i++; + break; + } + } + } + } + fclose(mf); + colour(3, 0); + /* Message areas selected */ + printf("%d %s\n", i, (char *)Language(456)); + } + fclose(up); + } + } + fclose(tp); + sprintf(temp, "%s/%s/%s.PDQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + unlink(temp); + } + + /* + * Check for .REQ file. + */ + sprintf(temp, "%s/%s/%s.REQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((tp = fopen(temp, "r")) == NULL) { + temp = tl(temp); + tp = fopen(temp, "r"); + } + if (tp != NULL) { + i = 0; + colour(9, 0); + /* Processing file requests */ + printf("%s\n", (char *)Language(457)); + Syslog('+', "Processing file requests"); + + while (fread(&Req, sizeof(REQ_REC), 1, tp) == 1) { + Syslog('m', " File %s", Req.filename); + colour(CFG.TextColourF, CFG.TextColourB); + printf("%-12s ", Req.filename); + colour(CFG.HiliteF, CFG.HiliteB); + fflush(stdout); + + printf("\n"); + } + + fclose(tp); + } + + free(temp); + Pause(); +} + + + +/* + * Add one area to the BlueWave download packet + */ +unsigned long BlueWave_PackArea(unsigned long ulLast, long Area) +{ + FILE *fdm, *fdfti, *fdmix; + char *Temp, *Text; + unsigned long Number; + MIX_REC Mix; + FTI_REC Fti; + struct tm *tp; + int Pack; + + Number = ulLast; + Temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(Temp, "%s/%s/tmp/%s.FTI", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + fdfti = fopen(Temp, "a+"); + + sprintf(Temp, "%s/%s/tmp/%s.MIX", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + fdmix = fopen(Temp, "a+"); + + sprintf(Temp, "%s/%s/tmp/%s.DAT", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + fdm = fopen(Temp, "a+"); + + memset(&Mix, 0, sizeof(MIX_REC)); + sprintf((char *)Mix.areanum, "%lu", Area); + Mix.msghptr = ftell(fdfti); + + if ((fdfti != NULL) && (fdmix != NULL) && (fdm != NULL)) { + if (Msg_Next(&Number)) { + do { + Msg_ReadHeader(Number); + Msg_Read(Number, 78); + Pack = TRUE; + + if ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || + (strcasecmp(Msg.To, exitinfo.sHandle) == 0)) { + Personal++; + TotalPersonal++; + } else if (msgs.Type == NETMAIL) { + Pack = FALSE; + } else if (msgs.MsgKinds == PRIVATE ) { + Pack = FALSE; + } else if (msgs.MsgKinds == BOTH ) { + if (Msg.Private == TRUE ) Pack = FALSE; + } + + if (Pack) { + Current++; + Total++; + memset (&Fti, 0, sizeof (FTI_REC)); + + Msg.From[sizeof(Fti.from) - 1] = '\0'; + strcpy((char *)Fti.from, Msg.From); + Msg.To[sizeof(Fti.to) - 1] = '\0'; + strcpy((char *)Fti.to, Msg.To); + Msg.Subject[sizeof(Fti.subject) - 1] = '\0'; + strcpy((char *)Fti.subject, Msg.Subject); + tp = localtime(&Msg.Written); + sprintf((char *)Fti.date, "%2d %.3s %2d %2d:%02d:%02d", tp->tm_mday, + (char *) Language(398 + tp->tm_mon), tp->tm_year, + tp->tm_hour, tp->tm_min, tp->tm_sec); + Fti.msgnum = Number; + Fti.msgptr = ftell(fdm); + Fti.replyto = Msg.Original; + Fti.replyat = Msg.Reply; + if (msgs.Type == NETMAIL) { + Fti.orig_zone = msgs.Aka.zone; + Fti.orig_net = msgs.Aka.net; + Fti.orig_node = msgs.Aka.node; + } + + Fti.msglength += fwrite(" ", 1, 1, fdm); + + if ((Text = (char *)MsgText_First()) != NULL) + do { + if ((Text[0] != 0x01 && strncmp(Text, "SEEN-BY: ", 9))|| + (strncmp(Text, "\001MSGID", 6) == 0) /* || + (exitinfo.OL_ExtInfo) */ ) { + Fti.msglength += fwrite(Text, 1, strlen(Text), fdm); + Fti.msglength += fwrite("\r\n", 1, 2, fdm); + } + } while ((Text = (char *)MsgText_Next()) != NULL); + + fwrite(&Fti, sizeof (Fti), 1, fdfti); + } + + if (BarWidth != (unsigned short)((Total * 61L) / TotalPack)) { + BarWidth = (unsigned short)((Total * 61L) / TotalPack); + colour(3, 0); + printf("\r%.*s", BarWidth, "ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ"); + fflush(stdout); + } + } while (Msg_Next(&Number)); + } + } + + Mix.totmsgs = (tWORD)Current; + Mix.numpers = (tWORD)Personal; + fwrite(&Mix, sizeof (Mix), 1, fdmix); + + if (fdfti != NULL) + fclose(fdfti); + if (fdmix != NULL) + fclose(fdmix); + if (fdm != NULL) + fclose(fdm); + + free(Temp); + return Number; +} + + + +/*********************************************************************************** + * + * QWK specific functions + * + */ + + + +void OLR_DownQWK(void) +{ + struct tm *tp; + time_t Now; + char Pktname[32]; + long Area = 0; + char *Work, *Temp; + int i, rc = 0; + FILE *fp = NULL, *tf, *mf, *af; + unsigned long Start, High; + msg_high *tmp, *mhl = NULL; + + if (!OLR_Prescan()) + return; + + Total = TotalPersonal = 0L; + clear(); + colour(9, 0); + /* QWK Offline Download */ + printf("%s\n", (char *)Language(458)); + + Work = calloc(PATH_MAX, sizeof(char)); + Temp = calloc(PATH_MAX, sizeof(char)); + + Now = time(NULL); + tp = localtime(&Now); + Syslog('+', "Preparing QWK packet"); + + sprintf(Temp, "%s.QWK", CFG.bbsid); + sprintf(Pktname, "%s", tl(Temp)); + Syslog('m', "Packet name %s", Pktname); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + Syslog('m', "Work path %s", Work); + + sprintf(Temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + sprintf(Temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((tf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + fclose(mf); + return; + } + + Area = 0; + DrawBar(Pktname); + fseek(mf, sizeof(msgshdr), SEEK_SET); + fseek(tf, 0, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + Current = Personal = 0; + if (Msg_Highest() != 0) { + memset(&LR, 0, sizeof(LR)); + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg; + else + Start = Msg_Lowest() -1; + if (Start > Msg_Highest()) + Start = Msg_Highest(); + if (Start < Msg_Highest()) { + Syslog('m', "First %lu, Last %lu, Start %lu", Msg_Lowest(), Msg_Highest(), Start); + High = QWK_PackArea(Start, Area); + fill_high(&mhl, Area, High, Personal); + } + } + Syslog('+', "Area %-20s %5ld (%ld personal)", msgs.QWKname, Current, Personal); + Msg_Close(); + } + } + } + + sprintf(Temp, "%s/CONTROL.DAT", Work); + if ((fp = fopen(Temp, "w+")) != NULL) { + fprintf(fp, "%s\n", CFG.bbs_name); + fprintf(fp, "%s\n", CFG.location); + fprintf(fp, "%s\n", CFG.Phone); + fprintf(fp, "%s\n", CFG.sysop_name); + fprintf(fp, "00000,%s\n", CFG.bbsid); + + fprintf(fp, "%02d-%02d-%04d,%02d:%02d:%02d\n", tp->tm_mday, tp->tm_mon+1, tp->tm_year+1900, + tp->tm_hour, tp->tm_min, tp->tm_sec); + sprintf(Temp, "%s", exitinfo.sUserName); + fprintf(fp, "%s\n", tu(Temp)); + fprintf(fp, " \n"); + fprintf(fp, "0\n"); + fprintf(fp, "%lu\n", Total); + + /* + * Count available areas. + */ + i = 0; + fseek(mf, msgshdr.hdrsize, SEEK_SET); + fseek(tf, 0, SEEK_SET); + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && strlen(msgs.QWKname)) + i++; + } + fprintf(fp, "%d\n", i - 1); + + /* + * Write available areas + */ + i = 0; + fseek(mf, msgshdr.hdrsize, SEEK_SET); + fseek(tf, 0, SEEK_SET); + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + i++; + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && strlen(msgs.QWKname)) { + fprintf(fp, "%d\n%s\n", i, msgs.QWKname); + } + } + + fprintf(fp, "WELCOME\n"); + fprintf(fp, "NEWS\n"); + fprintf(fp, "GOODBYE\n"); + fclose(fp); + } + + sprintf(Temp, "%s/DOOR.ID", Work); + if ((fp = fopen(Temp, "w+")) != 0) { + fprintf(fp, "DOOR = MBSE BBS QWK\n"); + fprintf(fp, "VERSION = %s\n", VERSION); + fprintf(fp, "SYSTEM = %s\n", CFG.bbs_name); + fprintf(fp, "CONTROLNAME = MBSEQWK\n"); + fprintf(fp, "CONTROLTYPE = ADD\n"); + fprintf(fp, "CONTROLTYPE = DROP\n"); + fclose(fp); + } + + Syslog('+', "Packed %ld messages (%ld personal)", Total, TotalPersonal); + fclose(tf); + + if (Total) { + /* Packing with */ + printf("\n%s ", (char *)Language(446)); + sprintf(Temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((af = fopen(Temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, af); + while (fread(&archiver, archiverhdr.recsize, 1, af) == 1) { + if (archiver.available && (!strcmp(archiver.name, exitinfo.Archiver))) { + Syslog('+', "Archiver %s", archiver.comment); + printf("%s ", archiver.comment); + sprintf(Temp, "%s/CONTROL.DAT", Work); + AddArc(Temp, Pktname); + alarm_on(); + sprintf(Temp, "%s/MESSAGES.DAT", Work); + AddArc(Temp, Pktname); + + for (tmp = mhl; tmp; tmp = tmp->next) { + sprintf(Temp, "%s/%03ld.NDX", Work, tmp->Area); + AddArc(Temp, Pktname); + } + + sprintf(Temp, "%s/PERSONAL.NDX", Work); + if (TotalPersonal) { + AddArc(Temp, Pktname); + } else + unlink(Temp); + + sprintf(Temp, "%s/DOOR.ID", Work); + AddArc(Temp, Pktname); + sprintf(Temp, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, Pktname); + rc = DownloadDirect(Temp, FALSE); + Syslog('m', "Download result %d", rc); + unlink(Temp); + } + } + fclose(af); + } + } + + colour(CFG.HiliteF, CFG.HiliteB); + if (rc == FALSE) { + Syslog('+', "QWK download failed"); + /* Download failed */ + printf("%s", (char *)Language(447)); + } else { + Syslog('+', "QWK download successfull"); + /* Download successfull */ + printf("\r%s\n", (char *)Language(448)); + + if (mhl != NULL) + UpdateLR(mhl, mf); + } + fclose(mf); + tidy_high(&mhl); + + free(Temp); + free(Work); + printf("\n\n"); + Pause(); +} + + + +/* + * QWK Fetch Reply packet + */ +void QWK_Fetch() +{ + char *temp, *otemp, Temp[128], szLine[132], *pLine = NULL, *pBuff; + FILE *up, *op, *mf; + unsigned short nRec, i, r, x, nCol = 0, nWidth, nReaded, nPosted = 0; + unsigned long Area; + struct tm *ltm = NULL; + fidoaddr dest; + + colour(9, 0); + /* Processing BlueWave reply packet */ + printf("%s\n", (char *)Language(459)); + temp = calloc(2048, sizeof(char)); + otemp = calloc(PATH_MAX, sizeof(char)); + nWidth = 78; + + sprintf(temp, "%s/%s/%s.MSG", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((up = fopen(temp, "r")) == NULL) { + temp = tl(temp); + up = fopen(temp, "r"); + } + + if (up != NULL) { + Syslog('+', "Processing QWK file %s", temp); + + fread(&Temp, 128, 1, up); + Temp[8] = '\0'; + if (strcmp(CFG.bbsid, StripSpaces(Temp, 8))) { + Syslog('?', "Wrong QWK packet id: \"%s\"", StripSpaces(Temp, 8)); + fclose(up); + unlink(temp); + /* ERROR in packet */ + printf("%s\n", (char *)Language(451)); + free(temp); + free(otemp); + Pause(); + return; + } + + while (fread(&Qwk, sizeof(Qwk), 1, up) == 1) { + Area = atol(StripSpaces(Qwk.Msgnum, sizeof(Qwk.Msgnum))); + nRec = atoi(StripSpaces(Qwk.Msgrecs, sizeof(Qwk.Msgrecs))); + + /* + * Test for blank records. + */ + if (Area && nRec) { + Syslog('m', "Conference %u", Area); + Syslog('m', "Records %d", nRec); + Syslog('m', "To %s", tlcap(StripSpaces(Qwk.MsgTo, sizeof(Qwk.MsgTo)))); + Syslog('m', "From %s", tlcap(StripSpaces(Qwk.MsgFrom, sizeof(Qwk.MsgFrom)))); + Syslog('m', "Subject %s", StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))); + sprintf(Temp, "%s", StripSpaces(Qwk.Msgdate, sizeof(Qwk.Msgdate))); + Syslog('m', "Date %s %s", Temp, StripSpaces(Qwk.Msgtime, sizeof(Qwk.Msgtime))); + + if (strcmp("MBSEQWK", StripSpaces(Qwk.MsgTo, sizeof(Qwk.MsgTo))) == 0) { + Syslog('m', "Command %s", StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))); + sprintf(otemp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((op = fopen(otemp, "r+")) != NULL) { + + sprintf(otemp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(otemp, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, mf); + fseek(mf, ((Area -1) * (msgshdr.recsize + msgshdr.syssize)) + + msgshdr.hdrsize, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, mf); + fseek(op, (Area -1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, op); + + if (strcmp("ADD", StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))) == 0) { + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname) && !olrtagrec.Tagged) { + olrtagrec.Tagged = TRUE; + fseek(op, - sizeof(olrtagrec), SEEK_CUR); + Syslog('m', "%d", fwrite(&olrtagrec, sizeof(olrtagrec), 1, op)); + Syslog('+', "QWK added area %s", msgs.QWKname); + } + } + + if (strcmp("DROP", StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))) == 0) { + if (!msgs.OLR_Forced && olrtagrec.Tagged) { + olrtagrec.Tagged = FALSE; + fseek(op, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, op); + Syslog('+', "QWK dropped area %s", msgs.QWKname); + } + } + + fclose(mf); + } + fclose(op); + } + } else { + /* + * Normal message + */ + Syslog('m', "Message"); + sprintf(otemp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(otemp, "r+")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, mf); + fseek(mf, ((Area -1) * (msgshdr.recsize + msgshdr.syssize)) + + msgshdr.hdrsize, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, mf); + + /* + * Check access to this area + */ + if (msgs.Active && strlen(msgs.QWKname) && Access(exitinfo.Security, msgs.WRSec) && + (msgs.MsgKinds != RONLY)) { + if (Open_Msgbase(msgs.Base, 'w')) { + Msg_New(); + pLine = szLine; + nCol = 0; + Syslog('m', "Msgbase open and locked"); + strcpy(Msg.From, tlcap(StripSpaces(Qwk.MsgFrom, sizeof(Qwk.MsgFrom)))); + strcpy(Msg.To, tlcap(StripSpaces(Qwk.MsgTo, sizeof(Qwk.MsgTo)))); + strcpy(Msg.Subject, StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))); + if ((Qwk.Msgstat == '*') || (Qwk.Msgstat == '+')) + Msg.Private = TRUE; + strcpy(Temp, StripSpaces(Qwk.Msgdate, sizeof(Qwk.Msgdate))); + ltm = malloc(sizeof(struct tm)); + memset(ltm, 0, sizeof(struct tm)); + ltm->tm_mday = atoi(&Temp[3]); + ltm->tm_mon = atoi(&Temp[0]) -1; + ltm->tm_year = atoi(&Temp[6]); + if (ltm->tm_year < 96) + ltm->tm_year += 100; + strcpy(Temp, StripSpaces(Qwk.Msgtime, sizeof(Qwk.Msgtime))); + ltm->tm_hour = atoi(&Temp[0]); + ltm->tm_min = atoi(&Temp[3]); + ltm->tm_sec = 0; + Msg.Written = mktime(ltm); + free(ltm); + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Local = TRUE; + memset(&dest, 0, sizeof(dest)); +// dest.zone = Upr.destzone; +// dest.net = Upr.destnet; +// dest.node = Upr.destnode; +// dest.point = Upr.destpoint; + Add_Headkludges(fido2faddr(dest), FALSE); + + for (r = 1; r < nRec; r++) { + nReaded = fread(Temp, 1, 128, up); + Syslog('m', "nReaded=%d", nReaded); + if (r == (nRec - 1)) { + x = 127; + while (x > 0 && Temp[x] == ' ') { + nReaded--; + x--; + } + Syslog('m', "Final=%d", nReaded); + } + + for (i = 0, pBuff = Temp; i < nReaded; i++, pBuff++) { + if (*pBuff == '\r' || *pBuff == (char)0xE3) { + *pLine = '\0'; + Syslog('m', "1 Len=%d \"%s\"", strlen(szLine), printable(szLine, 0)); + MsgText_Add2(szLine); + pLine = szLine; + nCol = 0; + } else if (*pBuff != '\n') { + *pLine++ = *pBuff; + nCol++; + if (nCol >= nWidth) { + *pLine = '\0'; + while (nCol > 1 && *pLine != ' ') { + nCol--; + pLine--; + } + if (nCol > 0) { + while (*pLine == ' ') + pLine++; + strcpy (szWrp, pLine); + } + *pLine = '\0'; + Syslog('m', "2 Len=%d \"%s\"", strlen(szLine), printable(szLine, 0)); + MsgText_Add2(szLine); + strcpy(szLine, szWrp); + pLine = strchr(szLine, '\0'); + nCol = (short)strlen (szLine); + } + } + } + } + if (nCol > 0) { + *pLine = '\0'; + Syslog('m', "3 Len=%d \"%s\"", strlen(szLine), printable(szLine, 0)); + MsgText_Add2(szLine); + } + + Add_Footkludges(FALSE); + Msg_AddMsg(); + + Syslog('+', "Msg (%ld) to \"%s\", \"%s\", in %s", Msg.Id, + Msg.To, Msg.Subject, msgs.QWKname); + nPosted++; + Close_Msgbase(); + Syslog('m', "Msgbase closed again"); + fseek(mf, ((Area -1) * (msgshdr.recsize + msgshdr.syssize)) + + msgshdr.hdrsize, SEEK_SET); + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + msgs.LastPosted = time(NULL); + fwrite(&msgs, msgshdr.recsize, 1, mf); + } + } else { + Syslog('+', "Can't post messages in area %u", Area); + } + fclose(mf); + } + } + } else { + Syslog('m', "Skip blank record"); + } + } + + fclose(up); + } + + printf("\n"); + colour(CFG.TextColourF, CFG.TextColourB); + if (nPosted) { + /* Messages imported */ + printf("%d %s\n", nPosted, (char *)Language(454)); + ReadExitinfo(); + exitinfo.iPosted += nPosted; + WriteExitinfo(); + do_mailout = TRUE; + } + fflush(stdout); + unlink(temp); + free(temp); + free(otemp); + Pause(); +} + + + +union Converter { + unsigned char uc[10]; + unsigned short ui[5]; + unsigned long ul[2]; + float f[2]; + double d[1]; +}; + + + +float IEEToMSBIN(float f) +{ + int sign, exp; + union Converter t; + + t.f[0] = f; + sign = t.uc[3] / 0x80; + exp = ((t.ui[1] >> 7) - 0x7F + 0x81) & 0xFF; + t.ui[1] = (t.ui[1] & 0x7F) | (sign << 7) | (exp << 8); + + return t.f[0]; +} + + + +float MSBINToIEEE(float f) +{ + union Converter t; + int sign, exp; + + t.f[0] = f; + sign = t.uc[2] / 0x80; + exp = (t.uc[3] - 0x81 + 0x7f) & 0xff; + t.ui[1] = (t.ui[1] & 0x7f) | (exp << 7) | (sign << 15); + return t.f[0]; +} + + + +/* + * Pack messages in one mail area + */ +unsigned long QWK_PackArea(unsigned long ulLast, long Area) +{ + FILE *fdm, *fdi, *fdp; + float out, in; + char *Work, *Temp, *Text; + unsigned long Number, Pos, Size, Blocks; + int Pack = FALSE; + struct tm *tp; + + Number = ulLast; + Current = Personal = 0L; + + Temp = calloc(PATH_MAX, sizeof(char)); + Work = calloc(PATH_MAX, sizeof(char)); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + + sprintf(Temp, "%s/%03ld.NDX", Work, Area); + fdi = fopen(Temp, "a+"); + + sprintf(Temp, "%s/PERSONAL.NDX", Work); + fdp = fopen(Temp, "a+"); + + /* + * Open MESSAGES.DAT, if it doesn't exist, create it and write + * the header. Then reopen the file in r/w mode. + */ + sprintf(Temp, "%s/MESSAGES.DAT", Work); + if ((fdm = fopen (Temp, "r+")) == NULL) { + Syslog('m', "Creating new %s", Temp); + fdm = fopen(Temp, "a+"); + // ---------------------------------------------------------------------- + // The first record of the MESSAGE.DAT file must be the Sparkware id + // block, otherwise some applications may complain. + // ---------------------------------------------------------------------- + fprintf(fdm, "Produced by Qmail..."); + fprintf(fdm, "Copywright (c) 1987 by Sparkware. "); + fprintf(fdm, "All Rights Reserved"); + memset(Temp, ' ', 54); + fwrite(Temp, 54, 1, fdm); + fclose(fdm); + sprintf(Temp, "%s/MESSAGES.DAT", Work); + fdm = fopen(Temp, "r+"); + } + + if ((fdm != NULL) && (fdp != NULL) && (fdi != NULL)) { + fseek(fdm, 0, SEEK_END); + if (Msg_Next(&Number)) { + do { + Msg_ReadHeader(Number); + Msg_Read(Number, 78); + Pack = TRUE; + if ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || + (strcasecmp(Msg.To, exitinfo.sHandle) == 0)) { + Personal++; + TotalPersonal++; + fwrite(&out, sizeof(float), 1, fdp); + fwrite("", 1, 1, fdp); + } else if (msgs.Type == NETMAIL) { + Pack = FALSE; + } else if (msgs.MsgKinds == PRIVATE ) { + Pack = FALSE; + } else if (msgs.MsgKinds == BOTH ) { + if (Msg.Private == TRUE ) Pack = FALSE; + } + + if (Pack) { + /* + * Calculate the recordnumber from the current file + * position and store it in M$oft BIN format. + */ + Pos = ftell(fdm); + Blocks = (Pos / 128L) + 1L; + sprintf(Temp, "%lu", Blocks); + in = atof(Temp); + out = IEEToMSBIN(in); + fwrite(&out, sizeof(float), 1, fdi); + fwrite(" ", 1, 1, fdi); + Current++; + Total++; + + memset(&Qwk, ' ', sizeof(Qwk)); + sprintf(Temp, "%-*lu", sizeof(Qwk.Msgnum), (long)Number); + Syslog('M', "Message %s", Temp); + memcpy(Qwk.Msgnum, Temp, sizeof(Qwk.Msgnum)); + tp = localtime(&Msg.Written); + sprintf(Temp, "%02d-%02d-%02d", tp->tm_mon+1, tp->tm_mday, tp->tm_year % 100); + memcpy(Qwk.Msgdate, Temp, sizeof(Qwk.Msgdate)); + sprintf(Temp, "%02d:%02d", tp->tm_hour, tp->tm_min); + memcpy(Qwk.Msgtime, Temp, sizeof(Qwk.Msgtime)); + Msg.From[sizeof(Qwk.MsgFrom) - 1] = '\0'; + memcpy(Qwk.MsgFrom, Msg.From, strlen(Msg.From)); + Msg.To[sizeof(Qwk.MsgTo) - 1] = '\0'; + memcpy(Qwk.MsgTo, Msg.To, strlen(Msg.To)); + Msg.Subject[sizeof(Qwk.MsgSubj) - 1] = '\0'; + memcpy(Qwk.MsgSubj, Msg.Subject, strlen(Msg.Subject)); + Qwk.Msglive = 0xE1; + Qwk.Msgarealo = (unsigned char)(Area & 0xFF); + Qwk.Msgareahi = (unsigned char)((Area & 0xFF00) >> 8); + fwrite(&Qwk, sizeof(Qwk), 1, fdm); + Size = 128L; + if ((Text = (char *)MsgText_First()) != NULL) { + do { + if (Text[0] != 0x01 && strncmp(Text, "SEEN-BY: ", 9)) { + Size += fwrite(Text, 1, strlen(Text), fdm); + Size += fwrite("\xE3", 1, 1, fdm); + } + } while ((Text = (char *)MsgText_Next()) != NULL); + + if ((Size % 128L) != 0) { + memset(Temp, ' ', 128); + Size += fwrite(Temp, (int)(128L - (Size % 128L)), 1, fdm); + } + + sprintf(Qwk.Msgrecs, "%-*lu", sizeof(Qwk.Msgrecs), (long)((ftell(fdm) - Pos) / 128L)); + fseek(fdm, Pos, SEEK_SET); + fwrite(&Qwk, sizeof(Qwk), 1, fdm); + fseek(fdm, 0L, SEEK_END); + if ((Total % 16L) == 0L) + usleep(1); + } + + if (BarWidth != (unsigned short)((Total * 61L) / TotalPack)) { + BarWidth = (unsigned short)((Total * 61L) / TotalPack); + colour(3, 0); + printf("\r%.*s", BarWidth, "ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ"); + fflush(stdout); + } + } + } while (Msg_Next(&Number)); + } + } else { + WriteError("Not all files open"); + } + + if (fdm != NULL) + fclose(fdm); + if (fdi != NULL) + fclose(fdi); + if (fdp != NULL) + fclose(fdp); + free(Work); + free(Temp); + + return Number; +} + + + +char *StripSpaces(char *String, int Size) +{ + int x; + + memcpy(TempStr, String, Size); + TempStr[Size] = '\0'; + if ((x = (Size - 1)) > 0) { + while (x > 0 && TempStr[x] == ' ') + TempStr[x--] = '\0'; + } + + return TempStr; +} + + +/***************************************************************************** + * + * ASCII Offline Functions + * + */ + + +void OLR_DownASCII(void) +{ + struct tm *tp; + time_t Now; + char Pktname[32]; + long Area = 0; + char *Work, *Temp; + int rc = 0; + FILE *fp = NULL, *tf, *mf, *af; + unsigned long Start, High; + msg_high *tmp, *mhl = NULL; + + if (!OLR_Prescan()) + return; + + Total = TotalPersonal = 0L; + clear(); + colour(9, 0); + /* ASCII Offline Download */ + printf("%s\n", (char *)Language(460)); + + Work = calloc(PATH_MAX, sizeof(char)); + Temp = calloc(PATH_MAX, sizeof(char)); + + Now = time(NULL); + tp = localtime(&Now); + Syslog('+', "Preparing ASCII packet"); + + sprintf(Temp, "%s.MSG", CFG.bbsid); + sprintf(Pktname, "%s", tl(Temp)); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + + sprintf(Temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + sprintf(Temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((tf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + fclose(mf); + return; + } + + Area = 0; + DrawBar(Pktname); + fseek(mf, sizeof(msgshdr), SEEK_SET); + fseek(tf, 0, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + Current = Personal = 0; + if (Msg_Highest() != 0) { + memset(&LR, 0, sizeof(LR)); + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg; + else + Start = Msg_Lowest() -1; + if (Start > Msg_Highest()) + Start = Msg_Highest(); + if (Start < Msg_Highest()) { + High = ASCII_PackArea(Start, Area); + fill_high(&mhl, Area, High, Personal); + } + } + Syslog('+', "Area %-20s %5ld (%ld personal)", msgs.QWKname, Current, Personal); + Msg_Close(); + } + } + } + + if (Total) { + /* Packing with */ + printf("\n%s ", (char *)Language(446)); + sprintf(Temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((af = fopen(Temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, af); + while (fread(&archiver, archiverhdr.recsize, 1, af) == 1) { + if (archiver.available && (!strcmp(archiver.name, exitinfo.Archiver))) { + Syslog('+', "Archiver %s", archiver.comment); + printf("%s ", archiver.comment); + alarm_on(); + + for (tmp = mhl; tmp; tmp = tmp->next) { + sprintf(Temp, "%s/%03ld.TXT", Work, tmp->Area); + AddArc(Temp, Pktname); + } + sprintf(Temp, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, Pktname); + rc = DownloadDirect(Temp, FALSE); + unlink(Temp); + } + } + fclose(af); + } + } + + colour(CFG.HiliteF, CFG.HiliteB); + if (rc == FALSE) { + Syslog('+', "ASCII download failed"); + /* Download failed */ + printf("%s", (char *)Language(447)); + } else { + Syslog('+', "ASCII download successfull"); + /* Download successfull */ + printf("\r%s\n", (char *)Language(448)); + + if (mhl != NULL) + UpdateLR(mhl, mf); + } + fclose(mf); + tidy_high(&mhl); + free(Temp); + free(Work); + printf("\n\n"); + Pause(); +} + + + +/* + * Pack messages in one mail area + */ +unsigned long ASCII_PackArea(unsigned long ulLast, long Area) +{ + FILE *fp; + char *Work, *Temp, *Text; + unsigned long Number; + int Pack = FALSE; + struct tm *tp; + + Number = ulLast; + Current = Personal = 0L; + + Temp = calloc(128, sizeof(char)); + Work = calloc(128, sizeof(char)); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + + sprintf(Temp, "%s/%03ld.TXT", Work, Area); + if ((fp = fopen(Temp, "a+")) != NULL) { + if (Msg_Next(&Number)) { + do { + Msg_ReadHeader(Number); + Msg_Read(Number, 78); + Pack = TRUE; + if ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || + (strcasecmp(Msg.To, exitinfo.sHandle) == 0)) { + Personal++; + TotalPersonal++; + } else if (msgs.Type == NETMAIL) { + Pack = FALSE; + } else if ( msgs.MsgKinds == PRIVATE ) { + Pack = FALSE; + } else if (msgs.MsgKinds == BOTH ) { + if ( Msg.Private == TRUE ) Pack = FALSE; + } + + if (Pack) { + fprintf (fp, "\n==============================================\n Msg. #%ld of %ld (%s)\n", Number, Msg_Number(), msgs.Name); + tp = localtime(&Msg.Written); + fprintf (fp, " Date: %d %s %d %2d:%02d\n", tp->tm_mday, + GetMonth(tp->tm_mon + 1), tp->tm_year, tp->tm_hour, tp->tm_min); + fprintf (fp, " From: %s\n", Msg.From); + if (Msg.To[0]) + fprintf (fp, " To: %s\n", Msg.To); + fprintf (fp, "Subject: %s\n----------------------------------------------\n", Msg.Subject); + Current++; + Total++; + + if ((Text = (char *)MsgText_First()) != NULL) { + do { + if (Text[0] != 0x01 && strncmp(Text, "SEEN-BY: ", 9)) + fprintf(fp, "%s\n", Text); + } while ((Text = (char *)MsgText_Next()) != NULL); + } + + if ((Total % 16L) == 0L) + usleep(1); + + if (BarWidth != (unsigned short)((Total * 61L) / TotalPack)) { + BarWidth = (unsigned short)((Total * 61L) / TotalPack); + colour(3, 0); + printf("\r%.*s", BarWidth, "ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ"); + fflush(stdout); + } + } + } while (Msg_Next(&Number)); + } + fclose(fp); + } else { + WriteError("Not all files open"); + } + + free(Work); + free(Temp); + return Number; +} + + diff --git a/mbsebbs/offline.h b/mbsebbs/offline.h new file mode 100644 index 00000000..2f46002f --- /dev/null +++ b/mbsebbs/offline.h @@ -0,0 +1,52 @@ +#ifndef _OFFLINE_H +#define _OFFLINE_H + + + +/* + * Each area has a tag if the area exists, so we can check + * at login if the sysop added new areas (or deleted). This + * file is synced at login. Location: usershomedir/.olrtags + */ +struct _olrtagrec { + unsigned short Available : 1; /* Is the area available */ + unsigned short Tagged : 1; /* Is this area tagged */ + unsigned short ScanNew : 1; /* Scan for new mail */ +}; + +struct _olrtagrec olrtagrec; + + +struct _qwkhdr { + unsigned char Msgstat; /* Message status */ + unsigned char Msgnum[7]; /* Message number */ + unsigned char Msgdate[8]; /* Message date MM-DD-YY */ + unsigned char Msgtime[5]; /* Message time HH:MM */ + unsigned char MsgTo[25]; /* Message To: */ + unsigned char MsgFrom[25]; /* Message From: */ + unsigned char MsgSubj[25]; /* Message Subject: */ + unsigned char Msgpass[12]; /* Message password */ + unsigned char Msgrply[8]; /* Message reply to */ + unsigned char Msgrecs[6]; /* Length in records */ + unsigned char Msglive; /* Message active status */ + unsigned char Msgarealo; /* Lo-byte message area */ + unsigned char Msgareahi; /* Hi-byte message area */ + unsigned char Msgfiller[3]; /* Filler bytes */ +}; + +struct _qwkhdr Qwk; + + +void OLR_TagArea(void); /* Tag area(s) */ +void OLR_UntagArea(void); /* Untag area(s) */ +void OLR_SyncTags(void); /* Sync tag/msg area(s) */ +void OLR_ViewTags(void); /* View tagged areas */ +void OLR_Upload(void); /* Upload mail packet */ +void OLR_RestrictDate(void); /* Restrict download date */ +void OLR_DownBW(void); /* Download BlueWave format */ +void OLR_DownQWK(void); /* Download QWK format */ +void OLR_DownASCII(void); /* Download ASCII format */ + + +#endif + diff --git a/mbsebbs/oneline.c b/mbsebbs/oneline.c new file mode 100644 index 00000000..149c41e1 --- /dev/null +++ b/mbsebbs/oneline.c @@ -0,0 +1,447 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/oneline.c + * Purpose ...............: Oneliner functions. + * Last modification date : 28-jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "oneline.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" + + +char sOneliner[81]; +int iColour; /* Current color */ + + +void Oneliner_Check() +{ + FILE *pOneline; + char *sFileName; + + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if ((pOneline = fopen(sFileName, "r")) == NULL) { + if ((pOneline = fopen(sFileName, "w")) != NULL) { + olhdr.hdrsize = sizeof(olhdr); + olhdr.recsize = sizeof(ol); + fwrite(&olhdr, sizeof(olhdr), 1, pOneline); + fclose(pOneline); + Syslog('-', "Created oneliner database"); + } + } + free(sFileName); +} + + + +void Oneliner_Add() +{ + FILE *pOneline; + char *sFileName; + int x; + char temp[81]; + + Oneliner_Check(); + + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "a+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return; + } + free(sFileName); + + memset(&ol, 0, sizeof(ol)); + clear(); + /* MBSE BBS Oneliners will randomly appear on the main menu. */ + poutCR(15, 0, Language(341)); + Enter(1); + + /* Obscene or libellous oneliners will be deleted!! */ + poutCR(15, 1, Language(342)); + Enter(1); + + /* Please enter your oneliner below. You have 75 characters.*/ + pout(12, 0, Language(343)); + Enter(1); + pout(15, 0, (char *)"> "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(temp, 75); + + if((strcmp(temp, "")) == 0) { + fclose(pOneline); + return; + } else { + x = strlen(temp); + if(x >= 78) + temp[78] = '\0'; + + strcpy(ol.Oneline, temp); + } + + Enter(1); + /* Oneliner added */ + pout(3, 0, Language(344)); + Enter(2); + Pause(); + + Syslog('!', "User added oneliner:"); + Syslog('!', ol.Oneline); + + sprintf(ol.UserName,"%s", exitinfo.sUserName); + sprintf(ol.DateOfEntry,"%02d-%02d-%04d",l_date->tm_mday,l_date->tm_mon+1,l_date->tm_year+1900); + ol.Available = TRUE; + + fwrite(&ol, sizeof(ol), 1, pOneline); + fclose(pOneline); +} + + + + +/* + * Print global string sOneliner centered on the screen + */ +void Oneliner_Print() +{ + int i, x, z; + int Strlen; + int Maxlen = 80; + char sNewOneliner[81] = ""; + + /* + * Select a new colour + */ + if (iColour < 8) + iColour = 8; + else + if (iColour == 15) + iColour = 8; + else + iColour++; + + /* + * Get a random oneliner + */ + strcpy(sOneliner, Oneliner_Get()); + + /* + * Now display it on screen + */ + Strlen = strlen(sOneliner); + + if(Strlen == Maxlen) + printf("%s\n", sOneliner); + else { + x = Maxlen - Strlen; + z = x / 2; + for(i = 0; i < z; i++) + strcat(sNewOneliner," "); + strcat(sNewOneliner, sOneliner); + colour(iColour, 0); + printf("%s\n", sNewOneliner); + } +} + + + +/* + * Get a random oneliner + */ +char *Oneliner_Get() +{ + FILE *pOneline; + int i, j, in, id; + int recno = 0; + long offset; + int nrecno; + char *sFileName; + static char temp[81]; + + /* + * Get a random oneliner + */ + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return '\0'; + } + fread(&olhdr, sizeof(olhdr), 1, pOneline); + + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + recno++; + } + nrecno = recno; + fseek(pOneline, olhdr.hdrsize, 0); + + /* + * Generate random record number + */ + while (TRUE) { + in = nrecno; + id = getpid(); + + i = rand(); + j = i % id; + if ((j <= in)) + break; + } + + offset = olhdr.hdrsize + (j * olhdr.recsize); + if (fseek(pOneline, offset, 0) != 0) { + WriteError("Can't move pointer in %s", sFileName); + return '\0'; + } + + fread(&ol, olhdr.recsize, 1, pOneline); + memset(&temp, 0, sizeof(temp)); + strcpy(temp, ol.Oneline); + fclose(pOneline); + free(sFileName); + return temp; +} + + + +/* + * List Oneliners + */ +void Oneliner_List() +{ + FILE *pOneline; + int recno = 0; + int Colour = 1; + char *sFileName; + + clear(); + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return; + } + fread(&olhdr, sizeof(olhdr), 1, pOneline); + + if((SYSOP == TRUE) || (exitinfo.Security.level >= CFG.sysop_access)) { + /* # A Date User Description */ + pout(10, 0, Language(345)); + Enter(1); + } else { + /* # Description */ + pout(10, 0, Language(346)); + Enter(1); + } + colour(2, 0); + sLine(); + + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + if((SYSOP == TRUE) || (exitinfo.Security.level >= CFG.sysop_access)) { + colour(15, 0); + printf("%2d", recno); + + colour(9, 0); + printf("%2d ", ol.Available); + + colour(11, 0); + printf("%s ", ol.DateOfEntry); + + colour(3, 0); + printf("%-15s ", ol.UserName); + + colour(Colour, 0); + printf("%-.48s\n", ol.Oneline); + } else { + colour(15, 0); + printf("%2d ", recno); + colour(Colour, 0); + printf("%-.76s\n", ol.Oneline); + } + + recno++; + Colour++; + if(Colour >= 16) + Colour = 1; + } + fclose(pOneline); + printf("\n"); + Pause(); + free(sFileName); +} + + + +void Oneliner_Show() +{ + FILE *pOneline; + int recno = 0; + long offset; + char *sFileName; + + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return; + } + fread(&olhdr, sizeof(olhdr), 1, pOneline); + + Enter(1); + /* Please enter number to list: */ + pout(15, 0, Language(347)); + colour(CFG.InputColourF, CFG.InputColourB); + scanf("%d", &recno); + + offset = olhdr.hdrsize + (recno * olhdr.recsize); + if (fseek(pOneline, offset, 0) != 0) + WriteError("Can't move pointer in %s",sFileName); + + fread(&ol, olhdr.recsize, 1, pOneline); + + colour(15, 0); + printf("\n%d ", recno); + colour(12, 0); + printf("%s\n\n", ol.Oneline); + + Pause(); + fclose(pOneline); + free(sFileName); +} + + + +void Oneliner_Delete() +{ + FILE *pOneline; + int recno = 0; + long offset; + int nrecno = 0; + char srecno[7]; + char *sFileName; + char stemp[50]; + char sUser[35]; + + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return; + } + fread(&olhdr, sizeof(olhdr), 1, pOneline); + + Enter(1); + /* Please enter number to delete: */ + pout(15, 0, Language(331)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(srecno, 6); + + if((strcmp(srecno,"")) == 0) { + fclose(pOneline); + return; + } + + recno = atoi(srecno); + + nrecno = recno; + recno = 0; + + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + recno++; + } + + if(nrecno >= recno) { + Enter(1); + /* Record does not exist */ + pout(12, 0, Language(319)); + Enter(2); + fclose(pOneline); + Pause(); + } else { + offset = olhdr.hdrsize + (nrecno * olhdr.recsize); + if (fseek(pOneline, offset, 0) != 0) { + WriteError("Can't move pointer in %s",sFileName); + } + + fread(&ol, olhdr.recsize, 1, pOneline); + + /* Convert Record Int to string, so we can print to logfiles */ + sprintf(stemp,"%d", nrecno); + + /* Print UserName to String, so we can compare for deletion */ + sprintf(sUser,"%s", exitinfo.sUserName); + + if((strcmp(sUser, ol.UserName)) != 0) { + if((!SYSOP) && (exitinfo.Security.level < CFG.sysop_access)) { + colour(12, 0); + /* Record *//* does not belong to you.*/ + printf("\n%s%s %s\n\n", (char *) Language(332), stemp, (char *) Language(333)); + Syslog('!', "User tried to delete somebody else's record: %s", stemp); + Pause(); + fclose(pOneline); + return; + } + } + + if ((ol.Available ) == FALSE) { + colour(12, 0); + /* Record: %d already marked for deletion */ + printf("\n%s%d %s\n\n", (char *) Language(332), nrecno, (char *) Language(334)); + Syslog('!', "User tried to mark an already marked record: %s", stemp); + Pause(); + } else { + ol.Available = FALSE; + colour(10, 0); + /* Record *//* marked for deletion */ + printf("\n%s%d %s\n\n", (char *) Language(332), nrecno, (char *) Language(334)); + Syslog('+', "User marked oneliner record for deletion: %s", stemp); + Pause(); + } + + if (fseek(pOneline, offset, 0) != 0) + WriteError("Can't move pointer in %s",sFileName); + fwrite(&ol, olhdr.recsize, 1, pOneline); + } + fclose(pOneline); + free(sFileName); +} + + diff --git a/mbsebbs/oneline.h b/mbsebbs/oneline.h new file mode 100644 index 00000000..8d926e68 --- /dev/null +++ b/mbsebbs/oneline.h @@ -0,0 +1,13 @@ +#ifndef _ONELINE_H +#define _ONELINE_H + +void Oneliner_Check(void); /* Check if database exists, creates new */ +void Oneliner_Add(void); /* Add oneliner */ +void Oneliner_Print(void); /* Print a oneliner centered at the screen */ +char *Oneliner_Get(void); /* Get a random oneliner */ +void Oneliner_List(void); /* List Oneliners */ +void Oneliner_Show(void); +void Oneliner_Delete(void); + +#endif + diff --git a/mbsebbs/page.c b/mbsebbs/page.c new file mode 100644 index 00000000..a4e53250 --- /dev/null +++ b/mbsebbs/page.c @@ -0,0 +1,296 @@ +/***************************************************************************** + * + * File ..................: bbs/page.c + * Purpose ...............: Sysop Paging + * Last modification date : 28-Jun-2001 + * Todo ..................: Implement new config settings. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "funcs.h" +#include "funcs4.h" +#include "chat.h" +#include "page.h" +#include "timeout.h" +#include "mail.h" +#include "language.h" + + +/* + * Function to Page Sysop + */ +void Page_Sysop(char *String) +{ + int i; + FILE *pWritingDevice, *pBusy; + int iOpenDevice = FALSE; /* Flag to check if you can write to CFG.sChatDevice */ + char *Reason; + char temp[81]; + + Reason = calloc(81, sizeof(char)); + + clear(); + colour(12, 0); + /* MBSE BBS Chat */ + Center((char *) Language(151)); + + if (CFG.iAskReason) { + locate(6, 0); + colour(1, 0); + printf("%c", 213); + for(i = 0; i < 78; i++) + printf("%c", 205); + printf("%c ", 184); + + colour(7, 0); + for(i = 0; i < 78; i++) + printf("%c", 250); + printf("\n"); + + colour(1, 0); + printf("%c", 212); + for(i = 0; i < 78; i++) + printf("%c", 205); + printf("%c\n", 190); + + locate(7, 2); + + colour(7, 0); + fflush(stdout); + GetPageStr(temp, 76); + + colour(1, 0); + printf("%c", 212); + for(i = 0; i < 78; i++) + printf("%c", 205); + printf("%c\n", 190); + + if((strcmp(temp, "")) == 0) + return; + + Syslog('+', "Chat Reason: %s", temp); + strcpy(Reason, temp); + } + + if (access("/tmp/.BusyChatting", F_OK) == 0) { + if((pBusy = fopen("/tmp/.BusyChatting", "r")) == NULL) + WriteError("Unable to open BusyChatting file", pTTY); + else { + fscanf(pBusy, "%10s", temp); + fclose(pBusy); + } + colour(13, 0); + printf("%s%s\n", (char *) Language(152), temp); + pout(10, 0, (char *) Language(153)); + Enter(2); + Syslog('+', "SysOp was busy chatting to user on %s", temp); + Pause(); + free(Reason); + return; + } + + CFG.iMaxPageTimes--; + + if(CFG.iMaxPageTimes <= 0) { + if (!DisplayFile((char *)"maxpage")) { + /* If i is FALSE display hard coded message */ + Enter(1); + pout(15, 0, (char *) Language(154)); + Enter(2); + } + + Syslog('!', "Attempted to page Sysop, above maximum page limit."); + Pause(); + } else { + locate(14, ((80 - strlen(String) ) / 2 - 2)); + pout(15, 0, (char *)"["); + pout(7, 0, String); + pout(15, 0, (char *)"]"); + + locate(16, ((80 - CFG.iPageLength) / 2 - 2)); + pout(15, 0, (char *)"["); + colour(1, 0); + for(i = 0; i < CFG.iPageLength; i++) + printf("%c", 176); + pout(15, 0, (char *)"]"); + + locate(16, ((80 - CFG.iPageLength) / 2 - 2) + 1); + + if((pWritingDevice = fopen(CFG.sChatDevice, "w")) != NULL) { + fprintf(pWritingDevice, "\n\n\n%s is trying to page you on %s.\n", \ + usrconfig.sUserName, pTTY); + + fprintf(pWritingDevice, "Type: '%s/bin/schat %s' to talk to him, you have", \ + getenv("MBSE_ROOT"), pTTY); + fprintf(pWritingDevice, "\n%d seconds to respond!\n\n", CFG.iPageLength); + fprintf(pWritingDevice, "%s\n", temp); + iOpenDevice = TRUE; + } + + colour(9, 0); + for(i = 0; i < CFG.iPageLength; i++) { + printf("\x07"); + /* If there weren't any problems opening the writing device */ + if(iOpenDevice) + fprintf(pWritingDevice, "\x07"); + printf("%c", 219); + fflush(pWritingDevice); + fflush(stdout); + sleep(1); + if(access("/tmp/chatdev", R_OK) == 0) { + fclose(pWritingDevice); + Chat(); + free(Reason); + return; + } + } + + fclose(pWritingDevice); + PageReason(); + printf("\n\n\n"); + if (strlen(Reason)) + SysopComment(Reason); + else + SysopComment((char *)"Failed chat"); + } + + free(Reason); + Pause(); +} + + + +/* + * Function gets string from user for Pager Function + */ +void GetPageStr(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + if ((ttyfd = open ("/dev/tty", O_RDWR)) < 0) { + perror("open 6"); + return; + } + Setraw(); + + strcpy(sStr, ""); + + alarm_on(); + while (ch != 13) { + ch = Readkey(); + + if (((ch == 8) || (ch == KEY_DEL) || (ch == 127)) && (iPos > 0)) { + printf("\b%c\b", 250); + fflush(stdout); + sStr[--iPos]='\0'; + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + fflush(stdout); + } else + ch=13; + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Function gets page reason from a file in the txtfiles directory + * randomly generates a number and prints the string to the screen + */ +void PageReason() +{ + FILE *Page; + int iLoop = FALSE, id, i, j = 0; + int Lines = 0, Count = 0, iFoundString = FALSE; + char *String; + char *temp; + + temp = calloc(128, sizeof(char)); + String = calloc(81, sizeof(char)); + + sprintf(temp, "%s/page.asc", CFG.bbs_txtfiles); + if(( Page = fopen(temp, "r")) != NULL) { + + while (( fgets(String, 80 ,Page)) != NULL) + Lines++; + + rewind(Page); + + Count = Lines; + id = getpid(); + do { + i = rand(); + j = i % id; + if ((j <= Count) && (j != 0)) + iLoop = 1; + } while (!iLoop); + + Lines = 0; + + while (( fgets(String,80,Page)) != NULL) { + if(Lines == j) { + Striplf(String); + locate(18, ((78 - strlen(String) ) / 2)); + pout(15, 0, (char *)"["); + pout(9, 0, String); + pout(15, 0, (char *)"]"); + iFoundString = TRUE; + } + + Lines++; /* Increment Lines until correct line is found */ + } + } /* End of Else */ + + if(!iFoundString) { + /* Sysop currently is not available ... please leave a comment */ + sprintf(String, "%s", (char *) Language(155)); + locate(18, ((78 - strlen(String) ) / 2)); + pout(15, 0, (char *)"["); + pout(9, 0, String); + pout(15, 0, (char *)"]"); + } + + free(temp); + free(String); +} + diff --git a/mbsebbs/page.h b/mbsebbs/page.h new file mode 100644 index 00000000..52e4318a --- /dev/null +++ b/mbsebbs/page.h @@ -0,0 +1,13 @@ +/* page.h */ + +#ifndef _PAGE_H +#define _PAHE_H + + +void Page_Sysop(char *); /* Sysop Pager */ +void GetPageStr(char *, int); /* Get String for Pager from User */ +void PageReason(void); /* Get Page Reason and Print String */ + + +#endif + diff --git a/mbsebbs/pinfo.c b/mbsebbs/pinfo.c new file mode 100644 index 00000000..d69715e6 --- /dev/null +++ b/mbsebbs/pinfo.c @@ -0,0 +1,159 @@ +/***************************************************************************** + * + * File ..................: bbs/pinfo.c + * Purpose ...............: Product information + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "funcs4.h" + + + +void ls(int a) +{ + printf("%c ", a ? 179 : '|'); +} + + + +void rs(int a) +{ + colour(8, 0); + printf("%c\n", a ? 179 : '|'); +} + + + +void wl(int a) +{ + int i; + + ls(a); + for(i = 0; i < 76; i++) + printf(" "); + rs(a); +} + + + +/* + * Product information screen + */ +void cr(void) +{ + int a, i; + char *string, *temp; + + a = exitinfo.GraphMode; + + string = calloc(81, sizeof(char)); + temp = calloc(81, sizeof(char)); + + clear(); + colour(8, 0); + + /* Print top row */ + printf("%c", a ? 213 : '+'); + for(i = 0; i < 77; i++) + printf("%c", a ? 205 : '='); + printf("%c\n", a ? 184 : '+'); + + wl(a); + + ls(a); + sprintf(temp, "MBSE Bulletin Board System %s Linux Pro", VERSION); + pout(14, 0, padleft(temp, 76, ' ')); + rs(a); + + wl(a); + + ls(a); + sprintf(temp, "%s", Copyright); + pout(11, 0, padleft(temp, 76, ' ')); + rs(a); + + wl(a); + + ls(a); + sprintf(temp, "Compiled on %s at %s", __DATE__, __TIME__); + pout(14, 0, padleft(temp, 76, ' ')); + rs(a); + + wl(a); + + ls(a); + pout(11, 0, (char *)"MBSE has been written and designed by Michiel Broek. Many others have given "); + rs(a); + + ls(a); + pout(11, 0, (char *)"valuable time in the form of new ideas and suggestions on how to make MBSE "); + rs(a); + + ls(a); + pout(11, 0, (char *)"BBS a better BBS "); + rs(a); + + wl(a); + + ls(a); + pout(12, 0, (char *)"JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner, "); + rs(a); + + ls(a); + pout(12, 0, (char *)" Mats Birch, Mats Wallin. "); + rs(a); + + ls(a); + pout(12, 0, (char *)" ALL RIGHTS RESERVED. "); + rs(a); + + wl(a); + + ls(a); + pout(9, 0, (char *)"Special thanks to Steven Wishart who wrote RapidBBS "); + rs(a); + + wl(a); + + printf("%c", a ? 212 : '+'); + for(i = 0; i < 77; i++) + printf("%c", a ? 205 : '='); + printf("%c", a ? 190 : '+'); + + free(string); + free(temp); + printf("\n"); + Pause(); +} + + diff --git a/mbsebbs/pinfo.h b/mbsebbs/pinfo.h new file mode 100644 index 00000000..79a49247 --- /dev/null +++ b/mbsebbs/pinfo.h @@ -0,0 +1,9 @@ +#ifndef _PINFO_H +#define _PINFO_H + +void ls(int); /* Left side of block */ +void rs(int); /* Right side of block */ +void cr(void); /* Show product info screen */ + +#endif + diff --git a/mbsebbs/pop3.c b/mbsebbs/pop3.c new file mode 100644 index 00000000..a98e8481 --- /dev/null +++ b/mbsebbs/pop3.c @@ -0,0 +1,212 @@ +/***************************************************************************** + * + * File ..................: bbs/pop3.c + * Purpose ...............: POP3 client + * Last modification date : 13-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "msgutil.h" +#include "pop3.h" + + + +void error_popmail(char *); +void error_popmail(char *umsg) +{ + char *p; + + pop3_send((char *)"QUIT\r\n"); + p = pop3_receive(); + pop3_close(); + colour(12, 0); + printf("%s\r\n", umsg); + fflush(stdout); +} + + + +void retr_msg(int); +void retr_msg(int msgnum) +{ + char *p, *q, temp[128]; + int Header; + unsigned long crc = -1; + + sprintf(temp, "RETR %d\r\n", msgnum); + if (pop3_cmd(temp) == 0) { + Msg_New(); + Header = TRUE; + sprintf(temp, "%s/%s/mailbox", CFG.bbs_usersdir, exitinfo.Name); + Open_Msgbase(temp, 'w'); + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Private = TRUE; + while (TRUE) { + p = pop3_receive(); + if ((p[0] == '.') && (strlen(p) == 1)) { + break; + } else { + if (Header) { + /* + * Check the primary message header lines. + */ + if (strncmp(p, "To: ", 4) == 0) { + if (strlen(p) > 104) + p[104] = '\0'; + sprintf(Msg.To, "%s", p+4); + } + if (strncmp(p, "From: ", 6) == 0) { + if (strlen(p) > 106) + p[106] = '\0'; + sprintf(Msg.From, "%s", p+6); + } + if (strncmp(p, "Subject: ", 9) == 0) { + if (strlen(p) > 109) + p[109] = '\0'; + sprintf(Msg.Subject, "%s", p+9); + } + if (strncmp(p, "Date: ", 6) == 0) + Msg.Written = parsedate(p+6, NULL) - (gmt_offset((time_t)0) * 60); + if (strncmp(p, "Message-Id: ", 12) == 0) { + q = xstrcpy(p+12); + Msg.MsgIdCRC = upd_crc32(q, crc, strlen(q)); + free(q); + } + Msg.ReplyCRC = 0xffffffff; + if (strlen(p) == 0) { + Header = FALSE; + } else { + sprintf(temp, "\001%s", p); + MsgText_Add2(temp); + } + } else { + MsgText_Add2(p); + } + } + } + Msg_AddMsg(); + Msg_UnLock(); + Msg_Close(); + sprintf(temp, "DELE %d\r\n", msgnum); + pop3_cmd(temp); + } else { + WriteError("POP3: Can't retrieve message %d", msgnum); + } +} + + + +void check_popmail(char *user, char *pass) +{ + char *p, *q, temp[128]; + int tmsgs = 0, size, msgnum, color = 9; + FILE *tp; + + /* + * If nothing is retrieved from the POP3 mailbox, the user sees nothing. + */ + Syslog('+', "POP3: connect user %s", user); + if (pop3_connect() == -1) { + WriteError("Can't connect POP3 server"); + return; + } + + sprintf(temp, "USER %s\r\n", user); + if (pop3_cmd(temp)) { + error_popmail((char *)"You have no email box"); + return; + } + + sprintf(temp, "PASS %s\r\n", pass); + if (pop3_cmd(temp)) { + error_popmail((char *)"Wrong email password, reset your password"); + return; + } + + Syslog('+', "POP3: logged in"); + + pop3_send((char *)"STAT\r\n"); + p = pop3_receive(); + if (strncmp(p, "+OK", 3) == 0) { + q = strtok(p, " "); + q = strtok(NULL, " "); + tmsgs = atoi(q); + q = strtok(NULL, " \r\n\0"); + size = atoi(q); + Syslog('+', "POP3: %d messages, %d bytes", tmsgs, size); + if (tmsgs && ((tp = tmpfile()) != NULL)) { + if (pop3_cmd((char *)"LIST\r\n") == 0) { + while (TRUE) { + p = pop3_receive(); + if (p[0] == '.') { + break; + } else { + q = strtok(p, " "); + msgnum = atoi(q); + fwrite(&msgnum, sizeof(msgnum), 1, tp); + } + } + rewind(tp); + while (fread(&msgnum, sizeof(msgnum), 1, tp) == 1) { + /* + * Show progress + */ + colour(color, 0); + printf("\rFetching message %02d/%02d, total %d bytes", msgnum, tmsgs, size); + fflush(stdout); + if (color < 15) + color++; + else + color = 9; + retr_msg(msgnum); + } + fclose(tp); + } + } + fflush(stdout); + } + + pop3_cmd((char *)"QUIT\r\n"); + pop3_close(); + + if (tmsgs) { + colour(13, 0); + printf("\r \r"); + fflush(stdout); + } +} + + + diff --git a/mbsebbs/pop3.h b/mbsebbs/pop3.h new file mode 100644 index 00000000..ecf0dc01 --- /dev/null +++ b/mbsebbs/pop3.h @@ -0,0 +1,9 @@ +#ifndef _POP3_H +#define _POP3_H + + +void check_popmail(char *, char *); + + +#endif + diff --git a/mbsebbs/pwcheck.c b/mbsebbs/pwcheck.c new file mode 100644 index 00000000..9fce8492 --- /dev/null +++ b/mbsebbs/pwcheck.c @@ -0,0 +1,108 @@ +/***************************************************************************** + * + * File ..................: bbs/pwcheck.c + * Purpose ...............: Password checking routines + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "pwcheck.h" +#include "funcs4.h" +#include "timeout.h" + + +/* + * Open up /dev/tty to get the password from the user + * because this is done in raw mode, it makes life a bit + * more difficult. + * This function gets a password from a user, upto CFG.max_passlen set above + */ +int Getpass(char *theword) +{ + unsigned char c = 0; + int counter = 0; + char password[Max_passlen+1]; + + /* + * Open the device that we want to read the password from, you can't use + * stdin as this might change in a pipe + */ + if ((ttyfd = open ("/dev/tty", O_RDWR)) < 0) { + perror("open 7"); + ExitClient(1); + } + + /* Set Raw mode so that the characters don't echo */ + Setraw(); + alarm_on(); + + /* + * Till the user presses ENTER or reaches the maximum length allowed + */ + while ((c != 13) && (counter < Max_passlen )) { + c = Readkey(); /* Reads a character from the raw device */ + + if (((c == 8) || (c == KEY_DEL) || (c == 127)) && (counter != 0 )) { /* If its a BACKSPACE */ + counter--; + password[counter] = '\0'; + printf("\x008 \x008"); + fflush(stdout); + continue; + } /* Backtrack to fix the BACKSPACE */ + + if (((c == 8) || (c == KEY_DEL) || (c == 127)) && (counter == 0) ) { + printf("\x007"); + fflush(stdout); + continue; + } /* Don't Backtrack as we are at the begining of the passwd field */ + + password[counter] = c; + counter++; + + if (c > 32 && c < 127) { /* If its a normal character, display a . */ + printf("%c", CFG.iPasswd_Char); + fflush(stdout); + } + } + Unsetraw(); /* Go normal */ + close(ttyfd); + + if (counter == Max_passlen) + password[counter] = '\0'; /* Make sure the string has a NULL at the end*/ + else + password[counter-1] ='\0'; + strcpy(theword,password); + + return(0); +} + + diff --git a/mbsebbs/pwcheck.h b/mbsebbs/pwcheck.h new file mode 100644 index 00000000..b0b7f050 --- /dev/null +++ b/mbsebbs/pwcheck.h @@ -0,0 +1,8 @@ +#ifndef _PWCHECK_H +#define _PWCHECK_H + + +int Getpass(char *); + +#endif + diff --git a/mbsebbs/pwio.c b/mbsebbs/pwio.c new file mode 100644 index 00000000..bd8cd640 --- /dev/null +++ b/mbsebbs/pwio.c @@ -0,0 +1,249 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/pwio.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 18-Sep-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "sgetpwent.h" +#include "commonio.h" +#include "pwio.h" + + + + + +struct passwd *__pw_dup(const struct passwd *pwent) +{ + struct passwd *pw; + + if (!(pw = (struct passwd *) malloc(sizeof *pw))) + return NULL; + *pw = *pwent; + if (!(pw->pw_name = strdup(pwent->pw_name))) + return NULL; + if (!(pw->pw_passwd = strdup(pwent->pw_passwd))) + return NULL; +#ifdef ATT_AGE + if (!(pw->pw_age = strdup(pwent->pw_age))) + return NULL; +#endif +#ifdef ATT_COMMENT + if (!(pw->pw_comment = strdup(pwent->pw_comment))) + return NULL; +#endif + if (!(pw->pw_gecos = strdup(pwent->pw_gecos))) + return NULL; + if (!(pw->pw_dir = strdup(pwent->pw_dir))) + return NULL; + if (!(pw->pw_shell = strdup(pwent->pw_shell))) + return NULL; + return pw; +} + + + +static void *passwd_dup(const void *ent) +{ + const struct passwd *pw = ent; + return __pw_dup(pw); +} + + + +static void passwd_free(void *ent) +{ + struct passwd *pw = ent; + + free(pw->pw_name); + free(pw->pw_passwd); +#ifdef ATT_AGE + free(pw->pw_age); +#endif +#ifdef ATT_COMMENT + free(pw->pw_comment); +#endif + free(pw->pw_gecos); + free(pw->pw_dir); + free(pw->pw_shell); + free(pw); +} + + + +static const char *passwd_getname(const void *ent) +{ + const struct passwd *pw = ent; + return pw->pw_name; +} + + + +static void *passwd_parse(const char *line) +{ + return (void *) sgetpwent(line); +} + + + +static int passwd_put(const void *ent, FILE *file) +{ + const struct passwd *pw = ent; + return (putpwent(pw, file) == -1) ? -1 : 0; +} + + + +static struct commonio_ops passwd_ops = { + passwd_dup, + passwd_free, + passwd_getname, + passwd_parse, + passwd_put, + fgets, + fputs +}; + + + +static struct commonio_db passwd_db = { + "/etc/passwd", + &passwd_ops, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0 +}; + + + +int pw_name(const char *filename) +{ + return commonio_setname(&passwd_db, filename); +} + + + +int pw_lock(void) +{ + return commonio_lock(&passwd_db); +} + + + +int pw_lock_first(void) +{ + return commonio_lock_first(&passwd_db); +} + + + +int pw_open(int mode) +{ + return commonio_open(&passwd_db, mode); +} + + + +const struct passwd *pw_locate(const char *name) +{ + return commonio_locate(&passwd_db, name); +} + + + +int pw_update(const struct passwd *pw) +{ + return commonio_update(&passwd_db, (const void *) pw); +} + + + +int pw_remove(const char *name) +{ + return commonio_remove(&passwd_db, name); +} + + + +int pw_rewind(void) +{ + return commonio_rewind(&passwd_db); +} + + + +const struct passwd *pw_next(void) +{ + return commonio_next(&passwd_db); +} + + + +int pw_close(void) +{ + return commonio_close(&passwd_db); +} + + + +int pw_unlock(void) +{ + return commonio_unlock(&passwd_db); +} + + + +struct commonio_entry *__pw_get_head(void) +{ + return passwd_db.head; +} + + + +void __pw_del_entry(const struct commonio_entry *ent) +{ + commonio_del_entry(&passwd_db, ent); +} + + diff --git a/mbsebbs/pwio.h b/mbsebbs/pwio.h new file mode 100644 index 00000000..f21b263b --- /dev/null +++ b/mbsebbs/pwio.h @@ -0,0 +1,19 @@ +#ifndef _PWIO_H +#define _PWIO_H + +struct passwd *__pw_dup (const struct passwd *); +void __pw_set_changed (void); +int pw_close (void); +const struct passwd *pw_locate (const char *); +int pw_lock (void); +int pw_lock_first (void); +int pw_name (const char *); +const struct passwd *pw_next (void); +int pw_open (int); +int pw_remove (const char *); +int pw_rewind (void); +int pw_unlock (void); +int pw_update (const struct passwd *); + +#endif + diff --git a/mbsebbs/rad64.c b/mbsebbs/rad64.c new file mode 100644 index 00000000..991f37a0 --- /dev/null +++ b/mbsebbs/rad64.c @@ -0,0 +1,157 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/rad64c.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 25-Sep-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * Copyright 1989 - 1992, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "../config.h" +#include "rad64.h" + + +#ifndef HAVE_C64I +/* + * c64i - convert a radix 64 character to an integer + */ +int c64i(char c) +{ + if (c == '.') + return (0); + + if (c == '/') + return (1); + + if (c >= '0' && c <= '9') + return (c - '0' + 2); + + if (c >= 'A' && c <= 'Z') + return (c - 'A' + 12); + + if (c >= 'a' && c <= 'z') + return (c - 'a' + 38); + else + return (-1); +} + + + +/* + * i64c - convert an integer to a radix 64 character + */ +int i64c(int i) +{ + if (i <= 0) + return ('.'); + + if (i == 1) + return ('/'); + + if (i >= 2 && i < 12) + return ('0' - 2 + i); + + if (i >= 12 && i < 38) + return ('A' - 12 + i); + + if (i >= 38 && i < 63) + return ('a' - 38 + i); + + return ('z'); +} +#endif + + +#ifndef HAVE_A64L +/* + * l64a - convert a long to a string of radix 64 characters + */ +char *l64a(long l) +{ + static char buf[8]; + int i = 0; + + if (l < 0L) + return ((char *) 0); + + do { + buf[i++] = i64c ((int) (l % 64)); + buf[i] = '\0'; + } while (l /= 64L, l > 0 && i < 6); + + return (buf); +} + + + +/* + * a64l - convert a radix 64 string to a long integer + */ +long a64l(const char *s) +{ + int i; + long value; + long shift = 0; + + for (i = 0, value = 0L;i < 6 && *s;s++) { + value += (c64i (*s) << shift); + shift += 6; + } + return (value); +} + +#endif /* !HAVE_A64L */ + diff --git a/mbsebbs/rad64.h b/mbsebbs/rad64.h new file mode 100644 index 00000000..3391cafb --- /dev/null +++ b/mbsebbs/rad64.h @@ -0,0 +1,15 @@ +#ifndef _RAD64_H +#define _RAD64_H + + +#ifndef HAVE_C64I +int c64i(char); +int i64c(int); +#endif +#ifndef HAVE_A64L +char *l64a(long); +long a64l(const char *); +#endif + +#endif + diff --git a/mbsebbs/safe.c b/mbsebbs/safe.c new file mode 100644 index 00000000..86d38e67 --- /dev/null +++ b/mbsebbs/safe.c @@ -0,0 +1,457 @@ +/***************************************************************************** + * + * File ..................: bbs/safe.c + * Purpose ...............: Safe Door + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "exitinfo.h" +#include "funcs.h" +#include "funcs4.h" +#include "misc.h" +#include "safe.h" +#include "timeout.h" +#include "language.h" + + + +FILE *pSafe; + +int iLoop, iFirst, iSecond, iThird; +char sFirst[4], sSecond[4], sThird[4]; + + +int getdigits(void); +int SafeCheckUser(void); + + + +void Safe(void) +{ + long isize; + int i; + + isize = sizeof(int); + srand(Time_Now); + + WhosDoingWhat(SAFE); + + Syslog('+', "User starts Safe Cracker Door"); + + Enter(1); + /* Safe Cracker Door */ + pout(15, 0, (char *) Language(86)); + Enter(1); + + clear(); + + DisplayFile(CFG.sSafeWelcome); + + if (SafeCheckUser() == TRUE) + return; + + /* In the safe lies */ + pout(15, 0, (char *) Language(87)); + + fflush(stdout); + alarm_on(); + Getone(); + + clear(); + + Enter(2); + pout(10, 0, (char *) Language(88)); + Enter(2); + + colour(13, 0); + printf("%s", CFG.sSafePrize); + + Enter(2); + /* Do you want to open the safe ? [Y/n]: */ + pout(15, 0, (char *) Language(102)); + + fflush(stdout); + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(102, 1)) { + Syslog('+', "User exited Safe Cracker Door"); + return; + } + + /* + * Loop until the safe is opened, maximum trys + * exceeded or the user is tired of this door. + */ + while (TRUE) { + /* Get digits, TRUE if safe cracked. */ + if (getdigits() == TRUE) + break; + + Enter(1); + /* Do you want to try again ? [Y/n]: */ + pout(12, 0, (char *) Language(101)); + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + if (i == Keystroke(101, 1)) + break; + + if (SafeCheckUser() == TRUE) + break; + } + Syslog('+', "User exited Safe Cracker Door"); +} + + + +/* + * Ask use for digits, returns TRUE if the safe is cracked. + */ +int getdigits(void) +{ + long result; + int i; + char temp[81]; + + colour(15, 0); + /* Please enter three numbers consisting from 1 to */ + printf("\n\n%s%d\n", (char *) Language(89), CFG.iSafeMaxNumber); + /* Please enter three combinations. */ + printf("%s", (char *) Language(90)); + + while (TRUE) { + Enter(2); + /* 1st Digit */ + pout(12, 0, (char *) Language(91)); + colour(9, 0); + fflush(stdout); + Getnum(sFirst, 2); + sprintf(temp, "1st: %s", sFirst); + if((strcmp(sFirst, "")) != 0) { + Syslog('-', temp); + iFirst=atoi(sFirst); + } + + if((iFirst > CFG.iSafeMaxNumber) || (iFirst <= 0) || (strcmp(sFirst, "") == 0)) { + colour(15,1); + /* Please try again! You must input a number greater than Zero and less than */ + printf("\n%s%d.", (char *) Language(92), CFG.iSafeMaxNumber); + Syslog('-', "Value out of range!"); + } else + break; + } + + while (TRUE) { + Enter(1); + /* 2nd digit: */ + pout(12, 0, (char *) Language(93)); + colour(9, 0); + fflush(stdout); + Getnum(sSecond, 2); + sprintf(temp, "2nd: %s", sSecond); + if((strcmp(sSecond, "")) != 0) { + Syslog('-', temp); + iSecond=atoi(sSecond); + } + + if((iSecond > CFG.iSafeMaxNumber) || (iSecond <= 0) || (strcmp(sSecond, "") == 0)) { + colour(15,1); + /* Please try again! You must input a number greater than Zero and less than */ + printf("\n%s%d.\n", (char *) Language(92), CFG.iSafeMaxNumber); + Syslog('-', "Value out of range!"); + } else + break; + } + + while (TRUE) { + Enter(1); + pout(12, 0, (char *) Language(94)); + colour(9, 0); + fflush(stdout); + Getnum(sThird, 2); + if((strcmp(sThird, "")) != 0) { + if((strcmp(sThird, "737") != 0) && (strcmp(sThird, "747") != 0)) { + sprintf(temp, "3rd: %s", sThird); + Syslog('!', temp); + } else { + sprintf(temp, "3rd: %d", CFG.iSafeMaxNumber - 1); + Syslog('-', temp); + } + } + iThird=atoi(sThird); + + if((iThird == 737) || (iThird == 747)) + break; + + if((iThird > CFG.iSafeMaxNumber) || (iThird <= 0)) { + colour(15,1); + /* Please try again! You must input a number greater than Zero and less than */ + printf("\n%s%d.\n", (char *) Language(92), CFG.iSafeMaxNumber); + Syslog('-', "Value out of range!"); + } else + break; + } + + /* Left: */ + Enter(1); + pout(12, 0, (char *) Language(95)); + poutCR(9, 0, sFirst); + + /* Right: */ + pout(12, 0, (char *) Language(96)); + poutCR(9, 0, sSecond); + + /* Left: */ + pout(12, 0, (char *) Language(95)); + poutCR(9, 0, sThird); + + Enter(1); + /* Attempt to open safe with this combination [Y/n]: */ + pout(12, 0, (char *) Language(97)); + fflush(stdout); + alarm_on(); + i = toupper(Getone()); + sprintf(temp, "%c", i); + + if ((i == Keystroke(97, 0)) || (i == 13)) { + printf("\n\n"); + + /* Left: */ + pout(12, 0, (char *) Language(95)); + for (iLoop = 0; iLoop < iFirst; iLoop++) + pout(14, 0, (char *)"."); + poutCR(9, 0, sFirst); + + /* Right: */ + pout(12, 0, (char *) Language(96)); + for (iLoop = 0; iLoop < iSecond; iLoop++) + pout(14, 0, (char *)"."); + poutCR(9, 0, sSecond); + + /* Left: */ + pout(12, 0, (char *) Language(95)); + for (iLoop = 0; iLoop < iThird; iLoop++) + pout(14, 0, (char *)"."); + poutCR(9, 0, sThird); + + if(CFG.iSafeNumGen) { + CFG.iSafeFirstDigit = (rand() % CFG.iSafeMaxNumber) + 1; + CFG.iSafeSecondDigit = (rand() % CFG.iSafeMaxNumber) + 1; + CFG.iSafeThirdDigit = (rand() % CFG.iSafeMaxNumber) + 1; + } + + if(CFG.iSafeFirstDigit == iFirst) + if(CFG.iSafeSecondDigit == iSecond) + if(CFG.iSafeThirdDigit == iThird) { + + DisplayFile(CFG.sSafeOpened); + + Enter(1); + /* You have won the following... */ + pout(12, 0, (char *) Language(98)); + Enter(2); + poutCR(13, 0, CFG.sSafePrize); + Enter(1); + + sprintf(temp, "%s/etc/safe.data", getenv("MBSE_ROOT")); + if(( pSafe = fopen(temp, "r+")) == NULL) + WriteError("Can't open %s for updating", temp); + else { + fseek(pSafe, 0L, SEEK_END); + result = ftell(pSafe); + result /= sizeof(safe); + + fread(&safe, sizeof(safe), 1, pSafe); + + safe.Opened = TRUE; + + fseek(pSafe, 0L, SEEK_END); + result = ftell(pSafe); + result /= sizeof(safe); + fwrite(&safe, sizeof(safe), 1, pSafe); + fclose(pSafe); + } + + Syslog('!', "User opened Safe Cracker Door"); + + Pause(); + return TRUE; + } + + Enter(1); + pout(10, 0, (char *) Language(99)); + Enter(1); + + if(CFG.iSafeNumGen) { + Enter(1); + /* The safe code was: */ + pout(12, 0, (char *) Language(100)); + Enter(2); + colour(12, 0); + + /* Left: */ + printf("%s%d\n", (char *) Language(95), CFG.iSafeFirstDigit); + + /* Right */ + printf("%s%d\n", (char *) Language(96), CFG.iSafeSecondDigit); + + /* Left */ + printf("%s%d\n", (char *) Language(95), CFG.iSafeThirdDigit); + } + + if(iThird == 737) + CFG.iSafeNumGen = FALSE; + + if(iThird == 747) { + colour(9, 0); + printf("Code: %d %d %d\n", CFG.iSafeFirstDigit, CFG.iSafeSecondDigit, CFG.iSafeThirdDigit); + } + + Enter(1); + /* Please press key to continue */ + pout(10, 0, (char *) Language(87)); + alarm_on(); + getchar(); + } + return FALSE; +} + + + +/* + * Returns true when safe already cracked or maximum trys exceeded + */ +int SafeCheckUser(void) +{ + int Counter = 0; + char *File, *Name, *Date; + + File = calloc(PATH_MAX, sizeof(char)); + Name = calloc(50, sizeof(char)); + Date = calloc(50, sizeof(char)); + + sprintf(Name, "%s", exitinfo.sUserName); + sprintf(Date, "%s", (char *) GetDateDMY()); + sprintf(File, "%s/etc/safe.data", getenv("MBSE_ROOT")); + + if(( pSafe = fopen(File, "r")) == NULL) { + if((pSafe = fopen(File, "w")) != NULL) { + sprintf(safe.Date, "%s", (char *) GetDateDMY()); + sprintf(safe.Name, "%s", Name); + safe.Trys = 0; + safe.Opened = 0; + fwrite(&safe, sizeof(safe), 1, pSafe); + fclose(pSafe); + } + } else { + while ( fread(&safe, sizeof(safe), 1, pSafe) == 1) { + if(safe.Opened) { + fclose(pSafe); + Syslog('+', "Safe is currently LOCKED - exiting door."); + + /* THE SAFE IS CURRENTLY LOCKED */ + poutCR(15, 4, (char *) Language(103)); + Enter(1); + colour(12, 0); + + /* has cracked the safe. */ + printf("%s, %s\n", safe.Name, (char *) Language(104)); + + /* The safe will remain locked until the sysop rewards the user. */ + pout(10, 0, (char *) Language(105)); + Enter(2); + Pause(); + fclose(pSafe); + free(File); + free(Name); + free(Date); + return TRUE; + } + } + rewind(pSafe); + + fread(&safe, sizeof(safe), 1, pSafe); + if((strcmp(Date, safe.Date)) != 0) { + fclose(pSafe); + if((pSafe = fopen(File, "w")) != NULL) { + sprintf(safe.Date, "%s", (char *) GetDateDMY()); + sprintf(safe.Name, "%s", Name); + safe.Trys = 0; + safe.Opened = 0; + fwrite(&safe, sizeof(safe), 1, pSafe); + fclose(pSafe); + } + } else { + while ( fread(&safe, sizeof(safe), 1, pSafe) == 1) { + if((strcmp(Name, safe.Name)) == 0) + Counter++; + } + + rewind(pSafe); + + if(Counter >= CFG.iSafeMaxTrys - 1) { + Enter(2); + /* Maximum trys per day exceeded */ + pout(15, 0, (char *) Language(106)); + Enter(1); + sleep(3); + fclose(pSafe); + free(File); + free(Name); + free(Date); + return TRUE; + } + + fclose(pSafe); + + if(( pSafe = fopen(File, "a+")) == NULL) + WriteError("Unable to append to safe.data", File); + else { + sprintf(safe.Date, "%s", (char *) GetDateDMY()); + sprintf(safe.Name, "%s", Name); + safe.Trys = 0; + safe.Opened = 0; + fwrite(&safe, sizeof(safe), 1, pSafe); + fclose(pSafe); + } + } + } + free(File); + free(Name); + free(Date); + return FALSE; +} + + diff --git a/mbsebbs/safe.h b/mbsebbs/safe.h new file mode 100644 index 00000000..f9c10461 --- /dev/null +++ b/mbsebbs/safe.h @@ -0,0 +1,11 @@ +/* safe.h */ + +#ifndef _SAFE_H +#define _SAFE_H + + +void Safe(void); + + +#endif + diff --git a/mbsebbs/salt.c b/mbsebbs/salt.c new file mode 100644 index 00000000..2cff3d81 --- /dev/null +++ b/mbsebbs/salt.c @@ -0,0 +1,98 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/salt.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 13-May-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * salt.c - generate a random salt string for crypt() + * + * Written by Marek Michalkiewicz , + * public domain. + */ +#include "../config.h" +#include +#include +#include +#include +#include "rad64.h" + + +#if 1 +#include "getdef.h" + + +/* + * Generate 8 base64 ASCII characters of random salt. If MD5_CRYPT_ENAB + * in /etc/login.defs is "yes", the salt string will be prefixed by "$1$" + * (magic) and pw_encrypt() will execute the MD5-based FreeBSD-compatible + * version of crypt() instead of the standard one. + */ +char *crypt_make_salt(void) +{ + struct timeval tv; + static char result[40]; + + result[0] = '\0'; + if (getdef_bool("MD5_CRYPT_ENAB")) { + strcpy(result, "$1$"); /* magic for the new MD5 crypt() */ + } + + /* + * Generate 8 chars of salt, the old crypt() will use only first 2. + */ + gettimeofday(&tv, (struct timezone *) 0); + strcat(result, l64a(tv.tv_usec)); + strcat(result, l64a(tv.tv_sec + getpid() + clock())); + + if (strlen(result) > 3 + 8) /* magic+salt */ + result[11] = '\0'; + + return result; +} +#else + +/* + * This is the old style random salt generator... + */ +char *crypt_make_salt(void) +{ + time_t now; + static unsigned long x; + static char result[3]; + + time(&now); + x += now + getpid() + clock(); + result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077); + result[1] = i64c(((x >> 12) ^ x) & 077); + result[2] = '\0'; + return result; +} +#endif diff --git a/mbsebbs/salt.h b/mbsebbs/salt.h new file mode 100644 index 00000000..ff7cbfd5 --- /dev/null +++ b/mbsebbs/salt.h @@ -0,0 +1,9 @@ +#ifndef _SALT_H +#define _SALT_H + + +char *crypt_make_salt(void); + + +#endif + diff --git a/mbsebbs/sgetpwent.c b/mbsebbs/sgetpwent.c new file mode 100644 index 00000000..a9d6d6e9 --- /dev/null +++ b/mbsebbs/sgetpwent.c @@ -0,0 +1,167 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/sgetpwent.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 07-Feb-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * Copyright 1989 - 1994, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "../config.h" +#include +#include +#include +#include "sgetpwent.h" + + +#define NFIELDS 7 + +/* + * sgetpwent - convert a string to a (struct passwd) + * + * sgetpwent() parses a string into the parts required for a password + * structure. Strict checking is made for the UID and GID fields and + * presence of the correct number of colons. Any failing tests result + * in a NULL pointer being returned. + * + * NOTE: This function uses hard-coded string scanning functions for + * performance reasons. I am going to come up with some conditional + * compilation glarp to improve on this in the future. + */ + +struct passwd * sgetpwent(const char *buf) +{ + static struct passwd pwent; + static char pwdbuf[1024]; + register int i; + register char *cp; + char *ep; + char *fields[NFIELDS]; + + /* + * Copy the string to a static buffer so the pointers into + * the password structure remain valid. + */ + + if (strlen(buf) >= sizeof pwdbuf) + return 0; + strcpy(pwdbuf, buf); + + /* + * Save a pointer to the start of each colon separated + * field. The fields are converted into NUL terminated strings. + */ + + for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) { + fields[i] = cp; + while (*cp && *cp != ':') + ++cp; + + if (*cp) + *cp++ = '\0'; + else + cp = 0; + } + + /* + * There must be exactly NFIELDS colon separated fields or + * the entry is invalid. Also, the UID and GID must be non-blank. + */ + + if (i != NFIELDS || *fields[2] == '\0' || *fields[3] == '\0') + return 0; + + /* + * Each of the fields is converted the appropriate data type + * and the result assigned to the password structure. If the + * UID or GID does not convert to an integer value, a NULL + * pointer is returned. + */ + + pwent.pw_name = fields[0]; + pwent.pw_passwd = fields[1]; + if (fields[2][0] == '\0' || + ((pwent.pw_uid = strtol (fields[2], &ep, 10)) == 0 && *ep)) { + return 0; + } + if (fields[3][0] == '\0' || + ((pwent.pw_gid = strtol (fields[3], &ep, 10)) == 0 && *ep)) { + return 0; + } +#ifdef ATT_AGE + cp = pwent.pw_passwd; + while (*cp && *cp != ',') + ++cp; + + if (*cp) { + *cp++ = '\0'; + pwent.pw_age = cp; + } else { + cp = 0; + pwent.pw_age = ""; + } +#endif + pwent.pw_gecos = fields[4]; +#ifdef ATT_COMMENT + pwent.pw_comment = ""; +#endif + pwent.pw_dir = fields[5]; + pwent.pw_shell = fields[6]; + + return &pwent; +} + + diff --git a/mbsebbs/sgetpwent.h b/mbsebbs/sgetpwent.h new file mode 100644 index 00000000..90777b1d --- /dev/null +++ b/mbsebbs/sgetpwent.h @@ -0,0 +1,7 @@ +#ifndef _SGETPWENT_H +#define _SGETPWENT_H + +struct passwd * sgetpwent(const char *); + +#endif + diff --git a/mbsebbs/shadowio.c b/mbsebbs/shadowio.c new file mode 100644 index 00000000..84ecd3d7 --- /dev/null +++ b/mbsebbs/shadowio.c @@ -0,0 +1,232 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/shadowio.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 13-Aug-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../config.h" + +#ifdef SHADOW_PASSWORD +#include +#include +#include +#include + + +#include "commonio.h" +#include "shadowio.h" + + + +struct spwd *__spw_dup(const struct spwd *spent) +{ + struct spwd *sp; + + if (!(sp = (struct spwd *) malloc(sizeof *sp))) + return NULL; + *sp = *spent; + if (!(sp->sp_namp = strdup(spent->sp_namp))) + return NULL; + if (!(sp->sp_pwdp = strdup(spent->sp_pwdp))) + return NULL; + return sp; +} + + + +static void * shadow_dup(const void *ent) +{ + const struct spwd *sp = ent; + return __spw_dup(sp); +} + + + +static void shadow_free(void *ent) +{ + struct spwd *sp = ent; + + free(sp->sp_namp); + free(sp->sp_pwdp); + free(sp); +} + + + +static const char * shadow_getname(const void *ent) +{ + const struct spwd *sp = ent; + return sp->sp_namp; +} + + + +static void * shadow_parse(const char *line) +{ + return (void *) sgetspent(line); +} + + + +static int shadow_put(const void *ent, FILE *file) +{ + const struct spwd *sp = ent; + return (putspent(sp, file) == -1) ? -1 : 0; +} + + + +static struct commonio_ops shadow_ops = { + shadow_dup, + shadow_free, + shadow_getname, + shadow_parse, + shadow_put, + fgets, + fputs +}; + + + +static struct commonio_db shadow_db = { + SHADOW_FILE, + &shadow_ops, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0 +}; + + + +int spw_name(const char *filename) +{ + return commonio_setname(&shadow_db, filename); +} + + + +int spw_file_present(void) +{ + return commonio_present(&shadow_db); +} + + + +int spw_lock(void) +{ + return commonio_lock(&shadow_db); +} + + + +int spw_lock_first(void) +{ + return commonio_lock_first(&shadow_db); +} + + + +int spw_open(int mode) +{ + return commonio_open(&shadow_db, mode); +} + + + +const struct spwd * spw_locate(const char *name) +{ + return commonio_locate(&shadow_db, name); +} + + + +int spw_update(const struct spwd *sp) +{ + return commonio_update(&shadow_db, (const void *) sp); +} + + + +int spw_remove(const char *name) +{ + return commonio_remove(&shadow_db, name); +} + + + +int spw_rewind(void) +{ + return commonio_rewind(&shadow_db); +} + + + +const struct spwd * spw_next(void) +{ + return commonio_next(&shadow_db); +} + + + +int spw_close(void) +{ + return commonio_close(&shadow_db); +} + + + +int spw_unlock(void) +{ + return commonio_unlock(&shadow_db); +} + + + +struct commonio_entry * __spw_get_head(void) +{ + return shadow_db.head; +} + + + +void __spw_del_entry(const struct commonio_entry *ent) +{ + commonio_del_entry(&shadow_db, ent); +} + + +#endif + diff --git a/mbsebbs/shadowio.h b/mbsebbs/shadowio.h new file mode 100644 index 00000000..2bb725f7 --- /dev/null +++ b/mbsebbs/shadowio.h @@ -0,0 +1,27 @@ +#ifndef _SHADOWIO_H +#define _SHADOWIO_H + +#ifdef SHADOW_PASSWORD +#ifndef SHADOW_FILE +#define SHADOW_FILE "/etc/shadow" +#endif +#endif + + +struct spwd *__spw_dup (const struct spwd *); +void __spw_set_changed (void); +int spw_close (void); +int spw_file_present (void); +const struct spwd *spw_locate (const char *); +int spw_lock (void); +int spw_lock_first (void); +int spw_name (const char *); +const struct spwd *spw_next (void); +int spw_open (int); +int spw_remove (const char *); +int spw_rewind (void); +int spw_unlock (void); +int spw_update (const struct spwd *); + +#endif + diff --git a/mbsebbs/statetbl.h b/mbsebbs/statetbl.h new file mode 100644 index 00000000..5ed4475f --- /dev/null +++ b/mbsebbs/statetbl.h @@ -0,0 +1,48 @@ +#ifndef STATETBL_H +#define STATETBL_H + +#define SM_DECL(proc,name) \ +int proc(void)\ +{\ + int sm_success=0;\ + char *sm_name=name; + +#define SM_STATES \ + enum { + +#define SM_NAMES \ + } sm_state;\ + char * sm_sname[] = { + +#define SM_EDECL \ + }; + +#define SM_START(x) \ + sm_state=x;\ + Syslog('S', "Statemachine %s start %s (%d)", sm_name, sm_sname[sm_state], sm_state);\ + while (!sm_success) switch (sm_state)\ + {\ + default: WriteError("Statemachine %s error: state=%d",sm_name,sm_state);\ + sm_success=-1; + +#define SM_STATE(x) \ + break;\ + case x: + +#define SM_END \ + }\ + +#define SM_RETURN \ + return (sm_success != 1);\ +} + +#define SM_PROCEED(x) \ + sm_state=x; break; + +#define SM_SUCCESS \ + sm_success=1; break; + +#define SM_ERROR \ + sm_success=-1; break; + +#endif diff --git a/mbsebbs/timecheck.c b/mbsebbs/timecheck.c new file mode 100644 index 00000000..3f16dc50 --- /dev/null +++ b/mbsebbs/timecheck.c @@ -0,0 +1,96 @@ +/***************************************************************************** + * + * File ..................: bbs/timecheck.c + * Purpose ...............: Timecheck functions + * Last modification date : 28-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 Internet: mbroek@users.sourceforge.net + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "timecheck.h" +#include "funcs.h" +#include "funcs4.h" +#include "misc.h" +#include "bye.h" +#include "exitinfo.h" +#include "language.h" + + +/* + * This is the users onlinetime check. Must be REWRITTEN!! + */ +void TimeCheck(void) +{ + char temp[81]; + time_t Now; + int Elapsed; + + time(&Now); + + /* + * Update the global string for the menu prompt + */ + sprintf(sUserTimeleft, "%d", iUserTimeLeft); + ReadExitinfo(); + + if (iUserTimeLeft != ((Time2Go - Now) / 60)) { + + Elapsed = iUserTimeLeft - ((Time2Go - Now) / 60); + iUserTimeLeft -= Elapsed; + sprintf(sUserTimeleft, "%d", iUserTimeLeft); + + sprintf(temp, "/tmp/.chat.%s", pTTY); + /* + * Update users counter if not chatting + */ + if(!CFG.iStopChatTime || (access(temp, F_OK) != 0)) { + exitinfo.iTimeLeft -= Elapsed; + exitinfo.iConnectTime += Elapsed; + exitinfo.iTimeUsed += Elapsed; + WriteExitinfo(); + } + } + + if(exitinfo.iTimeLeft <= 0) { + printf("\n%s\n", (char *) Language(130)); + sleep(3); + Syslog('!', "Users time limit exceeded ... user disconnected!"); + iExpired = TRUE; + Good_Bye(1); + } + + /* + * Check for a personal message + */ + Check_PM(); +} + + diff --git a/mbsebbs/timecheck.h b/mbsebbs/timecheck.h new file mode 100644 index 00000000..f104fa70 --- /dev/null +++ b/mbsebbs/timecheck.h @@ -0,0 +1,8 @@ +#ifndef _TIMECHECK_H +#define _TIMECHECK_H + +void TimeCheck(void); /* Check Users Time Limit */ + + +#endif + diff --git a/mbsebbs/timeout.c b/mbsebbs/timeout.c new file mode 100644 index 00000000..77ce64e1 --- /dev/null +++ b/mbsebbs/timeout.c @@ -0,0 +1,144 @@ +/***************************************************************************** + * + * File ..................: bbs/timeout.c + * Purpose ...............: Inactivity timeout functions + * Last modification date : 24-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "timeout.h" +#include "funcs.h" +#include "funcs4.h" +#include "bye.h" +#include "filesub.h" +#include "language.h" + + +extern int e_pid; /* Pid of external program */ + + + +void die(int onsig) +{ + /* + * First check if there is a child running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeeded", e_pid); + else + WriteError("Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode, reset the tty + */ + system("stty sane"); + } + + if (MsgBase.Locked) + Msg_UnLock(); + if (MsgBase.Open) + Msg_Close(); + + Home(); + signal(onsig, SIG_IGN); + if (onsig) + if (onsig == SIGHUP) { + Syslog('+', "Lost Carrier"); + } else if (onsig == SIGALRM) { + Syslog('+', "User inactivity timeout"); + } else { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + else + Syslog(' ', "Terminated by user"); + + if (onsig == SIGSEGV) { + Syslog('+', "Last msg area %s", msgs.Name); + } + + if (LoginPrompt) { + Unsetraw(); + Quick_Bye(onsig); + } else + Good_Bye(onsig); +} + + + +void alarm_sig() +{ + colour(12, 0); + /* Autologout: idletime reached.*/ + printf("\r\n%s\r\n", (char *) Language(410)); + + if (LoginPrompt) + Syslog('!', "Autologout: idletime reached at login prompt"); + else + Syslog('!', "Autologout: idletime reached"); + + die(SIGALRM); +} + + + +void alarm_set(int val) +{ + signal(SIGALRM, (void (*))alarm_sig); + alarm(val); + Syslog('S', "Alarm set for %d seconds", val); +} + + + +void alarm_on() +{ + alarm_set(60 * CFG.idleout); +} + + + +void alarm_off() +{ + alarm(0); + signal(SIGALRM, SIG_IGN); + Syslog('S', "Alarm is off"); +} + diff --git a/mbsebbs/timeout.h b/mbsebbs/timeout.h new file mode 100644 index 00000000..e7835b52 --- /dev/null +++ b/mbsebbs/timeout.h @@ -0,0 +1,12 @@ +#ifndef _TIMEOUT_H +#define _TIMEOUT_H + +void die(int); +void alarm_sig(void); +void alarm_set(int); +void alarm_on(void); +void alarm_off(void); + + +#endif + diff --git a/mbsebbs/user.c b/mbsebbs/user.c new file mode 100644 index 00000000..d8964131 --- /dev/null +++ b/mbsebbs/user.c @@ -0,0 +1,1157 @@ +/***************************************************************************** + * + * File ..................: bbs/user.c + * Purpose ...............: Main user login procedure. Checks for limits, + * new ratio's cats all the welcome screens, and + * does a lot of checking in general. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "timeout.h" +#include "user.h" +#include "pwcheck.h" +#include "funcs.h" +#include "funcs4.h" +#include "misc.h" +#include "bye.h" +#include "file.h" +#include "mail.h" +#include "change.h" +#include "menu.h" +#include "exitinfo.h" +#include "language.h" +#include "offline.h" +#include "statetbl.h" +#include "email.h" +#include "newuser.h" + + +extern int sock; +extern pid_t mypid; + + +/* Non global function prototypes */ + +char *AskLogin(void); +static int rxemsi(void); + + +char *Passwd = NULL; +int iMaxLogin = 1; +char *ieUserName = NULL; +char *ieHandle = NULL; +char *ieLocation = NULL; +char *ieVoicePhone = NULL; +char *ieDataPhone = NULL; +long iePassword = 0; +char *ieBirthDate = NULL; +char *ieTerminal = NULL; +int ieRows = 0; +int ieCols = 0; +int ieNulls = 0; +int ieDZA = FALSE; +int ieZAP = FALSE; +int ieZMO = FALSE; +int ieSLK = FALSE; +int ieKER = FALSE; +int ieCHT = FALSE; +int ieMNU = FALSE; +int ieTAB = FALSE; +int ieASCII8 = FALSE; +int ieNEWS = FALSE; +int ieMAIL = FALSE; +int ieFILE = FALSE; +int ieHOT = FALSE; +int ieCLR = FALSE; +int ieHUSH = FALSE; +int ieMORE = FALSE; +int ieFSED = FALSE; +int ieXPRS = FALSE; +char *ieSoftware = NULL; +int ieLogin = FALSE; + + + +/* + * Ask for BBS Login name (Firstname Lastname) and try to + * establish an IEMSI session if the client supports it. + */ +char *AskLogin(void); +char *AskLogin(void) +{ + char temp[36]; + int Count = 0, rc = 0; + static char GetName[36]; + + do { + /* + * if after the first time IEMSI failed rc will not be + * zero anymore so we don't check for IEMSI logon anymore. + */ + if (rc == 0) { + rc = rxemsi(); + if (rc) + Syslog('+', "rxemsi rc=%d", rc); + } + if (rc) { + /* + * IEMSI Aborted or other errors, so prompt user. + * Note that if the user didn't had an IEMSI client, + * rc is still 0, the name is entered in the rxemsi + * function. + */ + /* Please enter your First and Last name: */ + language(7, 0, 0); + fflush(stdout); + alarm_on(); + Getname(GetName, 35); + } else { + sprintf(GetName, "%s", ieUserName); + } + + if ((strcmp(GetName,"")) == 0) { + Count++; + + if (Count >= CFG.iCRLoginCount) { + Enter(1); + /* Disconnecting user ... */ + language(CFG.HiliteF, CFG.HiliteB, 2); + Enter(2); + Syslog('!', "Exceeded maximum login attempts"); + free(Passwd); + Quick_Bye(0); + } + } + } while (strcmp(GetName, "") == 0); + + strcpy(temp, GetName); + + /* + * Secret escape name + */ + if ((strcasecmp(temp, "off")) == 0) { + Syslog('+', "Quick \"off\" logout"); + free(Passwd); + Quick_Bye(0); + } + + /* + * Check for singlename + */ + if ((strchr(GetName,' ') == NULL && !CFG.iOneName)) { + Syslog('+', "Did not enter a full name"); + + Count = -1; + while (TRUE) { + do { + Count++; + if (Count >= CFG.iCRLoginCount) { + Enter(1); + /* Disconnecting user ... */ + language(CFG.HiliteF, CFG.HiliteB, 2); + Enter(2); + Syslog('!', "Exceeded maximum login attempts"); + free(Passwd); + Quick_Bye(0); + } + + /* Please enter your Last name: */ + language(7, 0, 1); + fflush(stdout); + alarm_on(); + Getname(temp, 34 - strlen(GetName)); + } while ((strcmp(temp, "")) == 0); + + if((strcmp(temp,"")) != 0) { + strcat(GetName," "); + strcat(GetName,temp); + break; + } + } + } + + alarm_off(); + return GetName; +} + + + +/* + * The next function is "borrowed" from Eugene M. Crossers ifcico. + */ +char *sel_brace(char *); +char *sel_brace(char *s) +{ + static char *save; + char *p, *q; + int i; + + if (s == NULL) + s = save; + for (; *s && (*s != '{'); s++); + if (*s == '\0') { + save = s; + return NULL; + } else + s++; + + for (p = s, q = s; *p; p++) + switch(*p) { + case '}': if (*(p+1) == '}') + *q++ = *p++; + else { + *q = '\0'; + save = p+1; + goto exit; + } + break; + + case '\\': if (*(p+1) == '\\') + *q++ = *p++; + else { + sscanf(p+1, "%02x", &i); + *q++ = i; + p+=2; + } + break; + + default: *q++ = *p; + break; + } +exit: + return s; +} + + + +int scanemsiici(char *); +int scanemsiici(char *buf) +{ + char *p, *q; + + ieUserName = xstrcpy(sel_brace(buf)); + Syslog('i', "Username : %s", MBSE_SS(ieUserName)); + ieHandle = xstrcpy(sel_brace(NULL)); + Syslog('i', "Handle : %s", MBSE_SS(ieHandle)); + ieLocation = xstrcpy(sel_brace(NULL)); + Syslog('i', "Location : %s", MBSE_SS(ieLocation)); + ieVoicePhone = xstrcpy(sel_brace(NULL)); + Syslog('i', "Voice Phone : %s", MBSE_SS(ieVoicePhone)); + ieDataPhone = xstrcpy(sel_brace(NULL)); + Syslog('i', "Data Phone : %s", MBSE_SS(ieDataPhone)); + p = sel_brace(NULL); + memset(Passwd, 0, 16); + if (strlen(p) < 16) + sprintf(Passwd, "%s", p); + iePassword = StringCRC32(tu(p)); + Syslog('i', "Password : %s (%ld)", p, iePassword); + ieBirthDate = xstrcpy(sel_brace(NULL)); + Syslog('i', "Birthdate : %s", MBSE_SS(ieBirthDate)); + p = sel_brace(NULL); + ieTerminal = strtok(p, ","); + ieRows = atoi(strtok(NULL, ",")); + ieCols = atoi(strtok(NULL, ",")); + ieNulls = atoi(strtok(NULL, ",")); + Syslog('i', "Terminal : %s (%d x %d) [%d]", ieTerminal, ieRows, ieCols, ieNulls); + + p = sel_brace(NULL); + Syslog('i', "Protocols : %s", MBSE_SS(p)); + for (q = strtok(p, ","); q; q = strtok(NULL, ",")) { + if (strcasecmp(q, "DZA") == 0) + ieDZA = TRUE; + else if (strcasecmp(q, "ZAP") == 0) + ieZAP = TRUE; + else if (strcasecmp(q, "ZMO") == 0) + ieZMO = TRUE; + else if (strcasecmp(q, "SLK") == 0) + ieSLK = TRUE; + else if (strcasecmp(q, "KER") == 0) + ieKER = TRUE; + else + Syslog('+', "Unrecognized IEMSI Protocol \"%s\"", q); + } + + p = sel_brace(NULL); + Syslog('i', "Capabilities: %s", MBSE_SS(p)); + for (q = strtok(p, ","); q; q = strtok(NULL, ",")) { + if (strcasecmp(q, "CHT") == 0) + ieCHT = TRUE; + else if (strcasecmp(q, "TAB") == 0) + ieTAB = TRUE; + else if (strcasecmp(q, "MNU") == 0) + ieMNU = TRUE; + else if (strcasecmp(q, "ASCII8") == 0) + ieASCII8 = TRUE; + else + Syslog('+', "Unrecognized IEMSI Capability \"%s\"", q); + } + + p = sel_brace(NULL); + Syslog('i', "Requests : %s", MBSE_SS(p)); + for (q = strtok(p, ","); q; q = strtok(NULL, ",")) { + if (strcasecmp(q, "NEWS") == 0) + ieNEWS = TRUE; + else if (strcasecmp(q, "MAIL") == 0) + ieMAIL = TRUE; + else if (strcasecmp(q, "FILE") == 0) + ieFILE = TRUE; + else if (strcasecmp(q, "HOT") == 0) + ieHOT = TRUE; + else if (strcasecmp(q, "CLR") == 0) + ieCLR = TRUE; + else if (strcasecmp(q, "HUSH") == 0) + ieHUSH = TRUE; + else if (strcasecmp(q, "MORE") == 0) + ieMORE = TRUE; + else if (strcasecmp(q, "FSED") == 0) + ieFSED = TRUE; + else if (strcasecmp(q, "XPRS") == 0) + ieXPRS = TRUE; + else + Syslog('+', "Unrecognized IEMSI Request \"%s\"", q); + } + + ieSoftware = xstrcpy(sel_brace(NULL)); + Syslog('i', "Software : %s", MBSE_SS(ieSoftware)); + + return 0; +} + + + +char *mkiemsiisi(void); +char *mkiemsiisi(void) +{ + char *p, cbuf[16]; + time_t tt; + + p = xstrcpy((char *)"EMSI_ISI0000{MBSE BBS,"); + p = xstrcat(p, (char *)VERSION); + p = xstrcat(p, (char *)",Linux}{"); + p = xstrcat(p, CFG.bbs_name); + p = xstrcat(p, (char *)"}{"); + p = xstrcat(p, CFG.location); + p = xstrcat(p, (char *)"}{"); + p = xstrcat(p, CFG.sysop_name); + p = xstrcat(p, (char *)"}{"); + (void)time(&tt); + sprintf(cbuf, "%08lX", mktime(localtime(&tt))); + p = xstrcat(p, cbuf); + p = xstrcat(p, (char *)"}{"); + p = xstrcat(p, CFG.comment); + p = xstrcat(p, (char *)"}{0}{}"); + sprintf(cbuf, "%04X", (unsigned int)strlen(p+12)); + memcpy(p+8, cbuf, 4); + + Syslog('i', "Prepared \"%s\"", p); + return p; +} + + + +SM_DECL(rxemsi, (char *)"rxemsi") +SM_STATES + prompt, + getpkt, + chkpkt, + chkici, + sendnak, + sendisi, + human +SM_NAMES + (char *)"prompt", + (char *)"getpkt", + (char *)"chkpkt", + (char *)"chkici", + (char *)"sendnak", + (char *)"sendisi", + (char *)"human" +SM_EDECL + int len, iemsi, newpos, tries = 0; + char *p, *buf = NULL; + unsigned char c = 0; + unsigned short lcrc, rcrc; + unsigned long llcrc, lrcrc; + + buf = calloc(2048, sizeof(char)); + +SM_START(prompt) + +SM_STATE(prompt) + Syslog('I', "SM: prompt"); + + /* + * Issue EMSI_IRQ and overwrite it with the prompt. + */ + printf("**EMSI_IRQ8E08\r \r"); + /* Please enter your First and Last name: */ + language(7, 0, 0); + fflush(stdout); + tries = 0; + SM_PROCEED(getpkt); + +SM_STATE(getpkt) + Syslog('I', "SM: getpkt"); + + fflush(stdin); + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + WriteError("$Can't open /dev/tty"); + SM_ERROR; + } + Setraw(); + len = 0; + iemsi = FALSE; + newpos = 0; + buf[0] = '\0'; + alarm_on(); + + while(TRUE) { + c = Readkey(); + + Syslog('I', "c=%s len=%d iemsi=%d", printablec(c), len, iemsi); + + if ((len == 0) && (c == '*')) { + iemsi = TRUE; + } else { + if (((c == 8) || (c == KEY_DEL) || (c == 127)) && (len > 0)) { + printf("\b \b"); + fflush(stdout); + buf[--len] = '\0'; + } + + if (c > 31 && c < 127) { + if ((len == 0) && (CFG.iCapUserName)) + c = toupper(c); + + if (c == 32) { + newpos = len; + newpos++; + } + + if (!iemsi) { + if (newpos == len && CFG.iCapUserName) + c = toupper(c); + else { + if (CFG.iCapUserName) + c = tolower(c); + } + printf("%c", c); + fflush(stdout); + } + buf[len] = c; + len++; + } + } + + if ((c == '\r') || (!iemsi && (len == 35)) || (iemsi && (len == 2047))) { + buf[len] = '\0'; + break; + } + } + + Unsetraw(); + close(ttyfd); + Syslog('I', "Buf \"%s\"", printable(buf,0)); + + if (strncasecmp(buf, "EMSI_", 5)) { + SM_PROCEED(human); + } else { + SM_PROCEED(chkpkt); + } + +SM_STATE(chkpkt) + Syslog('I', "SM: chkpkt"); + if (strncasecmp(buf, "EMSI_ICI", 8) == 0) { + SM_PROCEED(chkici) + } + lcrc = crc16xmodem(buf, 8); + sscanf(buf+8, "%04hx", &rcrc); + if (lcrc != rcrc) { + Syslog('+', "Got IEMSI packet \"%s\" with bad crc: %04x/%04x", printable(buf, 0), lcrc, rcrc); + SM_PROCEED(sendnak); + } + if (strncasecmp(buf, "EMSI_HBT", 8) == 0) { + tries = 0; + SM_PROCEED(getpkt); + } else if (strncasecmp(buf, "EMSI_IIR61E2", 12) == 0) { + Syslog('+', "IEMSI Interrupt Request received"); + SM_ERROR; + } else if (strncasecmp(buf, "EMSI_ACKA490", 12) == 0) { + Syslog('+', "Established IEMSI session"); + ieLogin = TRUE; + /* + * Clearup the part of the users screen where some IEMSI + * codes may be hanging around + */ + fflush(stdin); + printf("\r \r"); + fflush(stdout); + SM_SUCCESS; + } else if (strncasecmp(buf, "EMSI_NAKEEC3", 12) == 0) { + Syslog('+', "IEMSI NAK received"); + SM_PROCEED(getpkt); + } else { + Syslog('I', "rxemsi ignores packet \"%s\"", buf); + SM_PROCEED(getpkt); + } + +SM_STATE(chkici) + Syslog('I', "SM: chkici"); + sscanf(buf+8, "%04x", &len); + if (len != (strlen(buf) - 20)) { + Syslog('+', "Bad EMSI_ICI length: %d/%d", len, strlen(buf)-20); + SM_PROCEED(sendnak); + } + sscanf(buf+strlen(buf)-8, "%08lx", &lrcrc); + *(buf+strlen(buf)-8) = '\0'; + llcrc = crc32ccitt(buf, strlen(buf)); + if (llcrc != lrcrc) { + Syslog('+', "Got EMSI_ICI packet \"%s\" with bad crc: %08x/%08x", printable(buf, 0), llcrc, lrcrc); + SM_PROCEED(sendnak); + } + if (scanemsiici(buf+12) == 0) { + SM_PROCEED(sendisi); + } else { + WriteError("Could not parse EMSI_ICI packet \"%s\"", buf); + SM_ERROR; + } + +SM_STATE(sendnak) + Syslog('I', "SM: sendnak"); + if (++tries > 9) { + Syslog('+', "too many tries getting EMSI_ICI"); + SM_ERROR; + } + printf((char *)"**EMSI_IRQ8E08\r"); + if (tries > 1) + printf((char *)"**EMSI_NAKEEC3\r"); + fflush(stdout); + SM_PROCEED(getpkt); + +SM_STATE(sendisi) + Syslog('I', "SM: sendisi"); + p = mkiemsiisi(); + printf("**%s%08lX\r", p, crc32ccitt(p, strlen(p))); + fflush(stdout); + free(p); + SM_PROCEED(getpkt); + +SM_STATE(human) + printf("\n"); + fflush(stdout); + ieUserName = xstrcpy(buf); + Syslog('+', "Human caller (%s)", MBSE_SS(ieUserName)); + SM_SUCCESS; + +SM_END + free(buf); + +SM_RETURN + + + +void user() +{ + FILE *pUsrConfig, *pLimits; + int i, x, z; + int FoundName = FALSE, iFoundLimit = FALSE; + register int recno; + int lrecno = 0; + long l1, l2; + unsigned crc = 0; + char *token; + char temp[PATH_MAX]; + char temp1[84]; + char sGetName[84]; + char *FileName; + char *handle; + struct passwd *pw; + char *sGetPassword; + long offset; + time_t LastLogin; + struct stat st; + char UserName[36]; + int IsNew = FALSE; + + + recno=0; + LoginPrompt = TRUE; + + /* + * If not in unix mode ask for login + */ + if (!iUnixMode) { + strcpy(sGetName, AskLogin()); + } else { + Syslog('+', "Unixmode login: %s", sUnixName); + if ((pw = getpwnam(sUnixName))) + #ifdef linux + strcpy(sGetName, pw->pw_gecos); + #else + strcpy(sGetName, pw->pw_comment); + #endif + + /* + * If there are more fields in the passwd gecos field + * then only get the first field. + */ + if (strchr(sGetName, ',') != NULL) + strcpy(sGetName, strtok(sGetName, ",")); + + if (!(CheckName(sGetName))) { + printf("Unknown username: %s\n", sGetName); + /* FATAL ERROR: You are not in the BBS users file.*/ + printf("%s\n", (char *) Language(389)); + /* Please run 'newuser' to create an account */ + printf("%s\n", (char *) Language(390)); + Syslog('?', "FATAL: Could not find user in BBS users file."); + Syslog('?', " and system is using unix accounts\n"); + free(Passwd); + ExitClient(0); + } + } + + if (CFG.iCapUserName || SYSOP) + strcpy(sGetName, tlcap(sGetName)); + + /* + * Copy username, split first and lastname. + */ + strcpy(UserName, tlcap(sGetName)); + + if ((strchr(sGetName,' ') == NULL && !CFG.iOneName)) { + token = strtok(sGetName, " "); + strcpy(FirstName, token); + token = strtok(NULL, "\0"); + i = strlen(token); + for(x = 2; x < i; x++) { + if(token[x] == ' ') + token[x] = '\0'; + } + strcpy(LastName, token); + } else + strcpy(FirstName, sGetName); + + Syslog('+', "%s On-Line at %s", UserName, ttyinfo.comment); + + if ((strlen(sGetName)) < 2) + user(); + + /* + * Check some essential files, create them if they don't exist. + */ + ChkFiles(); + + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp,"r+b")) == NULL) { + /* + * This should only happen once, when you build the BBS + */ + WriteError("Can't open users file: %s", temp); + printf("Can't open userfile, run \"newuser\" first"); + free(Passwd); + ExitClient(0); + } + + handle = calloc(40, sizeof(char)); + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + strcpy(temp1, UserName); + while (fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig) == 1) { + strcpy(temp, usrconfig.sUserName); + strcpy(handle, usrconfig.sHandle); + + if ((strcasecmp(temp, temp1) == 0 || strcasecmp(handle, temp1) == 0)) { + FoundName = TRUE; + break; + } else + recno++; + } + free(handle); + + if (!FoundName) { + Syslog('+', "Name not in user file"); + Enter(1); + /* Scanning User File */ + language(7, 0, 3); + Enter(1); + + usrconfig.GraphMode = FALSE; + DisplayFile((char *)"notfound"); + + Enter(1); + /* Name entered: */ + language(7, 0, 5); + printf("%s\n\n", UserName); + /* Did you spell your name correctly [Y/n] */ + language(7, 0, 4); + fflush(stdout); + fflush(stdin); + i = toupper(Getone()); + if (i == Keystroke(4, 0) || i == '\r') { + if (!CFG.elite_mode) { + /* + * Here we run newuser. + */ + Syslog('+', "Creating user ..."); + recno = newuser(UserName); + IsNew = TRUE; + } else { + if (!DisplayFile((char *)"private")) { + /* If FALSE display hard coded message */ + Enter(1); + /* This is a PRIVATE System, Type "off" to leave */ + language(7, 0, 6); + Enter(2); + } + + Syslog('!', "NewUser tried to login to \"Private System\""); + free(Passwd); + Quick_Bye(0); + } + + } else { + Enter(1); + Syslog('+', "User spelt his/her name incorrectly"); + user(); + } + } + + /* + * Setup users favourite language. + */ + Set_Language(usrconfig.iLanguage); + Free_Language(); + InitLanguage(); + + /* + * User logged in, tell it to the server. + */ + UserCity(mypid, usrconfig.sUserName, usrconfig.sLocation); + + /* + * See if this user is the Sysop. + */ + strcpy(temp, UserName); + strcpy(temp1, CFG.sysop_name); + if ((strcasecmp(temp1, temp)) == 0) + SYSOP = TRUE; /* If login name is sysop, set SYSOP true */ + + grecno = recno; + + offset = usrconfighdr.hdrsize + (recno * usrconfighdr.recsize); + if (fseek(pUsrConfig, offset, 0) != 0) { + printf("Can't move pointer there."); + getchar(); + free(Passwd); + ExitClient(1); + } + + fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig); + TermInit(usrconfig.GraphMode); + sGetPassword = malloc(Max_passlen+1); + + /* + * If UnixMode is False, else let crc = iPassword to bypass the + * passwd + */ + if (!iUnixMode && !IsNew) { + /* + * Check for a blank or expired password, they do exist + * after upgrading from RA 2.xx due to a bug in RA (or feature) + */ + if (usrconfig.iPassword == 0) { + Syslog('!', "User has blank password, asking new"); + z = 0; + while (TRUE) { + Enter(1); + /* Your password is expired, enter password: */ + language(7, 0, 435); + fflush(stdout); + alarm_on(); + Getpass(temp); + if ((x = strlen(temp)) >= CFG.password_length) { + Enter(1); + /* Please enter password again: */ + language(7, 0, 40); + fflush(stdout); + alarm_on(); + Getpass(temp1); + if ((i = strcmp(temp, temp1)) != 0) { + Enter(2); + /* Passwords do not match */ + language(7,0,41); + Enter(1); + } else { + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + sprintf(usrconfig.Password, "%s", temp); + memset(Passwd, 0, 16); + sprintf(Passwd, "%s", temp); + crc = StringCRC32(tu(temp)); + usrconfig.iPassword = crc; + break; + } + } else { + z++; + if (z == CFG.iCRLoginCount) { + Syslog('!', "User did not enter new password"); + Enter(1); + language(CFG.HiliteF, CFG.HiliteB, 2); + Enter(2); + free(Passwd); + Quick_Bye(0); + } + + Enter(2); + /* Your password must contain at least */ + language(7, 0, 42); + printf("%d ", CFG.password_length); + /* characters! Try again */ + language(7, 0, 43); + Enter(1); + } + } + } else { + if ((ieLogin) && (iePassword == usrconfig.iPassword)) { + crc = iePassword; + } else { + /* Pasword: */ + language(7, 0, 8); + fflush(stdout); + alarm_on(); + Getpass(sGetPassword); + /* + * Password is CRC32 of uppercase string + */ + memset(Passwd, 0, 16); + sprintf(Passwd, "%s", sGetPassword); + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + sprintf(usrconfig.Password, "%s", sGetPassword); + crc = StringCRC32(tu(sGetPassword)); + } + } + } else { + crc = usrconfig.iPassword; + sprintf(Passwd, "%s", usrconfig.Password); + } + + IsDoing("Just Logged In"); + + /* + * If password already OK, give pause prompt so the bbs logo + * will stay on the users screen. + */ + if ((iUnixMode) || ((ieLogin) && (iePassword == usrconfig.iPassword))) { + alarm_on(); + Pause(); + } + + if (usrconfig.Archiver[0] == '\0') { + usrconfig.Archiver[0] = 'Z'; + usrconfig.Archiver[1] = 'I'; + usrconfig.Archiver[2] = 'P'; + Syslog('+', "Setup default archiver ZIP"); + } + + if (usrconfig.iPassword == crc) { + recno = 0; + free(sGetPassword); + + /* + * Check if user has an Unix account, if not create one + */ + if (usrconfig.Name[0] == '\0') { + alarm_on(); + sprintf(usrconfig.Name, "%s", (char *)NameCreate(NameGen(UserName), UserName, Passwd)); + sprintf(sUnixName, "%s", usrconfig.Name); + Pause(); + } + + /* + * Check users date format. We do it strict as we + * need this to be good for several other purposes. + * If it is correct, the users age is set in UserAge + */ + if (!Test_DOB(usrconfig.sDateOfBirth)) { + Syslog('!', "Error in Date of Birth"); + Chg_DOB(); + strcpy(usrconfig.sDateOfBirth, exitinfo.sDateOfBirth); + } + + /* + * Check to see if user must expire + */ + sprintf(temp,"%s", (char *) GetDateDMY()); + SwapDate(temp, usrconfig.sExpiryDate); + + /* Convert Date1 & Date2 to longs for compare */ + l1 = atol(Date1); + l2 = atol(Date2); + + if(l1 >= l2 && l2 != 0) { + /* + * If Expiry Date is the same as today expire to + * Expire Sec level + */ + usrconfig.Security = usrconfig.ExpirySec; + Syslog('!', "User is expired, resetting level"); + /* + * Show texfile to user telling him about this. + */ + DisplayFile((char *)"expired"); + } + + free(Date1); + free(Date2); + + /* + * Copy limits.data into memory + */ + FileName = calloc(84, sizeof(char)); + sprintf(FileName, "%s/etc/limits.data", getenv("MBSE_ROOT")); + + if(( pLimits = fopen(FileName,"rb")) == NULL) { + perror(""); + WriteError("Can't open file: %s", FileName); + } else { + fread(&LIMIThdr, sizeof(LIMIThdr), 1, pLimits); + + while (fread(&LIMIT, sizeof(LIMIT), 1, pLimits) == 1) { + if (LIMIT.Security == usrconfig.Security.level) { + iFoundLimit = TRUE; + break; + } else + lrecno++; + } + fclose(pLimits); + } + free(FileName); + + if(!iFoundLimit) { + Syslog('?', "Unknown Security Level in limits.data"); + usrconfig.iTimeLeft = 0; /* Could not find limit, so set to Zero */ + usrconfig.iTimeUsed = 0; /* Set to Zero as well */ + } else { + /* + * Give user new time limit everyday + */ + sprintf(temp,"%s", (char *) GetDateDMY()); + + if((strcmp(StrDateDMY(usrconfig.tLastLoginDate), temp)) != 0) { + usrconfig.iTimeLeft = LIMIT.Time; /* Copy Sec limit/time to users file */ + usrconfig.iTimeUsed = 0; /* Set time used today to Zero */ + usrconfig.iConnectTime = 0; /* Set connect time to Zero */ + + /* + * Give user new bytes and files every day + */ + usrconfig.DownloadKToday = LIMIT.DownK; + usrconfig.DownloadsToday = LIMIT.DownF; + } + } /* End of else */ + + usrconfig.iConnectTime = 0; + + /* Copy Users Protocol into Memory */ + Set_Protocol(usrconfig.sProtocol); + tlf(usrconfig.sProtocol); + + /* + * Set last login Date and Time, copy previous session + * values in memory. + */ + sprintf(LastLoginDate, "%s", StrDateDMY(usrconfig.tLastLoginDate)); + sprintf(LastLoginTime, "%s", StrTimeHMS(usrconfig.tLastLoginDate)); + LastLogin = usrconfig.tLastLoginDate; + usrconfig.tLastLoginDate = ltime; /* Set current login to current date */ + usrconfig.iTotalCalls = ++usrconfig.iTotalCalls; + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + sprintf(usrconfig.Password, "%s", Passwd); + + /* + * If IEMSI login, update some settings + */ + if (ieLogin) { + usrconfig.Cls = ieCLR; + usrconfig.HotKeys = ieHOT; + usrconfig.ieNEWS = ieNEWS; + usrconfig.MailScan = ieMAIL; + usrconfig.ieFILE = ieFILE; + usrconfig.Chat = ieCHT; + usrconfig.ieASCII8 = ieASCII8; + usrconfig.DoNotDisturb = ieHUSH; + usrconfig.FsMsged = ieFSED; + } + + /* + * Update user record. + */ + if(fseek(pUsrConfig, offset, 0) != 0) + WriteError("Can't move pointer in file: %s", temp); + else { + fwrite(&usrconfig, sizeof(usrconfig), 1, pUsrConfig); + fclose(pUsrConfig); + } + + /* + * Write users structure to tmp file in ~/tmp + */ + InitExitinfo(); + GetLastUser(); + GetLastCallers(); + ChangeHomeDir(exitinfo.Name, exitinfo.Email); + + Syslog('+', "User successfully logged into BBS"); + Syslog('+', "Level %d (%s), %d mins. left, port %s", usrconfig.Security.level, LIMIT.Description, usrconfig.iTimeLeft, pTTY); + time(&Time2Go); + Time2Go += usrconfig.iTimeLeft * 60; + iUserTimeLeft = usrconfig.iTimeLeft; + + DisplayFile((char *)"welcome"); + + /* + * The following files are only displayed if the user has + * turned the Bulletins on. + */ + if (exitinfo.ieNEWS) { + DisplayFile((char *)"welcome1"); + + sprintf(temp, "%s", (char *) GetDateDMY() ); + if ((strcmp(usrconfig.sDateOfBirth, temp)) == 0) + DisplayFile((char *)"birthday"); + + /* + * Displays file if it exists DD-MM.A?? + */ + sprintf(temp, "%s", (char *) GetDateDMY()); + strcpy(temp1, ""); + strncat(temp1, temp, 5); + sprintf(temp, "%s", temp1); + DisplayFile(temp); + + /* + * Displays users security file if it exists + */ + sprintf(temp, "sec%d", usrconfig.Security.level); + DisplayFile(temp); + + /* + * Display News file + */ + DisplayFile((char *)"news"); + } + + /* + * Display Onceonly file, first get the date of that + * file, search order is the same as in DisplayFile() + */ + st.st_mtime = 0; + if (usrconfig.GraphMode) { + sprintf(temp, "%s/onceonly.ans", lang.TextPath); + stat(temp, &st); + if (st.st_mtime == 0) { + sprintf(temp, "%s/onceonly.ans", CFG.bbs_txtfiles); + stat(temp, &st); + } + } + if (st.st_mtime == 0) { + sprintf(temp, "%s/onceonly.asc", lang.TextPath); + stat(temp, &st); + if (st.st_mtime == 0) { + sprintf(temp, "%s/onceonly.asc", CFG.bbs_txtfiles); + stat(temp, &st); + } + } + + if ((st.st_mtime != 0) && (LastLogin < st.st_mtime)) + DisplayFile((char *)"onceonly"); + + LoginPrompt = FALSE; + OLR_SyncTags(); + + if (usrconfig.MailScan) + CheckMail(); + + /* + * We don't show new files to new users, their lastlogin + * date is not yet set so they would see all the files + * which can be boring... + */ + if (usrconfig.ieFILE && (!IsNew)) + NewfileScan(FALSE); + + /* + * Copy last file Area in to current Area + */ + SetFileArea(usrconfig.iLastFileArea); + + /* + * Copy Last Message Area in to Current Msg Area + */ + SetMsgArea(usrconfig.iLastMsgArea); + SetEmailArea((char *)"mailbox"); + + /* + * Set or Reset the DoNotDisturb flag, now is the time + * we may be interrupted. + */ + UserSilent(usrconfig.DoNotDisturb); + + /* + * Start the menu, but first, wipe the password. + */ + memset(Passwd, 0, sizeof(Passwd)); + free(Passwd); + menu(); + } else { + Syslog('+',"Login attempt: %d, password: %s", iMaxLogin, sGetPassword); + free(sGetPassword); + iMaxLogin++; + if(iMaxLogin == CFG.max_login + 1) { + Enter(2); + language(7, 0, 9); + Enter(1); + Syslog('!', "Exceeded maximum login attempts, user disconnected"); + ExitClient(1); + } + Enter(2); + language(7, 0, 10); + Enter(2); + alarm_on(); + Pause(); + printf("\n"); + user(); + } +} + + diff --git a/mbsebbs/user.h b/mbsebbs/user.h new file mode 100644 index 00000000..08a5c6df --- /dev/null +++ b/mbsebbs/user.h @@ -0,0 +1,19 @@ +#ifndef _USER_H +#define _USER_H + + +#define EMSI_ACK **EMSI_ACKA490 +#define EMSI_NAK **EMSI_NAKEEC3 +#define EMSI_IRQ **EMSI_IRQ8E08 +#define EMSI_IIR **EMSI_IIR +#define EMSI_ICI **EMSI_ICI +#define EMSI_ISI **EMSI_ISI +#define EMSI_CHT **EMSI_CHT +#define EMSI_TCH **EMSI_TCH +#define EMSI_CLI **EMSI_CLIFA8C + + +void user(void); + +#endif + diff --git a/mbsebbs/xmalloc.c b/mbsebbs/xmalloc.c new file mode 100644 index 00000000..89d1f6ce --- /dev/null +++ b/mbsebbs/xmalloc.c @@ -0,0 +1,71 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/xmalloc.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 25-Jul-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +/* Replacements for malloc and strdup with error checking. Too trivial + to be worth copyrighting :-). I did that because a lot of code used + malloc and strdup without checking for NULL pointer, and I like some + message better than a core dump... --marekm + + Yeh, but. Remember that bailing out might leave the system in some + bizarre state. You really want to put in error checking, then add + some back-out failure recovery code. -- jfh */ + + +#include "../config.h" +#include +#include +#include +#include "xmalloc.h" + + + +char *xmalloc(size_t size) +{ + char *ptr; + + ptr = malloc(size); + if (!ptr && size) { + fprintf(stderr, "malloc(%d) failed\n", (int) size); + exit(13); + } + return ptr; +} + + + +char *xstrdup(const char *str) +{ + return strcpy(xmalloc(strlen(str) + 1), str); +} + diff --git a/mbsebbs/xmalloc.h b/mbsebbs/xmalloc.h new file mode 100644 index 00000000..dc92d0cf --- /dev/null +++ b/mbsebbs/xmalloc.h @@ -0,0 +1,8 @@ +#ifndef _XMALLOC_H +#define _XMALLOC_H + +char *xmalloc(size_t); +char *xstrdup(const char *); + +#endif + diff --git a/mbsetup/Makefile.am b/mbsetup/Makefile.am new file mode 100644 index 00000000..119651ba --- /dev/null +++ b/mbsetup/Makefile.am @@ -0,0 +1,24 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +noinst_PROGRAMS = mbsetup + +mbsetup_SOURCES = screen.c mutil.c ledit.c m_bbs.c m_global.c m_mail.c m_tic.c \ +m_fido.c m_archive.c m_virus.c m_tty.c m_users.c m_protocol.c \ +m_limits.c m_lang.c m_ol.c m_node.c m_marea.c m_mgroup.c m_ff.c \ +m_ticarea.c m_magic.c m_menu.c m_new.c m_modem.c grlist.c \ +m_fgroup.c m_farea.c m_fdb.c m_hatch.c stlist.c mbsetup.c \ +m_ngroup.c m_service.c m_domain.c m_task.c \ +screen.h mutil.h ledit.h m_bbs.h m_global.h m_mail.h m_tic.h \ +m_fido.h m_archive.h m_virus.h m_tty.h m_users.h m_protocol.h \ +m_limits.h m_lang.h m_ol.h m_node.h m_marea.h m_mgroup.h m_ff.h \ +m_ticarea.h m_magic.h m_menu.h m_new.h m_modem.h grlist.h \ +m_fgroup.h m_farea.h m_fdb.h m_hatch.h stlist.h \ +m_ngroup.h m_service.h m_domain.h m_task.h + +LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbsetup $(bindir) + diff --git a/mbsetup/Makefile.in b/mbsetup/Makefile.in new file mode 100644 index 00000000..99d596a9 --- /dev/null +++ b/mbsetup/Makefile.in @@ -0,0 +1,502 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +noinst_PROGRAMS = mbsetup + +mbsetup_SOURCES = screen.c mutil.c ledit.c m_bbs.c m_global.c m_mail.c m_tic.c m_fido.c m_archive.c m_virus.c m_tty.c m_users.c m_protocol.c m_limits.c m_lang.c m_ol.c m_node.c m_marea.c m_mgroup.c m_ff.c m_ticarea.c m_magic.c m_menu.c m_new.c m_modem.c grlist.c m_fgroup.c m_farea.c m_fdb.c m_hatch.c stlist.c mbsetup.c m_ngroup.c m_service.c m_domain.c m_task.c screen.h mutil.h ledit.h m_bbs.h m_global.h m_mail.h m_tic.h m_fido.h m_archive.h m_virus.h m_tty.h m_users.h m_protocol.h m_limits.h m_lang.h m_ol.h m_node.h m_marea.h m_mgroup.h m_ff.h m_ticarea.h m_magic.h m_menu.h m_new.h m_modem.h grlist.h m_fgroup.h m_farea.h m_fdb.h m_hatch.h stlist.h m_ngroup.h m_service.h m_domain.h m_task.h + + +LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbsetup_OBJECTS = screen.o mutil.o ledit.o m_bbs.o m_global.o m_mail.o \ +m_tic.o m_fido.o m_archive.o m_virus.o m_tty.o m_users.o m_protocol.o \ +m_limits.o m_lang.o m_ol.o m_node.o m_marea.o m_mgroup.o m_ff.o \ +m_ticarea.o m_magic.o m_menu.o m_new.o m_modem.o grlist.o m_fgroup.o \ +m_farea.o m_fdb.o m_hatch.o stlist.o mbsetup.o m_ngroup.o m_service.o \ +m_domain.o m_task.o +mbsetup_LDADD = $(LDADD) +mbsetup_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbsetup_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbsetup_SOURCES) +OBJECTS = $(mbsetup_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbsetup/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbsetup: $(mbsetup_OBJECTS) $(mbsetup_DEPENDENCIES) + @rm -f mbsetup + $(LINK) $(mbsetup_LDFLAGS) $(mbsetup_OBJECTS) $(mbsetup_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbsetup + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +grlist.o: grlist.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h screen.h grlist.h ledit.h +ledit.o: ledit.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h screen.h mutil.h \ + ledit.h +m_archive.o: m_archive.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_archive.h +m_bbs.o: m_bbs.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + screen.h mutil.h ledit.h m_lang.h m_protocol.h m_ol.h \ + m_fgroup.h m_farea.h m_menu.h m_bbs.h m_limits.h +m_domain.o: m_domain.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_menu.h m_domain.h +m_farea.o: m_farea.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_fgroup.h m_archive.h m_farea.h m_ngroup.h +m_fdb.o: m_fdb.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_farea.h m_fdb.h +m_ff.o: m_ff.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h screen.h mutil.h ledit.h stlist.h m_global.h \ + m_ff.h m_lang.h m_marea.h +m_fgroup.o: m_fgroup.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_node.h m_ticarea.h m_fgroup.h +m_fido.o: m_fido.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_fido.h +m_global.o: m_global.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_node.h m_marea.h m_ticarea.h m_global.h +m_hatch.o: m_hatch.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_fgroup.h m_ticarea.h m_hatch.h +m_lang.o: m_lang.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_lang.h +m_limits.o: m_limits.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_limits.h +m_magic.o: m_magic.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_ticarea.h m_global.h m_magic.h +m_mail.o: m_mail.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h screen.h mutil.h ledit.h m_global.h m_marea.h \ + m_mgroup.h m_mail.h +m_marea.o: m_marea.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + grlist.h m_global.h m_node.h m_mgroup.h m_marea.h +m_menu.o: m_menu.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h mutil.h screen.h ledit.h \ + m_lang.h m_menu.h +m_mgroup.o: m_mgroup.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_node.h m_marea.h m_mgroup.h +m_modem.o: m_modem.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_modem.h +m_new.o: m_new.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h grlist.h m_new.h m_lang.h m_marea.h \ + m_ngroup.h +m_ngroup.o: m_ngroup.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_ngroup.h +m_node.o: m_node.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + grlist.h stlist.h m_global.h m_lang.h m_ticarea.h m_marea.h \ + m_node.h +m_ol.o: m_ol.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h screen.h mutil.h ledit.h m_global.h m_ol.h +m_protocol.o: m_protocol.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_protocol.h +m_service.o: m_service.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_service.h +m_task.o: m_task.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_task.h +m_tic.o: m_tic.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + screen.h mutil.h ledit.h m_fgroup.h m_ticarea.h m_magic.h \ + m_hatch.h m_tic.h +m_ticarea.o: m_ticarea.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h grlist.h m_global.h m_node.h m_fgroup.h m_farea.h \ + m_archive.h m_ticarea.h +m_tty.o: m_tty.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_modem.h m_global.h m_tty.h +m_users.o: m_users.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_archive.h m_protocol.h m_users.h +m_virus.o: m_virus.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_virus.h +mbsetup.o: mbsetup.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_bbs.h m_mail.h m_tic.h m_fido.h m_archive.h \ + m_virus.h m_tty.h m_limits.h m_users.h m_node.h m_fdb.h m_new.h \ + m_ff.h m_modem.h m_marea.h m_ngroup.h m_service.h m_domain.h \ + m_task.h +mutil.o: mutil.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h screen.h mutil.h +screen.o: screen.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/ansi.h \ + ../lib/common.h screen.h +stlist.o: stlist.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h stlist.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbsetup $(bindir) + +# 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/mbsetup/grlist.c b/mbsetup/grlist.c new file mode 100644 index 00000000..8a93ba51 --- /dev/null +++ b/mbsetup/grlist.c @@ -0,0 +1,177 @@ +/***************************************************************************** + * + * File ..................: grlist.c + * Purpose ...............: Group Listing utils + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "grlist.h" +#include "ledit.h" + + +/* + * Tidy the groupnames array + */ +void tidy_grlist(gr_list ** fdp) +{ + gr_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a group to the array + */ +void fill_grlist(gr_list **fdp, char *groupname) +{ + gr_list *tmp; + + tmp = (gr_list *)malloc(sizeof(gr_list)); + tmp->next = *fdp; + sprintf(tmp->group, "%s", groupname); + tmp->tagged = FALSE; + *fdp = tmp; +} + + + +int compgroup(gr_list **, gr_list **); + +/* + * Sort the array of groups + */ +void sort_grlist(gr_list **fdp) +{ + gr_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) + return; + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (gr_list **)malloc(n * sizeof(gr_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) { + vector[i++] = ta; + } + + qsort(vector, n, sizeof(gr_list*), (int(*)(const void*, const void*))compgroup); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compgroup(gr_list **fdp1, gr_list **fdp2) +{ + return strcmp((*fdp1)->group, (*fdp2)->group); +} + + + +int E_Group(gr_list **fdp, char *title) +{ + int n = 0, i, j, x, y, rc = FALSE; + gr_list *tmp; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 5, (char *)"%s", title); + set_color(CYAN, BLACK); + + for (tmp = *fdp; tmp; tmp = tmp->next) + n++; + + for (;;) { + set_color(CYAN, BLACK); + y = 7; + x = 5; + j = 0; + + for (tmp = *fdp; tmp; tmp = tmp->next) { + j++; + if (tmp->tagged) + mvprintw(y, x, (char *)"%2d. + %s", j, tmp->group); + else + mvprintw(y, x, (char *)"%2d. %s", j, tmp->group); + y++; + if (y == 18) { + y = 7; + x += 20; + } + } + + i = select_tag(n); + + if (i == 0) { + clr_index(); + return rc; + } + + if ((i >= 1) && (i <= n)) { + j = 0; + rc = TRUE; + for (tmp = *fdp; tmp; tmp = tmp->next) { + j++; + if (j == i) { + if (tmp->tagged) + tmp->tagged = FALSE; + else + tmp->tagged = TRUE; + } + } + } + } +} + + diff --git a/mbsetup/grlist.h b/mbsetup/grlist.h new file mode 100644 index 00000000..3fc4bbbe --- /dev/null +++ b/mbsetup/grlist.h @@ -0,0 +1,18 @@ +#ifndef _GRLIST_H +#define _GRLIST_H + +typedef struct _gr_list { + struct _gr_list *next; + char group[13]; + int tagged; +} gr_list; + + +void tidy_grlist(gr_list **); +void fill_grlist(gr_list **, char *); +void sort_grlist(gr_list **); +int E_Group(gr_list **, char *); + + +#endif + diff --git a/mbsetup/ledit.c b/mbsetup/ledit.c new file mode 100644 index 00000000..512215e5 --- /dev/null +++ b/mbsetup/ledit.c @@ -0,0 +1,1598 @@ +/***************************************************************************** + * + * File ..................: ledit.c + * Purpose ...............: Line Editor + * Last modification date : 27-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" + + + +int sock; /* Connected socket */ + + +int yes_no(char *T_) +{ + char t[256]; + int ch; + + strcpy(t, T_); + strcat(t, " Y/n "); + set_color(LIGHTGRAY, BLACK); + locate(LINES - 3, 1); + clrtoeol(); + mvprintw(LINES -3, 6, t); + do { + ch = toupper(readkey(LINES - 3, strlen(t) + 6, LIGHTGRAY, BLACK)); + } while (ch != KEY_ENTER && ch != 'Y' && ch != 'N' && ch != '\012'); + locate(LINES - 3, 6); + clrtoeol(); + if (ch == KEY_ENTER || ch == 'Y' || ch == KEY_LINEFEED) + return 1; + else + return 0; +} + + + +void errmsg(const char *format, ...) +{ + char *t; + int ch; + va_list va_ptr; + + t = calloc(256, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(t, format, va_ptr); + va_end(va_ptr); + + t = xstrcat(t, (char *)", Press any key "); + set_color(LIGHTGRAY, BLACK); + locate(LINES - 3, 1); + clrtoeol(); + mvprintw(LINES - 3, 6, t); + putchar(7); + ch = readkey(LINES - 3, strlen(t) + 6, LIGHTGRAY, BLACK); + locate(LINES - 3, 6); + clrtoeol(); + free(t); +} + + + +void show_field(int y, int x, char *str, int length, int fill) +{ + mvprintw(y, x, padleft(str, length, fill)); +} + + + +int insertflag = 0; + +void newinsert(int i, int fg, int bg) +{ + insertflag = i; + set_color(YELLOW, RED); + if (insertflag != 0) { + mvprintw(2,36," INS "); + } else { + mvprintw(2,36," OVR "); + } + set_color(fg, bg); +} + + + + +char *edit_field(int y, int x, int w, int p, char *s_) +{ + int i, charok, first, curpos, AllSpaces; + static char s[256]; + unsigned int ch; + + memset((char *)s, 0, 256); + sprintf(s, "%s", s_); + curpos = 0; + first = 1; + newinsert(1, YELLOW, BLUE); + + do { + set_color(YELLOW, BLUE); + show_field(y, x, s, w, '_'); + locate(y, x + curpos); + do { + ch = readkey(y, x + curpos, YELLOW, BLUE); + set_color(YELLOW, BLUE); + + /* + * Test if the pressed key is a valid key. + */ + charok = 0; + if ((ch >= ' ') && (ch <= '~')) { + switch(p) { + case '!': + ch = toupper(ch); + charok = 1; + break; + case 'X': + charok = 1; + break; + case '9': + if (ch == ' ' || ch == '-' || ch == ',' || + ch == '.' || isdigit(ch)) + charok = 1; + break; + case 'U': + ch = toupper(ch); + if (isupper(ch)) + charok = 1; + break; + default: + putchar(7); + break; + } + } + + } while (charok == 0 && ch != KEY_ENTER && ch != KEY_LINEFEED && + ch != KEY_DEL && ch != KEY_INS && ch != KEY_HOME && + ch != KEY_LEFT && ch != KEY_RIGHT && ch != KEY_ESCAPE && + ch != KEY_BACKSPACE && ch != KEY_RUBOUT && ch != KEY_END); + + + if (charok == 1) { + if (first == 1) { + first = 0; + memset((char *)s, 0, 256); + curpos = 0; + } + if (curpos < w) { + if (insertflag == 1) { + /* + * Insert mode + */ + if (strlen(s) < w) { + if (curpos < strlen(s)) { + for (i = strlen(s); i >= curpos; i--) + s[i+1] = s[i]; + } + s[curpos] = ch; + if (curpos < w) + curpos++; + } else { + putchar(7); + } + } else { + /* + * Overwrite mode + */ + s[curpos] = ch; + if (curpos < w) + curpos++; + } + } else { + /* + * The field is full + */ + putchar(7); + } + } /* if charok */ + + first = 0; + switch (ch) { + case KEY_HOME: + curpos = 0; + break; + case KEY_END: + curpos = strlen(s); + break; + case KEY_LEFT: + if (curpos > 0) + curpos--; + else + putchar(7); + break; + case KEY_RIGHT: + if (curpos < strlen(s)) + curpos++; + else + putchar(7); + break; + case KEY_INS: + if (insertflag == 1) + newinsert(0, YELLOW, BLUE); + else + newinsert(1, YELLOW, BLUE); + break; + case KEY_BACKSPACE: + if (strlen(s) > 0) { + if (curpos >= strlen(s)) { + curpos--; + s[curpos] = '\0'; + } else { + for (i = curpos; i < strlen(s); i++) + s[i] = s[i+1]; + s[i] = '\0'; + } + } else + putchar(7); + break; + case KEY_RUBOUT: + case KEY_DEL: + if (strlen(s) > 0) { + if ((curpos) == (strlen(s) -1)) { + s[curpos] = '\0'; + } else { + for (i = curpos; i < strlen(s); i++) + s[i] = s[i+1]; + s[i] = '\0'; + } + } else + putchar(7); + break; + } + } while ((ch != KEY_ENTER) && (ch != KEY_LINEFEED) && (ch != KEY_ESCAPE)); + + set_color(LIGHTGRAY, BLUE); + mvprintw(2,36, " "); + set_color(LIGHTGRAY, BLACK); + if (strlen(s)) { + AllSpaces = TRUE; + for (i = 0; i < strlen(s); i++) { + if (s[i] != ' ') + AllSpaces = FALSE; + } + if (AllSpaces) + s[0] = '\0'; + } + return s; +} + + + +char *select_show(int max) +{ + static char s[12]; + static char *menu=(char *)"-"; + char help[81]; + + memset((char *)s, 0, 12); + + if (max == 0) + sprintf(help, "Select ^\"-\"^ for previous level"); + else + if (max > 10) + sprintf(help, "Select ^\"-\"^ for previous level, ^\"P\" or \"N\"^ to page"); + else + sprintf(help, "Select ^\"-\"^ for previous level"); + showhelp(help); + + /* + * Loop until the answer is right + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES - 3, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) + break; + if (max > 10) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + + working(2, 0, 0); + working(0, 0, 0); + } + + return menu; +} + + + +char *select_record(int max, int items) +{ + static char s[12]; + static char *menu=(char *)"-"; + char help[81]; + int pick; + + memset((char *)s, 0, 12); + + if (max == 0) + sprintf(help, "Select ^\"-\"^ for previous level, ^\"A\"^ to append first record"); + else + if (max > items) + sprintf(help, "Record (1..%d), ^\"-\"^ prev. level, ^\"A\"^ Append record, ^\"P\" or \"N\"^ to page", max); + else + sprintf(help, "Select record (1..%d), ^\"-\"^ for previous level, ^\"A\"^ to append a new record", max); + showhelp(help); + + /* + * Loop until the answer is right + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES - 3, 6); + clrtoeol(); + + if (strncmp(menu, "A", 1) == 0) + break; + if (strncmp(menu, "-", 1) == 0) + break; + if (strncmp(menu, "M", 1) == 0) + break; + if (max > items) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + break; + + working(2, 0, 0); + working(0, 0, 0); + } + + return menu; +} + + + +char *select_area(int max, int items) +{ + static char s[12]; + static char *menu=(char *)"-"; + char help[81]; + int pick; + + memset((char *)s, 0, 12); + + if (max == 0) + sprintf(help, "^\"-\"^ back, ^A^ppend"); + else + if (max > items) + sprintf(help, "Record (1..%d), ^\"-\"^ back, ^A^ppend, ^G^lobal, ^M^ove, ^N^ext, ^P^revious", max); + else + sprintf(help, "Record (1..%d), ^\"-\"^ back, ^A^ppend, ^G^lobal, ^M^ove", max); + showhelp(help); + + /* + * Loop until the answer is right + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES - 3, 6); + clrtoeol(); + + if (strncmp(menu, "A", 1) == 0) + break; + if (strncmp(menu, "-", 1) == 0) + break; + if ((strncmp(menu, "M", 1) == 0) && max) + break; + if ((strncmp(menu, "G", 1) == 0) && max) + break; + if (max > items) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + break; + } + + return menu; +} + + + +char *select_pick(int max, int items) +{ + static char s[12]; + static char *menu=(char *)"-"; + char help[81]; + int pick; + + memset((char *)s, 0, 12); + + if (max == 0) + sprintf(help, "Select ^\"-\"^ for previous level"); + else + if (max > 20) + sprintf(help, "Record (1..%d), ^\"-\"^ prev. level, ^\"P\" or \"N\"^ to page", max); + else + sprintf(help, "Select record (1..%d), ^\"-\"^ for previous level", max); + showhelp(help); + + /* + * Loop until the answer is right + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES - 3, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) + break; + if (max > items) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + break; + + working(2, 0, 0); + working(0, 0, 0); + } + + return menu; +} + + + + +/* Select menu, max is the highest item to pick. Returns zero if + * "-" (previous level) is selected. + */ +int select_menu_sub(int, char *); + +int select_menu(int max) +{ + return select_menu_sub(max, (char *)"Select menu item"); +} + +int select_tag(int max) +{ + return select_menu_sub(max, (char *)"Toggle item"); +} + + +int select_menu_sub(int max, char *hlp) +{ + static char *menu=(char *)"-"; + char help[80]; + int pick; + + sprintf(help, "%s (1..%d) or ^\"-\"^ for previous level.", hlp, max); + showhelp(help); + + /* Loop forever until it's right. + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 3, '9', menu); + locate(LINES -3, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) + return 0; + + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + return pick; + + working(2, 0, 0); + working(0, 0, 0); + } +} + + + +void show_str(int y, int x, int l, char *line) +{ + show_field(y, x, line, l, ' '); +} + + + +char *edit_str(int y, int x, int l, char *line, char *help) +{ + static char s[256]; + + showhelp(help); + memset((char *)s, 0, 256); + strcpy(s, edit_field(y, x, l, 'X', line)); + set_color(WHITE, BLACK); + show_str(y, x, l, s); + return s; +} + + + +char *edit_pth(int y, int x, int l, char *line, char *help) +{ + static char s[256]; + char *temp; + + showhelp(help); + memset((char *)s, 0, 256); + strcpy(s, edit_field(y, x, l, 'X', line)); + temp = xstrcpy(s); + if (strlen(temp)) { + temp = xstrcat(temp, (char *)"/foobar"); + if (access(s, R_OK)) { + if (yes_no((char *)"Path doesn't exist, create")) + if (! mkdirs(temp)) + errmsg((char *)"Can't create path"); + } + } + free(temp); + set_color(WHITE, BLACK); + show_str(y, x, l, s); + return s; +} + + + +char *edit_jam(int y, int x, int l, char *line, char *help) +{ + static char s[256]; + char *temp; + + showhelp(help); + memset((char *)s, 0, 256); + strcpy(s, edit_field(y, x, l, 'X', line)); + + /* + * Check if the messagebase exists, if not, create it. + */ + temp = xstrcpy(s); + temp = xstrcat(temp, (char *)".jhr"); + if (access(temp, W_OK)) { + if (mkdirs(s)) { + if (yes_no((char *)"Messagebase doesn't exist, create")) { + if (Msg_Open(s)) + Msg_Close(); + } + } else { + errmsg((char *)"Can't create directory"); + } + } + free(temp); + + set_color(WHITE, BLACK); + show_str(y, x, l, s); + return s; +} + + + +char *edit_ups(int y, int x, int l, char *line, char *help) +{ + static char s[256]; + + showhelp(help); + memset((char *)s, 0, 256); + strcpy(s, edit_field(y, x, l, '!', line)); + set_color(WHITE, BLACK); + show_str(y, x, l, s); + return s; +} + + + +char *getboolean(int val) +{ + if (val) + return (char *)"Yes"; + else + return (char *)"No "; +} + + + +void show_bool(int y, int x, int val) +{ + mvprintw(y, x, getboolean(val)); +} + + + +int edit_bool(int y, int x, int val, char *help) +{ + int ch; + char *temp; + + temp = calloc(81, sizeof(char)); + sprintf(temp, "%s (Spacebar = toggle)", help); + showhelp(temp); + free(temp); + + do { + set_color(YELLOW, BLUE); + show_bool(y, x, val); + ch = readkey(y, x, YELLOW, BLUE); + if (ch == ' ') + val ^= 1; + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_bool(y, x, val); + fflush(stdout); + return val; +} + + + +char *getloglevel(long val) +{ + char *p; + + p = xstrcpy((char *)"?"); + + if (val & DLOG_ATTENT) p = xstrcat(p, (char *)"!"); + if (val & DLOG_NORMAL) p = xstrcat(p, (char *)"+"); + if (val & DLOG_VERBOSE) p = xstrcat(p, (char *)"-"); + if (val & DLOG_TCP) p = xstrcat(p, (char *)"A"); + if (val & DLOG_BBS) p = xstrcat(p, (char *)"B"); + if (val & DLOG_CHAT) p = xstrcat(p, (char *)"C"); + if (val & DLOG_DEVIO) p = xstrcat(p, (char *)"D"); + if (val & DLOG_EXEC) p = xstrcat(p, (char *)"E"); + if (val & DLOG_FILEFWD) p = xstrcat(p, (char *)"F"); + if (val & DLOG_HYDRA) p = xstrcat(p, (char *)"H"); + if (val & DLOG_IEMSI) p = xstrcat(p, (char *)"I"); + if (val & DLOG_LOCK) p = xstrcat(p, (char *)"L"); + if (val & DLOG_MAIL) p = xstrcat(p, (char *)"M"); + if (val & DLOG_NEWS) p = xstrcat(p, (char *)"N"); + if (val & DLOG_OUTSCAN) p = xstrcat(p, (char *)"O"); + if (val & DLOG_PACK) p = xstrcat(p, (char *)"P"); + if (val & DLOG_ROUTE) p = xstrcat(p, (char *)"R"); + if (val & DLOG_SESSION) p = xstrcat(p, (char *)"S"); + if (val & DLOG_TTY) p = xstrcat(p, (char *)"T"); + if (val & DLOG_XMODEM) p = xstrcat(p, (char *)"X"); + if (val & DLOG_ZMODEM) p = xstrcat(p, (char *)"Z"); + + return p; +} + + + +void show_logl(int y, int x, long val) +{ + char *p; + + p = getloglevel(val); + show_field(y, x, p, 21, ' '); + free(p); +} + + + +long edit_logl(long val, char *txt) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 5, (char *)"%s EDIT LOGLEVEL", txt); + set_color(CYAN, BLACK); + mvprintw( 5,45, "Logflags"); + + mvprintw( 7, 5, "1. ! Attention"); + mvprintw( 8, 5, "2. + Normal"); + mvprintw( 9, 5, "3. - Verbose"); + mvprintw(10, 5, "4. A Debug TCP"); + mvprintw(11, 5, "5. B Debug BBS/binkp"); + mvprintw(12, 5, "6. C Chat modems"); + mvprintw(13, 5, "7. D Device IO"); + mvprintw(14, 5, "8. E Execute"); + mvprintw(15, 5, "9. F File forward"); + mvprintw(16, 5, "10. H Hydra debug"); + mvprintw(17, 5, "11. I EMSI debug"); + mvprintw( 7,45, "12. L Locking"); + mvprintw( 8,45, "13. M Mail debug"); + mvprintw( 9,45, "14. N News debug"); + mvprintw(10,45, "15. O Outboundscan"); + mvprintw(11,45, "16. P Packing"); + mvprintw(12,45, "17. R Routing"); + mvprintw(13,45, "18. S Session"); + mvprintw(14,45, "19. T TTY debug"); + mvprintw(15,45, "20. X Xmodem debug"); + mvprintw(16,45, "21. Z Zmodem debug"); + + for (;;) { + set_color(WHITE, BLACK); + show_logl(5, 54, val); + show_lbit( 7,24, val, DLOG_ATTENT); + show_lbit( 8,24, val, DLOG_NORMAL); + show_lbit( 9,24, val, DLOG_VERBOSE); + show_lbit(10,24, val, DLOG_TCP); + show_lbit(11,24, val, DLOG_BBS); + show_lbit(12,24, val, DLOG_CHAT); + show_lbit(13,24, val, DLOG_DEVIO); + show_lbit(14,24, val, DLOG_EXEC); + show_lbit(15,24, val, DLOG_FILEFWD); + show_lbit(16,24, val, DLOG_HYDRA); + show_lbit(17,24, val, DLOG_IEMSI); + show_lbit( 7,64, val, DLOG_LOCK); + show_lbit( 8,64, val, DLOG_MAIL); + show_lbit( 9,64, val, DLOG_NEWS); + show_lbit(10,64, val, DLOG_OUTSCAN); + show_lbit(11,64, val, DLOG_PACK); + show_lbit(12,64, val, DLOG_ROUTE); + show_lbit(13,64, val, DLOG_SESSION); + show_lbit(14,64, val, DLOG_TTY); + show_lbit(15,64, val, DLOG_XMODEM); + show_lbit(16,64, val, DLOG_ZMODEM); + + switch(select_menu(21)) { + case 0: return val; + case 1: val ^= DLOG_ATTENT; break; + case 2: val ^= DLOG_NORMAL; break; + case 3: val ^= DLOG_VERBOSE; break; + case 4: val ^= DLOG_TCP; break; + case 5: val ^= DLOG_BBS; break; + case 6: val ^= DLOG_CHAT; break; + case 7: val ^= DLOG_DEVIO; break; + case 8: val ^= DLOG_EXEC; break; + case 9: val ^= DLOG_FILEFWD; break; + case 10:val ^= DLOG_HYDRA; break; + case 11:val ^= DLOG_IEMSI; break; + case 12:val ^= DLOG_LOCK; break; + case 13:val ^= DLOG_MAIL; break; + case 14:val ^= DLOG_NEWS; break; + case 15:val ^= DLOG_OUTSCAN; break; + case 16:val ^= DLOG_PACK; break; + case 17:val ^= DLOG_ROUTE; break; + case 18:val ^= DLOG_SESSION; break; + case 19:val ^= DLOG_TTY; break; + case 20:val ^= DLOG_XMODEM; break; + case 21:val ^= DLOG_ZMODEM; break; + } + } + + return val; +} + + + +void show_int(int y, int x, int val) +{ + mvprintw(y, x, (char *)" "); + mvprintw(y, x, (char *)"%d", val); +} + + + +int edit_int(int y, int x, int val, char *help) +{ + static char s[6]; + static char line[6]; + + showhelp(help); + memset((char *)s, 0, 6); + sprintf(line, "%d", val); + strcpy(s, edit_field(y, x, 7, '9', line)); + set_color(WHITE, BLACK); + show_int(y, x, atoi(s)); + fflush(stdout); + return atoi(s); +} + + + +void show_ushort(int y, int x, unsigned short val) +{ + mvprintw(y, x, (char *)"%d", val); +} + + + +unsigned short edit_ushort(int y, int x, unsigned short val, char *help) +{ + unsigned short r; + static char s[6]; + static char line[6]; + + showhelp(help); + memset((char *)s, 0, 6); + do { + sprintf(line, "%d", val); + strcpy(s, edit_field(y, x, 5, '9', line)); + r = atoi(s); + if (r >= 65535L) { + working(2, y, x); + working(0, y, x); + } + } while (r >= 65535L); + set_color(WHITE, BLACK); + show_int(y, x, val); + fflush(stdout); + return r; +} + + + +void show_sbit(int y, int x, unsigned short val, unsigned short mask) +{ + show_bool(y, x, (val & mask) != 0); +} + + + +unsigned short toggle_sbit(int y, int x, unsigned short val, unsigned short mask, char *help) +{ + int ch; + + showhelp(help); + do { + set_color(YELLOW, BLUE); + show_sbit(y, x, val, mask); + ch = readkey(y, x, YELLOW, BLUE); + if (ch == ' ') + val ^= mask; + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_sbit(y, x, val, mask); + fflush(stdout); + return val; +} + + + +void show_lbit(int y, int x, long val, long mask) +{ + show_bool(y, x, (val & mask) != 0); +} + + + +long toggle_lbit(int y, int x, long val, long mask, char *help) +{ + int ch; + + showhelp(help); + do { + set_color(YELLOW, BLUE); + show_lbit(y, x, val, mask); + ch = readkey(y, x, YELLOW, BLUE); + if (ch == ' ') + val ^= mask; + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_lbit(y, x, val, mask); + fflush(stdout); + return val; +} + + + +char *getflag(unsigned long flag, unsigned long not) +{ + static char temp[33]; + int i; + + memset(temp, 0, 33); + memset(temp, '-', 32); + + for (i = 0; i < 32; i++) { + if ((flag >> i) & 1) + temp[i] = 'X'; + if ((not >> i) & 1) + temp[i] = 'O'; + /* + * The next one may never show up! + */ + if (((flag >> i) & 1) && ((not >> i) & 1)) + temp[i] = '!'; + } + + return temp; +} + + + +void show_sec(int y, int x, securityrec sec) +{ + show_int(y, x, sec.level); + mvprintw(y, x + 6, getflag(sec.flags, sec.notflags)); +} + + + +securityrec edit_sec(int y, int x, securityrec sec, char *shdr) +{ + int c, i, xx, yy, s; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(4,3,shdr); + set_color(CYAN, BLACK); + xx = 3; + yy = 6; + + for (i = 0; i < 32; i++) { + if (i == 11) { + xx = 28; + yy = 6; + } + if (i == 22) { + xx = 53; + yy = 6; + } + set_color(CYAN,BLACK); + mvprintw(yy, xx, (char *)"%2d. %-16s", i+1, CFG.fname[i]); + yy++; + } + mvprintw(16,53, "33. Security level"); + + for (;;) { + set_color(WHITE, BLACK); + xx = 24; + yy = 6; + + for (i = 0; i < 32; i++) { + if (i == 11) { + xx = 49; + yy = 6; + } + if (i == 22) { + xx = 74; + yy = 6; + } + c = '-'; + if ((sec.flags >> i) & 1) + c = 'X'; + if ((sec.notflags >> i) & 1) + c = 'O'; + /* + * The next one may never show up + */ + if (((sec.flags >> i) & 1) && ((sec.notflags >> i) & 1)) + c = '!'; + mvprintw(yy,xx,(char *)"%c", c); + yy++; + } + show_int(16,74, sec.level); + s = select_menu(33); + + switch(s) { + case 0: + return sec; + case 33: + sec.level = edit_int(16,74, sec.level, (char *)"^Security level^ 0..65535"); + break; + default: + if ((sec.notflags >> (s - 1)) & 1) { + sec.notflags = (sec.notflags ^ (1 << (s - 1))); + break; + } + if ((sec.flags >> (s - 1)) & 1) { + sec.flags = (sec.flags ^ (1 << (s - 1))); + sec.notflags = (sec.notflags | (1 << (s - 1))); + break; + } + sec.flags = (sec.flags | (1 << (s - 1))); + break; + } + } +} + + + +securityrec edit_usec(int y, int x, securityrec sec, char *shdr) +{ + int c, i, xx, yy, s; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(4,3,shdr); + set_color(CYAN, BLACK); + xx = 3; + yy = 6; + + for (i = 0; i < 32; i++) { + if (i == 11) { + xx = 28; + yy = 6; + } + if (i == 22) { + xx = 53; + yy = 6; + } + set_color(CYAN,BLACK); + mvprintw(yy, xx, (char *)"%2d. %-16s", i+1, CFG.fname[i]); + yy++; + } + mvprintw(16,53, "33. Security level"); + + for (;;) { + set_color(WHITE, BLACK); + xx = 24; + yy = 6; + + for (i = 0; i < 32; i++) { + if (i == 11) { + xx = 49; + yy = 6; + } + if (i == 22) { + xx = 74; + yy = 6; + } + c = '-'; + if ((sec.flags >> i) & 1) + c = 'X'; + if ((sec.notflags >> i) & 1) + c = 'O'; + /* + * The next one may never show up + */ + if (((sec.flags >> i) & 1) && ((sec.notflags >> i) & 1)) + c = '!'; + mvprintw(yy,xx,(char *)"%c", c); + yy++; + } + show_int(16,74, sec.level); + s = select_menu(33); + + switch(s) { + case 0: + return sec; + case 33: + sec.level = edit_int(16,74, sec.level, (char *)"^Security level^ 0..65535"); + break; + default: + if ((sec.flags >> (s - 1)) & 1) { + sec.flags = (sec.flags ^ (1 << (s - 1))); + break; + } + sec.flags = (sec.flags | (1 << (s - 1))); + break; + } + } +} + + + +char *get_secstr(securityrec S) +{ + static char temp[45]; + + memset(&temp, 0, sizeof(temp)); + sprintf(temp, "%-5d %s", S.level, getflag(S.flags, S.notflags)); + return temp; +} + + + +char *getmsgtype(int val) +{ + switch (val) { + case LOCALMAIL: return (char *)"Local "; + case NETMAIL: return (char *)"Netmail "; + case ECHOMAIL: return (char *)"Echomail"; + case NEWS: return (char *)"News "; + default: return NULL; + } +} + + + +void show_msgtype(int y, int x, int val) +{ + mvprintw(y, x, getmsgtype(val)); +} + + + +int edit_msgtype(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Message Type^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_msgtype(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < NEWS) + val++; + else + val = LOCALMAIL; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_msgtype(y, x, val); + fflush(stdout); + return val; +} + + +char *getemailmode(int val) +{ + switch (val) { + case E_NOISP: return (char *)"No ISP "; + case E_TMPISP: return (char *)"Dial. ISP"; + case E_PRMISP: return (char *)"Perm. ISP"; + default: return NULL; + } +} + + + +void show_emailmode(int y, int x, int val) +{ + mvprintw(y, x, getemailmode(val)); +} + + + +int edit_emailmode(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^ISP Email Mode^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_emailmode(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < E_PRMISP) + val++; + else + val = E_NOISP; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_emailmode(y, x, val); + return val; +} + + + +char *getmsgkinds(int val) +{ + switch (val) { + case BOTH: return (char *)"Private/Public "; + case PRIVATE: return (char *)"Private only "; + case PUBLIC: return (char *)"Public only "; + case RONLY: return (char *)"Read Only "; + case FTNMOD: return (char *)"FTN moderated "; + case USEMOD: return (char *)"Usenet moderated"; + default: return NULL; + } +} + + + +void show_msgkinds(int y, int x, int val) +{ + mvprintw(y, x, getmsgkinds(val)); +} + + + +int edit_msgkinds(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Message Kinds^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_msgkinds(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < USEMOD) + val++; + else + val = BOTH; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_msgkinds(y, x, val); + return val; +} + + + +char *getlinetype(int val) +{ + switch (val) { + case POTS: return (char *)"POTS "; + case ISDN: return (char *)"ISDN "; + case NETWORK: return (char *)"Network"; + case LOCAL: return (char *)"Local "; + default: return NULL; + } +} + + + +void show_linetype(int y, int x, int val) +{ + mvprintw(y, x, getlinetype(val)); +} + + + +int edit_linetype(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Line Type^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_linetype(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < LOCAL) + val++; + else + val = POTS; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_linetype(y, x, val); + return val; +} + + + +char *getservice(int val) +{ + switch (val) { + case AREAMGR: return (char *)"AreaMgr"; + case FILEMGR: return (char *)"FileMgr"; + case EMAIL: return (char *)"Email "; + default: return NULL; + } +} + + + +void show_service(int y, int x, int val) +{ + mvprintw(y, x, getservice(val)); +} + + + +int edit_service(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Service Type^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_service(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < EMAIL) + val++; + else + val = AREAMGR; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_service(y, x, val); + return val; +} + + + +char *getnewsmode(int val) +{ + switch (val) { + case FEEDINN: return (char *)"NNTP feed "; + case FEEDRNEWS: return (char *)"rnews feed"; + case FEEDUUCP: return (char *)"UUCP feed "; + default: return NULL; + } +} + + + +void show_newsmode(int y, int x, int val) +{ + mvprintw(y, x, getnewsmode(val)); +} + + + +int edit_newsmode(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Newsfeed mode^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_newsmode(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < FEEDUUCP) + val++; + else + val = FEEDINN; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_newsmode(y, x, val); + return val; +} + + + +void show_magictype(int y, int x, int val) +{ + mvprintw(y, x, getmagictype(val)); +} + + + +int edit_magictype(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Magic type^ with spacebar, press whene done"); + + do { + set_color(YELLOW, BLUE); + show_magictype(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < MG_DELETE) + val++; + else + val = 0; + } + + } while ((ch != KEY_ENTER) && (ch != '\012')); + + set_color(WHITE, BLACK); + show_magictype(y, x, val); + return val; +} + + + +char *getmagictype(int val) +{ + switch(val) { + case MG_EXEC: return (char *)"Execute "; + case MG_COPY: return (char *)"Copy file "; + case MG_UNPACK: return (char *)"Unpack file "; + case MG_KEEPNUM: return (char *)"Keep number "; + case MG_MOVE: return (char *)"Move file "; + case MG_UPDALIAS: return (char *)"Update alias"; + case MG_ADOPT: return (char *)"Adopt file "; + case MG_OTHER: return (char *)"Other path "; + case MG_DELETE: return (char *)"Delete file "; + default: return NULL; + } +} + + + +void show_aka(int y, int x, fidoaddr aka) +{ + char temp[24]; + + if (aka.point == 0) + sprintf(temp, "%d:%d/%d@%s", aka.zone, aka.net, aka.node, aka.domain); + else + sprintf(temp, "%d:%d/%d.%d@%s", aka.zone, aka.net, aka.node, aka.point, aka.domain); + mvprintw(y, x, temp); +} + + + +void edit_color(int *fg, int *bg, char *help) +{ + int ch, f, b; + char temp[81]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 6, "1.7 EDIT COLORS"); + + sprintf(temp, "Change ^%s^ color with arrow keys, press whene done", help); + showhelp(help); + + for (f = 0; f < 16; f++) + for (b = 0; b < 8; b++) { + set_color(f, b); + mvprintw(b + 9, f + 33, "."); + } + f = (* fg); + b = (* bg); + + for (;;) { + set_color(f, b); + mvprintw(7, 6, "This is an example..."); + fflush(stdout); + mvprintw(b + 9, f + 33, "*"); + ch = readkey(10,10,f,b); + mvprintw(b + 9, f + 33, "."); + switch(ch) { + case KEY_LINEFEED: + case KEY_ENTER: (* fg) = f; + (* bg) = b; + return; + case KEY_LEFT: if (f > 0) + f--; + break; + case KEY_RIGHT: if (f < 15) + f++; + break; + case KEY_UP: if (b > 0) + b--; + break; + case KEY_DOWN: if (b < 7) + b++; + break; + } + } +} + + + +char *getmenutype(int val) +{ + switch (val) { + case 1: return (char *)"Goto another menu"; + case 2: return (char *)"Gosub another menu"; + case 3: return (char *)"Return from gosub"; + case 4: return (char *)"Return to top menu"; + case 5: return (char *)"Display A?? file w/Ctrl codes"; + case 6: return (char *)"Display menu prompt"; + case 7: return (char *)"Run external program in shell"; + case 8: return (char *)"Show product information"; + case 9: return (char *)"Display todays callers list"; + case 10: return (char *)"Display user list"; + case 11: return (char *)"Display time statistics"; + case 12: return (char *)"Page sysop for a chat"; + case 13: return (char *)"Terminate call"; + case 14: return (char *)"Make a log entry"; + case 15: return (char *)"Print text to screen"; + case 16: return (char *)"Who's currently on-line"; + case 17: return (char *)"Comment to sysop"; + case 18: return (char *)"Send an on-line message"; + case 19: return (char *)"Display textfile with more"; + case 20: return (char *)"Display .A?? file with Enter"; + + case 22: return (char *)"Message to nextuser door"; + case 23: return (char *)"Time banking system"; + + case 25: return (char *)"Safe cracker door"; + + case 101: return (char *)"Select new file area"; + case 102: return (char *)"List files in current area"; + case 103: return (char *)"View a textfile"; + case 104: return (char *)"Download tagged files"; + case 105: return (char *)"Raw directory listing"; + case 106: return (char *)"Search file on keyword"; + case 107: return (char *)"Search file on filename"; + case 108: return (char *)"Scan for new files"; + case 109: return (char *)"Upload a file"; + case 110: return (char *)"Edit the taglist"; + case 111: return (char *)"View file in home directory"; + case 112: return (char *)"Download a specific file"; + case 113: return (char *)"Copy file to home directory"; + case 114: return (char *)"List files in home directory"; + case 115: return (char *)"Delete file in home directory"; + case 116: return (char *)"Unpack file in home directory"; + case 117: return (char *)"Pack files in home directory"; + case 118: return (char *)"Download from home directory"; + case 119: return (char *)"Upload to home directory"; + + case 201: return (char *)"Select new message area"; + case 202: return (char *)"Post a new message"; + case 203: return (char *)"Read messages"; + case 204: return (char *)"Check for new mail"; + case 205: return (char *)"Quick-scan messages"; + case 206: return (char *)"Delete a specific message"; + case 207: return (char *)"Show mail status"; + case 208: return (char *)"OLR Tag Area"; + case 209: return (char *)"OLR Remove Area"; + case 210: return (char *)"OLR View Areas"; + case 211: return (char *)"OLR Restrict Date"; + case 212: return (char *)"OLR Upload"; + case 213: return (char *)"OLR Download BlueWave"; + case 214: return (char *)"OLR Download QWK"; + case 215: return (char *)"OLR Download ASCII"; + case 216: return (char *)"Read email"; + case 217: return (char *)"Post email"; + case 218: return (char *)"Trash email"; + case 219: return (char *)"Choose mailbox"; + case 220: return (char *)"Quick-scan email's"; + case 301: return (char *)"Change transfer protocol"; + case 302: return (char *)"Change password"; + case 303: return (char *)"Change location"; + case 304: return (char *)"Change graphics mode"; + case 305: return (char *)"Change voice phone"; + case 306: return (char *)"Change data phone"; + case 307: return (char *)"Change show news bulletins"; + case 308: return (char *)"Change screen length"; + case 309: return (char *)"Change date of birth"; + case 310: return (char *)"Change language"; + case 311: return (char *)"Change hot-keys"; + case 312: return (char *)"Change handle (alias)"; + case 313: return (char *)"Change check for new mail"; + case 314: return (char *)"Change do-not-disturb"; + case 315: return (char *)"Change check for new files"; + case 316: return (char *)"Change fullscreen editor"; + + case 401: return (char *)"Add oneliner"; + case 402: return (char *)"List oneliners"; + case 403: return (char *)"Show a oneliner"; + case 404: return (char *)"Mark oneliner for deletion"; + case 405: return (char *)"Print a random oneliner"; + + case 501: return (char *)"Add a BBS"; + case 502: return (char *)"List BBS's"; + case 503: return (char *)"Show a BBS"; + case 504: return (char *)"Mark a BBS for deletion"; + case 505: return (char *)"Print a BBS"; + case 506: return (char *)"Search for a BBS"; + + default: return (char *)"Unknown menu"; + } +} + + + diff --git a/mbsetup/ledit.h b/mbsetup/ledit.h new file mode 100644 index 00000000..c86a1e4b --- /dev/null +++ b/mbsetup/ledit.h @@ -0,0 +1,80 @@ +#ifndef _LEDIT_H +#define _LEDIT_H + +int yes_no(char *); +void errmsg(const char *, ...); +void show_field(int, int, char *, int, int); +void newinsert(int, int, int); +char *edit_field(int, int, int, int, char *); +char *select_record(int, int); +char *select_area(int, int); +char *select_pick(int, int); +char *select_show(int); +int select_menu(int); +int select_tag(int); +void show_str(int, int, int, char *); +char *edit_str(int, int, int, char *, char *); +char *edit_pth(int, int, int, char *, char *); +char *edit_jam(int, int, int, char *, char *); +char *edit_ups(int, int, int, char *, char *); +char *getboolean(int val); +void show_bool(int, int, int); +int edit_bool(int, int, int, char *); +char *getloglevel(long val); +void show_logl(int, int, long); +long edit_logl(long, char *); +char *getflag(unsigned long, unsigned long); +void show_sec(int, int, securityrec); +securityrec edit_sec(int, int, securityrec, char *); +securityrec edit_usec(int, int, securityrec, char *); +char *get_secstr(securityrec); +void show_int(int, int, int); +int edit_int(int, int, int, char *); +void show_ushort(int, int, unsigned short); +unsigned short edit_ushort(int, int, unsigned short, char *); +void show_sbit(int, int, unsigned short, unsigned short); +unsigned short toggle_sbit(int, int, unsigned short, unsigned short, char *); +void show_lbit(int, int, long, long); +long toggle_lbit(int, int, long, long, char *); +char *getmsgtype(int); +void show_msgtype(int, int, int); +int edit_msgtype(int, int, int); +char *getemailmode(int); +void show_emailmode(int, int, int); +int edit_emailmode(int, int, int); +char *getmsgkinds(int); +void show_msgkinds(int, int, int); +int edit_msgkinds(int, int, int); +char *getservice(int); +void show_service(int, int, int); +int edit_service(int, int, int); +char *getnewsmode(int); +void show_newsmode(int, int, int); +int edit_newsmode(int, int, int); +char *getlinetype(int); +void show_linetype(int, int, int); +int edit_linetype(int, int, int); +char *getmagictype(int); +void show_magictype(int, int, int); +int edit_magictype(int, int, int); +void show_aka(int, int, fidoaddr); +void edit_color(int *, int *, char *); +char *getmenutype(int); + + +/* + * Macro's for the edit functions + */ +#define E_STR(y,x,l,str,help) strcpy(str, edit_str(y,x,l,str,(char *)help)); break; +#define E_PTH(y,x,l,str,help) strcpy(str, edit_pth(y,x,l,str,(char *)help)); break; +#define E_UPS(y,x,l,str,help) strcpy(str, edit_ups(y,x,l,str,(char *)help)); break; +#define E_JAM(y,x,l,str,help) strcpy(str, edit_jam(y,x,l,str,(char *)help)); break; +#define E_BOOL(y,x,bool,help) bool = edit_bool(y,x,bool,(char *)help); break; +#define E_INT(y,x,value,help) value = edit_int(y,x,value,(char *)help); break; +#define E_LOGL(grade,txt,af) grade = edit_logl(grade,(char *)txt); af(); break; +#define S_COL(y,x,name,fg,bg) set_color(fg,bg); mvprintw(y,x,name); +#define E_SEC(y,x,sec,hdr,af) sec = edit_sec(y,x,sec,(char *)hdr); af(); break; +#define E_USEC(y,x,sec,hdr,af) sec = edit_usec(y,x,sec,(char *)hdr); af(); break; + +#endif /* _LEDIT_H */ + diff --git a/mbsetup/m_archive.c b/mbsetup/m_archive.c new file mode 100644 index 00000000..6cbe58e9 --- /dev/null +++ b/mbsetup/m_archive.c @@ -0,0 +1,577 @@ +/***************************************************************************** + * + * File ..................: setup/m_archive.c + * Purpose ...............: Setup Archive structure. + * Last modification date : 22-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_archive.h" + + + +int ArchUpdated = 0; + + +/* + * Count nr of archiver records in the database. + * Creates the database if it doesn't exist. + */ +int CountArchive(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + archiverhdr.hdrsize = sizeof(archiverhdr); + archiverhdr.recsize = sizeof(archiver); + fwrite(&archiverhdr, sizeof(archiverhdr), 1, fil); + /* + * Create default records + */ + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "ARC Version 5.21"); + sprintf(archiver.name, "ARC"); + archiver.available = TRUE; + sprintf(archiver.marc, "/usr/bin/arc anw"); + sprintf(archiver.tarc, "/usr/bin/arc tnw"); + sprintf(archiver.funarc, "/usr/bin/arc xnw"); + sprintf(archiver.munarc, "/usr/bin/arc enw"); + sprintf(archiver.iunarc, "/usr/bin/arc enw"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "LHarc"); + sprintf(archiver.name, "LHA"); + archiver.available = TRUE; + sprintf(archiver.marc, "/usr/bin/lha aq"); + sprintf(archiver.tarc, "/usr/bin/lha tq"); + sprintf(archiver.funarc, "/usr/bin/lha xqf"); + sprintf(archiver.munarc, "/usr/bin/lha eqf"); + sprintf(archiver.iunarc, "/usr/bin/lha eqf"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "RAR by Eugene Roshal"); + sprintf(archiver.name, "RAR"); + archiver.available = TRUE; + sprintf(archiver.farc, "/usr/bin/rar a -y -r"); + sprintf(archiver.marc, "/usr/bin/rar a -y"); + sprintf(archiver.barc, "/usr/bin/rar c -y"); + sprintf(archiver.tarc, "/usr/bin/rar t -y"); + sprintf(archiver.funarc, "/usr/bin/unrar x -o+ -y -r"); + sprintf(archiver.munarc, "/usr/bin/unrar e -o+ -y"); + sprintf(archiver.iunarc, "/usr/bin/unrar e"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "TAR the GNU version"); + sprintf(archiver.name, "TAR"); + archiver.available = TRUE; + sprintf(archiver.farc, "/bin/tar cfz"); + sprintf(archiver.marc, "/bin/tar Afz"); + sprintf(archiver.tarc, "/bin/tar tfz"); + sprintf(archiver.funarc, "/bin/tar xfz"); + sprintf(archiver.munarc, "/bin/tar xfz"); + sprintf(archiver.iunarc, "/bin/tar xfz"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "UNARJ by Robert K Jung"); + sprintf(archiver.name, "ARJ"); + archiver.available = TRUE; + sprintf(archiver.tarc, "/usr/bin/unarj t"); + sprintf(archiver.funarc, "/usr/bin/unarj x"); + sprintf(archiver.munarc, "/usr/bin/unarj e"); + sprintf(archiver.iunarc, "/usr/bin/unarj e"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "ZIP and UNZIP by Info-ZIP"); + sprintf(archiver.name, "ZIP"); + archiver.available = TRUE; + sprintf(archiver.farc, "/usr/bin/zip -r -q"); + sprintf(archiver.marc, "/usr/bin/zip -q"); + sprintf(archiver.barc, "/usr/bin/zip -z"); + sprintf(archiver.tarc, "/usr/bin/zip -T"); + sprintf(archiver.funarc, "/usr/bin/unzip -o -q"); + sprintf(archiver.munarc, "/usr/bin/unzip -o -j -L"); + sprintf(archiver.iunarc, "/usr/bin/unzip -o -j"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "ZOO archiver"); + sprintf(archiver.name, "ZOO"); + archiver.available = TRUE; + sprintf(archiver.farc, "/usr/bin/zoo aq"); + sprintf(archiver.marc, "/usr/bin/zoo aq:O"); + sprintf(archiver.barc, "/usr/bin/zoo aqC"); + sprintf(archiver.funarc, "/usr/bin/zoo xqO"); + sprintf(archiver.munarc, "/usr/bin/zoo eq:O"); + sprintf(archiver.iunarc, "/usr/bin/zoo eqO"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + fclose(fil); + return 7; + } else + return -1; + } + + fread(&archiverhdr, sizeof(archiverhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - archiverhdr.hdrsize) / archiverhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenArchive(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/archiver.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = archiverhdr.recsize; + if (oldsize != sizeof(archiver)) + ArchUpdated = 1; + else + ArchUpdated = 0; + archiverhdr.hdrsize = sizeof(archiverhdr); + archiverhdr.recsize = sizeof(archiver); + fwrite(&archiverhdr, sizeof(archiverhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&archiver, 0, sizeof(archiver)); + while (fread(&archiver, oldsize, 1, fin) == 1) { + fwrite(&archiver, sizeof(archiver), 1, fout); + memset(&archiver, 0, sizeof(archiver)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseArchive(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *arc = NULL, *tmp; + + sprintf(fin, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/archiver.temp", getenv("MBSE_ROOT")); + + if (ArchUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&archiverhdr, archiverhdr.hdrsize, 1, fi); + fwrite(&archiverhdr, archiverhdr.hdrsize, 1, fo); + + while (fread(&archiver, archiverhdr.recsize, 1, fi) == 1) + if (!archiver.deleted) + fill_stlist(&arc, archiver.comment, ftell(fi) - archiverhdr.recsize); + sort_stlist(&arc); + + for (tmp = arc; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&archiver, archiverhdr.recsize, 1, fi); + fwrite(&archiver, archiverhdr.recsize, 1, fo); + } + + tidy_stlist(&arc); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"archiver.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendArchive(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/archiver.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&archiver, 0, sizeof(archiver)); + fwrite(&archiver, sizeof(archiver), 1, fil); + fclose(fil); + ArchUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditArchRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Archiver"); + + sprintf(mfile, "%s/etc/archiver.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(archiverhdr) + ((Area -1) * sizeof(archiver)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&archiver, sizeof(archiver), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&archiver, crc, sizeof(archiver)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 2, "3. EDIT ARCHIVER"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Comment"); + mvprintw( 8, 2, "2. Name"); + mvprintw( 9, 2, "3. Available"); + mvprintw(10, 2, "4. Deleted"); + mvprintw(11, 2, "5. Arc files"); + mvprintw(12, 2, "6. Arc mail"); + mvprintw(13, 2, "7. Banners"); + mvprintw(14, 2, "8. Arc test"); + mvprintw(15, 2, "9. Un. files"); + mvprintw(16, 2, "10. Un. mail"); + mvprintw(17, 2, "11. FILE_ID"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16,40, archiver.comment); + show_str( 8,16, 5, archiver.name); + show_bool(9,16, archiver.available); + show_bool(10,16, archiver.deleted); + show_str(11,16,64, archiver.farc); + show_str(12,16,64, archiver.marc); + show_str(13,16,64, archiver.barc); + show_str(14,16,64, archiver.tarc); + show_str(15,16,64, archiver.funarc); + show_str(16,16,64, archiver.munarc); + show_str(17,16,64, archiver.iunarc); + + j = select_menu(11); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&archiver, crc1, sizeof(archiver)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&archiver, sizeof(archiver), 1, fil); + fclose(fil); + ArchUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,16,40,archiver.comment, "The ^Comment^ for this record") + case 2: E_STR( 8,16,5, archiver.name, "The ^name^ of this archiver") + case 3: E_BOOL( 9,16, archiver.available,"Switch if this archiver is ^Available^ for use.") + case 4: E_BOOL(10,16, archiver.deleted, "Is this archiver ^deleted^") + case 5: E_STR( 11,16,64,archiver.farc, "The ^Archive^ command for files") + case 6: E_STR( 12,16,64,archiver.marc, "The ^Archive^ command for mail packets") + case 7: E_STR( 13,16,64,archiver.barc, "The ^Archive^ command to insert/replace banners") + case 8: E_STR( 14,16,64,archiver.tarc, "The ^Archive^ command to test an archive") + case 9: E_STR( 15,16,64,archiver.funarc, "The ^Unarchive^ command for files") + case 10:E_STR( 16,16,64,archiver.munarc, "The ^Unarchive^ command for mail packets") + case 11:E_STR( 17,16,64,archiver.iunarc, "The ^Unarchive^ command to extract the FILE_ID.DIZ file") + } + } + + return 0; +} + + + +void EditArchive(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountArchive(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenArchive() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "3. ARCHIVER SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/archiver.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(archiverhdr) + ((i - 1) * archiverhdr.recsize); + fseek(fil, offset, 0); + fread(&archiver, archiverhdr.recsize, 1, fil); + if (i == 11) { + x = 42; + y = 7; + } + if (archiver.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", i, archiver.comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + /* Show records here */ + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseArchive(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendArchive() == 0) { + records++; + working(3, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditArchRec(atoi(pick)); + } +} + + + +char *PickArchive(char *shdr) +{ + static char Arch[6] = ""; + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return Arch; + } + + records = CountArchive(); + if (records == -1) { + working(2, 0, 0); + return Arch; + } + + working(0, 0, 0); + + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. ARCHIVER SELECT", shdr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(archiverhdr) + ((i - 1) * archiverhdr.recsize); + fseek(fil, offset, 0); + fread(&archiver, archiverhdr.recsize, 1, fil); + if (i == 11) { + x = 41; + y = 7; + } + if (archiver.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", i, archiver.comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + strcpy(pick, select_pick(records, 20)); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = sizeof(archiverhdr) + ((atoi(pick) - 1) * archiverhdr.recsize); + fseek(fil, offset, 0); + fread(&archiver, archiverhdr.recsize, 1, fil); + strcpy(Arch, archiver.name); + } + fclose(fil); + } + } + return Arch; +} + + +int archive_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *arch; + int j; + + sprintf(temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((arch = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 3, 0, page, (char *)"Archiver programs"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&archiverhdr, sizeof(archiverhdr), 1, arch); + while ((fread(&archiver, archiverhdr.recsize, 1, arch)) == 1) { + + if (j == 4) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Comment %s\n", archiver.comment); + fprintf(fp, " Short name %s\n", archiver.name); + fprintf(fp, " Available %s\n", getboolean(archiver.available)); + fprintf(fp, " Pack files %s\n", archiver.farc); + fprintf(fp, " Pack mail %s\n", archiver.marc); + fprintf(fp, " Pack banners %s\n", archiver.barc); + fprintf(fp, " Test archive %s\n", archiver.tarc); + fprintf(fp, " Unpack files %s\n", archiver.funarc); + fprintf(fp, " Unpack mail %s\n", archiver.munarc); + fprintf(fp, " Get FILE_ID.DIZ %s\n", archiver.iunarc); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(arch); + return page; +} + + + diff --git a/mbsetup/m_archive.h b/mbsetup/m_archive.h new file mode 100644 index 00000000..fe06c300 --- /dev/null +++ b/mbsetup/m_archive.h @@ -0,0 +1,13 @@ +/* m_archive.h */ + +#ifndef _ARCHIVE_H +#define _ARCHIVE_H + + +int CountArchive(void); +void EditArchive(void); +char *PickArchive(char *); +int archive_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_bbs.c b/mbsetup/m_bbs.c new file mode 100644 index 00000000..68766a9c --- /dev/null +++ b/mbsetup/m_bbs.c @@ -0,0 +1,120 @@ +/***************************************************************************** + * + * File ..................: m_bbs.c + * Purpose ...............: BBS Setup Program + * Last modification date : 17-Jul-1999 + * Todo ..................: + * Edit BBS lists + * Edit timebank data + * Edit safe data + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_lang.h" +#include "m_protocol.h" +#include "m_ol.h" +#include "m_fgroup.h" +#include "m_farea.h" +#include "m_menu.h" +#include "m_bbs.h" +#include "m_limits.h" + + +void bbs_menu(void) +{ + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8. BBS SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Security Limits"); + mvprintw( 8, 6, "2. Edit Language Setup"); + mvprintw( 9, 6, "3. Edit BBS Menus"); + mvprintw(10, 6, "4. Edit File Areas"); + mvprintw(11, 6, "5. Edit Transfer Protocols"); + mvprintw(12, 6, "6. Edit BBS List Data"); + mvprintw(13, 6, "7. Edit Oneliners"); + mvprintw(14, 6, "8. Edit TimeBank data"); + mvprintw(15, 6, "9. Edit Safe Cracker data"); + + switch(select_menu(9)) { + case 0: + return; + + case 1: + EditLimits(); + break; + + case 2: + EditLanguage(); + break; + + case 3: + EditMenus(); + break; + + case 4: + EditFilearea(); + break; + + case 5: + EditProtocol(); + break; + + case 6: + break; + + case 7: + ol_menu(); + break; + } + } +} + + + +int bbs_doc(FILE *fp, FILE *toc, int page) +{ + page = newpage(fp, page); + addtoc(fp, toc, 8, 0, page, (char *)"BBS setup"); + + page = bbs_limits_doc(fp, toc, page); + page = bbs_lang_doc(fp, toc, page); + page = bbs_menu_doc(fp, toc, page); + page = bbs_file_doc(fp, toc, page); + page = bbs_prot_doc(fp, toc, page); + + return page; +} + + diff --git a/mbsetup/m_bbs.h b/mbsetup/m_bbs.h new file mode 100644 index 00000000..9c9e53e2 --- /dev/null +++ b/mbsetup/m_bbs.h @@ -0,0 +1,8 @@ +#ifndef _MBBS_H +#define _MBBS_H + +void bbs_menu(void); +int bbs_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_domain.c b/mbsetup/m_domain.c new file mode 100644 index 00000000..b8a3de39 --- /dev/null +++ b/mbsetup/m_domain.c @@ -0,0 +1,485 @@ +/***************************************************************************** + * + * File ..................: m_domain.c + * Purpose ...............: Domain Setup + * Last modification date : 23-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_menu.h" +#include "m_domain.h" + + +int DomainUpdated; + + +/* + * Count nr of domtrans records in the database. + * Creates the database if it doesn't exist. + */ +int CountDomain(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/domain.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + domainhdr.hdrsize = sizeof(domainhdr); + domainhdr.recsize = sizeof(domtrans); + domainhdr.lastupd = time(NULL); + fwrite(&domainhdr, sizeof(domainhdr), 1, fil); + memset(&domtrans, 0, sizeof(domtrans)); + domtrans.Active = TRUE; + sprintf(domtrans.ftndom, ".z1.fidonet"); + sprintf(domtrans.intdom, ".z1.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z2.fidonet"); + sprintf(domtrans.intdom, ".z2.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z3.fidonet"); + sprintf(domtrans.intdom, ".z3.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z4.fidonet"); + sprintf(domtrans.intdom, ".z4.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z5.fidonet"); + sprintf(domtrans.intdom, ".z5.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z6.fidonet"); + sprintf(domtrans.intdom, ".z6.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".fidonet"); + sprintf(domtrans.intdom, ".ftn"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + fclose(fil); + return 7; + } else + return -1; + } + + fread(&domainhdr, sizeof(domainhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - domainhdr.hdrsize) / domainhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenDomain(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/domain.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&domainhdr, sizeof(domainhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = domainhdr.recsize; + if (oldsize != sizeof(domtrans)) + DomainUpdated = 1; + else + DomainUpdated = 0; + domainhdr.hdrsize = sizeof(domainhdr); + domainhdr.recsize = sizeof(domtrans); + fwrite(&domainhdr, sizeof(domainhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&domtrans, 0, sizeof(domtrans)); + while (fread(&domtrans, oldsize, 1, fin) == 1) { + fwrite(&domtrans, sizeof(domtrans), 1, fout); + memset(&domtrans, 0, sizeof(domtrans)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseDomain(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + + sprintf(fin, "%s/etc/domain.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/domain.temp", getenv("MBSE_ROOT")); + + if (DomainUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&domainhdr, domainhdr.hdrsize, 1, fi); + fwrite(&domainhdr, domainhdr.hdrsize, 1, fo); + + while (fread(&domtrans, domainhdr.recsize, 1, fi) == 1) { + if (!domtrans.Deleted) + fwrite(&domtrans, domainhdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"domtrans.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendDomain(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&domtrans, 0, sizeof(domtrans)); + /* + * Fill in default values + */ + fwrite(&domtrans, sizeof(domtrans), 1, fil); + fclose(fil); + DomainUpdated = 1; + return 0; + } else + return -1; +} + + + +void DomainScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "17. EDIT DOMAINS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Fidonet"); + mvprintw( 8, 2, "2. Internet"); + mvprintw( 9, 2, "3. Active"); + mvprintw(10, 2, "4. Deleted"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditDomainRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Domain"); + + sprintf(mfile, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&domainhdr, sizeof(domainhdr), 1, fil); + offset = domainhdr.hdrsize + ((Area -1) * domainhdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&domtrans, domainhdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&domtrans, crc, domainhdr.recsize); + working(0, 0, 0); + + for (;;) { + DomainScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,60, domtrans.ftndom); + show_str( 8,18,60, domtrans.intdom); + show_bool( 9,18, domtrans.Active); + show_bool(10,18, domtrans.Deleted); + + switch(select_menu(4)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&domtrans, crc1, domainhdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&domtrans, domainhdr.recsize, 1, fil); + fclose(fil); + DomainUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,60, domtrans.ftndom, "Enter the ^fidonet^ side of this ^domain^.") + case 2: E_STR( 8,18,60, domtrans.intdom, "Enter the ^internet^ side of this ^domain^.") + case 3: E_BOOL( 9,18, domtrans.Active, "If this domain is ^active^") + case 4: E_BOOL(10,18, domtrans.Deleted, "If this record is ^Deleted^") + } + } +} + + + +void EditDomain(void) +{ + int records, i, o, y, from, too; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + struct domrec tdomtrans; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountDomain(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenDomain() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "17. DOMAIN MANAGER"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&domainhdr, sizeof(domainhdr), 1, fil); + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = sizeof(domainhdr) + (((o + i) - 1) * domainhdr.recsize); + fseek(fil, offset, 0); + fread(&domtrans, domainhdr.recsize, 1, fil); + if (domtrans.Deleted) + set_color(LIGHTRED, BLACK); + else if (domtrans.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-31s %-31s", o+i, domtrans.ftndom, domtrans.intdom); + temp[75] = 0; + mvprintw(y, 3, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_menurec(records)); + + if (strncmp(pick, "-", 1) == 0) { + CloseDomain(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendDomain() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "D", 1) == 0) { + mvprintw(LINES -3, 6, "Enter domain number (1..%d) to delete >", records); + y = 0; + y = edit_int(LINES -3, 44, y, (char *)"Enter record number"); + if ((y > 0) && (y <= records) && yes_no((char *)"Remove record")) { + sprintf(temp, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r+")) != NULL) { + offset = ((y - 1) * domainhdr.recsize) + domainhdr.hdrsize; + fseek(fil, offset, SEEK_SET); + fread(&domtrans, domainhdr.recsize, 1, fil); + domtrans.Deleted = TRUE; + fseek(fil, offset, SEEK_SET); + fwrite(&domtrans, domainhdr.recsize, 1, fil); + DomainUpdated = TRUE; + fclose(fil); + } + } + } + + if (strncmp(pick, "M", 1) == 0) { + from = too = 0; + mvprintw(LINES -3, 6, "Enter domain number (1..%d) to move >", records); + from = edit_int(LINES -3, 42, from, (char *)"Enter record number"); + locate(LINES -3, 6); + clrtoeol(); + mvprintw(LINES -3, 6, "Enter new position (1..%d) >", records); + too = edit_int(LINES -3, 36, too, (char *)"Enter destination record number, other will move away"); + if ((from == too) || (from == 0) || (too == 0) || (from > records) || (too > records)) { + errmsg("That makes no sense"); + } else if (yes_no((char *)"Proceed move")) { + sprintf(temp, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r+")) != NULL) { + fseek(fil, ((from -1) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fread(&tdomtrans, domainhdr.recsize, 1, fil); + if (from > too) { + for (i = from; i > too; i--) { + fseek(fil, ((i -2) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fread(&domtrans, domainhdr.recsize, 1, fil); + fseek(fil, ((i -1) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fwrite(&domtrans, domainhdr.recsize, 1, fil); + } + } else { + for (i = from; i < too; i++) { + fseek(fil, (i * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fread(&domtrans, domainhdr.recsize, 1, fil); + fseek(fil, ((i -1) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fwrite(&domtrans, domainhdr.recsize, 1, fil); + } + } + fseek(fil, ((too -1) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fwrite(&tdomtrans, domainhdr.recsize, 1, fil); + fclose(fil); + DomainUpdated = TRUE; + } + } + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o = o + 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o = o - 10; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditDomainRec(atoi(pick)); + } +} + + + +int domain_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/domain.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 15, 0, page, (char *)"Domain manager"); + j = 0; + + fprintf(fp, "\n"); + fprintf(fp, " Fidonet Internet Active\n"); + fprintf(fp, " ------------------------------ ------------------------------ ------\n"); + fread(&domainhdr, sizeof(domainhdr), 1, no); + + while ((fread(&domtrans, domainhdr.recsize, 1, no)) == 1) { + + if (j == 50) { + page = newpage(fp, page); + fprintf(fp, "\n"); + fprintf(fp, " Fidonet Internet Active\n"); + fprintf(fp, " ------------------------------ ------------------------------ ------\n"); + j = 0; + } + + fprintf(fp, " %-30s %-30s %s\n", domtrans.ftndom, domtrans.intdom, getboolean(domtrans.Active)); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_domain.h b/mbsetup/m_domain.h new file mode 100644 index 00000000..80aaefcf --- /dev/null +++ b/mbsetup/m_domain.h @@ -0,0 +1,10 @@ +#ifndef _DOMAIN_H +#define _DOMAIN_H + + +int CountDomain(void); +void EditDomain(void); +int domain_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_farea.c b/mbsetup/m_farea.c new file mode 100644 index 00000000..3b9c42a6 --- /dev/null +++ b/mbsetup/m_farea.c @@ -0,0 +1,587 @@ +/***************************************************************************** + * + * File ..................: m_farea.c + * Purpose ...............: File Setup Program + * Last modification date : 28-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_fgroup.h" +#include "m_archive.h" +#include "m_farea.h" +#include "m_fgroup.h" +#include "m_ngroup.h" + + +int FileUpdated = 0; + + +/* + * Count nr of area records in the database. + * Creates the database if it doesn't exist. + */ +int CountFilearea(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + areahdr.hdrsize = sizeof(areahdr); + areahdr.recsize = sizeof(area); + fwrite(&areahdr, sizeof(areahdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&areahdr, sizeof(areahdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - areahdr.hdrsize) / areahdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenFilearea(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/fareas.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = areahdr.recsize; + if (oldsize != sizeof(area)) + FileUpdated = 1; + else + FileUpdated = 0; + areahdr.hdrsize = sizeof(areahdr); + areahdr.recsize = sizeof(area); + fwrite(&areahdr, sizeof(areahdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&area, 0, sizeof(area)); + while (fread(&area, oldsize, 1, fin) == 1) { + fwrite(&area, sizeof(area), 1, fout); + memset(&area, 0, sizeof(area)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseFilearea(void) +{ + char fin[81], fout[81]; + + sprintf(fin, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/fareas.temp", getenv("MBSE_ROOT")); + + if (FileUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + if ((rename(fout, fin)) == 0) + unlink(fout); + Syslog('+', "Updated \"fareas.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendFilearea(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/fareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&area, 0, sizeof(area)); + /* + * Fill in default values + */ + area.New = TRUE; + area.Dupes = TRUE; + area.FileFind = TRUE; + area.AddAlpha = TRUE; + area.FileReq = TRUE; + fwrite(&area, sizeof(area), 1, fil); + fclose(fil); + FileUpdated = 1; + return 0; + } else + return -1; +} + + + +void FileScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "8.4 EDIT FILE AREA"); + set_color(CYAN, BLACK); + mvprintw( 6, 2, "1. Area Name"); + mvprintw( 7, 2, "2. Path"); + mvprintw( 8, 2, "3. Down Sec."); + mvprintw( 9, 2, "4. Upl. Sec."); + mvprintw(10, 2, "5. List Sec."); + mvprintw(11, 2, "6. Files.bbs"); + mvprintw(12, 2, "7. Available"); + mvprintw(13, 2, "8. Check new"); + mvprintw(14, 2, "9. Dupecheck"); + mvprintw(15, 2, "10. Free area"); + mvprintw(16, 2, "11. Direct DL"); + mvprintw(17, 2, "12. Pwd upl."); + mvprintw(18, 2, "13. Filefind"); + + mvprintw(12,30, "14. Add alpha"); + mvprintw(13,30, "15. CDrom"); + mvprintw(14,30, "16. File req."); + mvprintw(15,30, "17. BBS Group"); + mvprintw(16,30, "18. New group"); + mvprintw(17,30, "19. Min. age"); + mvprintw(18,30, "20. Password"); + + mvprintw(12,59, "21. DL days"); + mvprintw(13,59, "22. FD days"); + mvprintw(14,59, "23. Move area"); + mvprintw(15,59, "24. Cost"); + mvprintw(16,59, "25. Archiver"); + mvprintw(17,59, "26. Upload"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditFileRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit File Area"); + + sprintf(mfile, "%s/etc/fareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&areahdr, sizeof(areahdr), 1, fil); + offset = areahdr.hdrsize + ((Area -1) * areahdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&area, areahdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&area, crc, areahdr.recsize); + working(0, 0, 0); + FileScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6,16,44, area.Name); + show_str( 7,16,64, area.Path); + show_sec( 8,16, area.DLSec); + show_sec( 9,16, area.UPSec); + show_sec(10,16, area.LTSec); + show_str(11,16,64, area.FilesBbs); + show_bool(12,16, area.Available); + show_bool(13,16, area.New); + show_bool(14,16, area.Dupes); + show_bool(15,16, area.Free); + show_bool(16,16, area.DirectDL); + show_bool(17,16, area.PwdUP); + show_bool(18,16, area.FileFind); + + show_bool(12,44, area.AddAlpha); + show_bool(13,44, area.CDrom); + show_bool(14,44, area.FileReq); + show_str(15,44,12, area.BbsGroup); + show_str(16,44,12, area.NewGroup); + show_int(17,44, area.Age); + show_str(18,44,20, (char *)"********************"); + + show_int(12,73, area.DLdays); + show_int(13,73, area.FDdays); + show_int(14,73, area.MoveArea); + show_int(15,73, area.Cost); + show_str(16,73, 5, area.Archiver); + show_int(17,73, area.Upload); + + switch(select_menu(26)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&area, crc1, areahdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&area, areahdr.recsize, 1, fil); + fclose(fil); + FileUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 6,16,44, area.Name, "The ^name^ for this area") + case 2: E_PTH( 7,16,64, area.Path, "The ^path^ for the files in this area") + case 3: E_SEC( 8,16, area.DLSec, "8.4.3 DOWNLOAD SECURITY", FileScreen) + case 4: E_SEC( 9,16, area.UPSec, "8.4.4 UPLOAD SECURITY", FileScreen) + case 5: E_SEC( 10,16, area.LTSec, "8.4.5 LIST SECURITY", FileScreen) + case 6: E_STR( 11,16,64, area.FilesBbs, "The path and name of \"files.bbs\" if area is on CDROM") + case 7: E_BOOL(12,16, area.Available, "Is this area ^available^") + case 8: E_BOOL(13,16, area.New, "Include this area in ^new files^ check") + case 9: E_BOOL(14,16, area.Dupes, "Check this area for ^duplicates^ during upload") + case 10:E_BOOL(15,16, area.Free, "Are all files ^free^ in this area") + case 11:E_BOOL(16,16, area.DirectDL, "Allow ^direct download^ from this area") + case 12:E_BOOL(17,16, area.PwdUP, "Allow ^password^ on uploads") + case 13:E_BOOL(18,16, area.FileFind, "Search this area for ^filefind^ requests") + case 14:E_BOOL(12,44, area.AddAlpha, "Add new files ^alphabetic^ or at the end") + case 15:E_BOOL(13,44, area.CDrom, "Is this area on a ^CDROM^") + case 16:E_BOOL(14,44, area.FileReq, "Allow ^file requests^ from this area") + case 17:strcpy(area.BbsGroup, PickFGroup((char *)"8.4.17")); + FileScreen(); + break; + case 18:strcpy(area.NewGroup, PickNGroup((char *)"8.4.18")); + FileScreen(); + break; + case 19:E_INT( 17,44, area.Age, "The ^minimum age^ to access this area") + case 20:E_STR( 18,44,20, area.Password, "The ^password^ to access this area") + case 21:E_INT( 12,73, area.DLdays, "The not ^downloaded days^ to move/kill files") + case 22:E_INT( 13,73, area.FDdays, "The ^file age^ in days to move/kill files") + case 23:E_INT( 14,73, area.MoveArea, "The ^area to move^ files to, 0 is kill") + case 24:E_INT( 15,73, area.Cost, "The ^cost^ to download a file") + case 25:strcpy(area.Archiver, PickArchive((char *)"8.4")); + FileScreen(); + break; + case 26:E_INT( 17,73, area.Upload, "The ^upload^ area, 0 if upload in this area") + } + } +} + + + +void EditFilearea(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountFilearea(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenFilearea() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "8.4 FILE AREA SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/fareas.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(areahdr) + (((o + i) - 1) * areahdr.recsize); + fseek(fil, offset, 0); + fread(&area, areahdr.recsize, 1, fil); + if (area.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, area.Name); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseFilearea(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendFilearea() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditFileRec(atoi(pick)); + } +} + + + +long PickFilearea(char *shdr) +{ + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return 0; + } + + records = CountFilearea(); + if (records == -1) { + working(2, 0, 0); + return 0; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. FILE AREA SELECT", shdr); + mvprintw(5,3,temp); + set_color(CYAN, BLACK); + if (records) { + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(areahdr) + (((o + i) - 1) * areahdr.recsize); + fseek(fil, offset, SEEK_SET); + fread(&area, areahdr.recsize, 1, fil); + if (area.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-31s", o + i, area.Name); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return 0; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o += 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o -= 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + offset = areahdr.hdrsize + ((atoi(pick) - 1) * areahdr.recsize); + fseek(fil, offset, SEEK_SET); + fread(&area, areahdr.recsize, 1, fil); + fclose(fil); + if (area.Available) + return atoi(pick); + } + } + } +} + + + +int bbs_file_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int i = 0, j = 0; + + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + fread(&areahdr, sizeof(areahdr), 1, no); + page = newpage(fp, page); + addtoc(fp, toc, 8, 4, page, (char *)"BBS File areas"); + + while ((fread(&area, areahdr.recsize, 1, no)) == 1) { + + i++; + if (area.Available) { + + if (j == 1) { + page = newpage(fp, page); + j = 0; + } else { + j++; + } + fprintf(fp, "\n\n"); + fprintf(fp, " Area number %d\n", i); + fprintf(fp, " Area name %s\n", area.Name); + fprintf(fp, " Files path %s\n", area.Path); + fprintf(fp, " Download sec. %s\n", get_secstr(area.DLSec)); + fprintf(fp, " Upload security %s\n", get_secstr(area.UPSec)); + fprintf(fp, " List seccurity %s\n", get_secstr(area.LTSec)); + fprintf(fp, " Path to files.bbs %s\n", area.FilesBbs); + fprintf(fp, " Newfiles scan %s\n", getboolean(area.New)); + fprintf(fp, " Check upl. dupes %s\n", getboolean(area.Dupes)); + fprintf(fp, " Files are free %s\n", getboolean(area.Free)); + fprintf(fp, " Allow direct DL %s\n", getboolean(area.DirectDL)); + fprintf(fp, " Allow pwd upl. %s\n", getboolean(area.PwdUP)); + fprintf(fp, " Filefind on %s\n", getboolean(area.FileFind)); + fprintf(fp, " Add files sorted %s\n", getboolean(area.AddAlpha)); + fprintf(fp, " Files in CDROM %s\n", getboolean(area.CDrom)); + fprintf(fp, " Allow filerequst %s\n", getboolean(area.FileReq)); + fprintf(fp, " BBS group %s\n", area.BbsGroup); + fprintf(fp, " Newfiles group %s\n", area.NewGroup); + fprintf(fp, " Minimum age %d\n", area.Age); + fprintf(fp, " Area password %s\n", area.Password); + fprintf(fp, " Kill DL days %d\n", area.DLdays); + fprintf(fp, " Kill FD days %d\n", area.FDdays); + fprintf(fp, " Move to area %d\n", area.MoveArea); + fprintf(fp, " Archiver %s\n", area.Archiver); + fprintf(fp, " Upload area %d\n", area.Upload); + } + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_farea.h b/mbsetup/m_farea.h new file mode 100644 index 00000000..db102cf0 --- /dev/null +++ b/mbsetup/m_farea.h @@ -0,0 +1,11 @@ +#ifndef _FAREA_H +#define _FAREA_H + + +int CountFilearea(void); +void EditFilearea(void); +long PickFilearea(char *); +int bbs_file_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_fdb.c b/mbsetup/m_fdb.c new file mode 100644 index 00000000..187efbfb --- /dev/null +++ b/mbsetup/m_fdb.c @@ -0,0 +1,282 @@ +/***************************************************************************** + * + * File ..................: setup/m_fdb.c + * Purpose ...............: Edit Files DataBase. + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1999-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_farea.h" +#include "m_fdb.h" + + +void E_F(long); +void EditFile(void); + + +void FHeader(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "14. EDIT FILE"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, " FileName"); + mvprintw( 8, 2, " Long fn"); + mvprintw( 9, 2, " FileSize"); + mvprintw(10, 2, " FileDate"); + mvprintw(11, 2, " Last DL."); + mvprintw(12, 2, " Upl.Date"); + mvprintw(13, 2, "1. Uploader"); + mvprintw(14, 2, "2. Times DL"); + mvprintw(15, 2, "3. Times FTP"); + mvprintw(16, 2, "4. Times Req"); + mvprintw(17, 2, "5. Password"); + mvprintw(18, 2, "6. Cost"); + + mvprintw(14,42, "7. Free"); + mvprintw(15,42, "8. Deleted"); + mvprintw(16,42, " Missing"); + mvprintw(17,42, "9. No Kill"); + mvprintw(18,42, "10. Announced"); +} + + + +void EditFile() +{ + FHeader(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16,12, file.Name); + show_str( 8,16,64, file.LName); + show_int( 9,16, file.Size); + mvprintw(10,16, (char *)"%s %s", StrDateDMY(file.FileDate), StrTimeHM(file.FileDate)); + mvprintw(11,16, (char *)"%s %s", StrDateDMY(file.LastDL), StrTimeHM(file.LastDL)); + mvprintw(12,16, (char *)"%s %s", StrDateDMY(file.UploadDate), StrTimeHM(file.UploadDate)); + show_str(13,16,36, file.Uploader); + show_int(14,16, file.TimesDL); + show_int(15,16, file.TimesFTP); + show_int(16,16, file.TimesReq); + show_str(17,16,15, file.Password); + show_int(18,16, file.Cost); + + show_bool(14,56, file.Free); + show_bool(15,56, file.Deleted); + show_bool(16,56, file.Missing); + show_bool(17,56, file.NoKill); + show_bool(18,56, file.Announced); + + switch(select_menu(10)) { + case 0: return; + case 1: E_STR( 13,16,35, file.Uploader, "The ^uploader^ of this file") + case 2: E_INT( 14,16, file.TimesDL, "The number of times file is sent with ^download^") + case 3: E_INT( 15,16, file.TimesFTP, "The number of times file is sent with ^FTP or WWW^") + case 4: E_INT( 16,16, file.TimesReq, "The number of times file is sent with ^filerequest^") + case 5: E_STR( 17,16,15, file.Password, "The ^password^ to protect this file with") + case 6: E_INT( 18,16, file.Cost, "The ^cost^ of this file") + case 7: E_BOOL(14,56, file.Free, "If this file is a ^free^ download") + case 8: E_BOOL(15,56, file.Deleted, "Should this this file be ^deleted^") + case 9: E_BOOL(17,56, file.NoKill, "File can't be ^killed^ automatic") + case 10:E_BOOL(18,56, file.Announced, "File is ^announced^ as new file") + } + } +} + + + +void E_F(long areanr) +{ + FILE *fil; + char temp[81]; + int i, y, o, records, Ondisk; + char help[81]; + static char *menu = (char *)"0"; + long offset; + time_t Time; + struct stat statfile; + unsigned long crc, crc1; + + clr_index(); + + sprintf(temp, "%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), areanr); + if ((fil = fopen(temp, "r+")) == NULL) { + working(2, 0, 0); + return; + } + + fseek(fil, 0, SEEK_END); + records = ftell(fil) / sizeof(file); + o = 0; + + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 4, "14. EDIT FILES DATABASE"); + + y = 8; + working(1, 0, 0); + + set_color(YELLOW, BLUE); + mvprintw(7, 1, " Nr Filename Size Date Time Description "); +/* 1234 12345678901234 12345678 12-34-1998 12:45 123456789012345678901234567890*/ + set_color(CYAN, BLACK); + + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = ((o + i) - 1) * sizeof(file); + fseek(fil, offset, SEEK_SET); + fread(&file, sizeof(file), 1, fil); + + set_color(WHITE, BLACK); + mvprintw(y, 1, (char *)"%4d.", o + i); + + sprintf(temp, "%s/%s", area.Path, file.Name); + Ondisk = ((stat(temp, &statfile)) != -1); + + if (Ondisk) + set_color(CYAN, BLACK); + else + set_color(LIGHTRED, BLACK); + mvprintw(y, 8, (char *)"%-14s", file.Name); + + if (Ondisk) { + if (file.Size == statfile.st_size) + set_color(CYAN, BLACK); + else + set_color(LIGHTRED, BLACK); + mvprintw(y,23, (char *)"%8ld", file.Size); + + if (file.FileDate == statfile.st_mtime) + set_color(CYAN, BLACK); + else + set_color(LIGHTRED, BLACK); + Time = file.FileDate; + mvprintw(y,32, (char *)"%s %s", StrDateDMY(Time), StrTimeHM(Time)); + } + + set_color(CYAN, BLACK); + sprintf(temp, "%s", file.Desc[0]); + temp[30] = '\0'; + mvprintw(y,49, (char *)"%s", temp); + y++; + } + } + working(0, 0, 0); + + if (records) + if (records > 10) + sprintf(help, "^1..%d^ Edit, ^-^ Return, ^N^/^P^ Page", records); + else + sprintf(help, "^1..%d^ Edit, ^-^ Return", records); + else + sprintf(help, "^-^ Return"); + + showhelp(help); + + while(TRUE) { + mvprintw(LINES - 4, 6, "Enter your choice >"); + menu = (char *)"0"; + menu = edit_field(LINES - 4, 26, 6, '!', menu); + locate(LINES - 4, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) { + fclose(fil); + return; + } + + if (records > 10) { + if (strncmp(menu, "N", 1) == 0) + if ((o + 10) < records) { + o += 10; + break; + } + + if (strncmp(menu, "P", 1) == 0) + if ((o - 10) >= 0) { + o -= 10; + break; + } + } + + if ((atoi(menu) > 0) && (atoi(menu) <= records)) { + working(1, 0, 0); + offset = (atoi(menu) - 1) * sizeof(file); + fseek(fil, offset, SEEK_SET); + fread(&file, sizeof(file), 1, fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&file, crc, sizeof(file)); + + sprintf(temp, "%s/%s", area.Path, file.Name); + if (stat(temp, &statfile) == -1) + file.Missing = TRUE; + + EditFile(); + + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&file, crc1, sizeof(file)); + + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + fseek(fil, offset, SEEK_SET); + fwrite(&file, sizeof(file), 1, fil); + } + } + break; + } + } + + } +} + + + +void EditFDB() +{ + long areanr; + + IsDoing("Browsing Menu"); + + for (;;) { + if ((areanr = PickFilearea((char *)"14")) == 0) + return; + E_F(areanr); + } +} + + diff --git a/mbsetup/m_fdb.h b/mbsetup/m_fdb.h new file mode 100644 index 00000000..1cf3ffcc --- /dev/null +++ b/mbsetup/m_fdb.h @@ -0,0 +1,8 @@ +#ifndef _M_FDB_H +#define _M_FDB_H + +void EditFDB(void); + +#endif + + diff --git a/mbsetup/m_ff.c b/mbsetup/m_ff.c new file mode 100644 index 00000000..112c6584 --- /dev/null +++ b/mbsetup/m_ff.c @@ -0,0 +1,449 @@ +/***************************************************************************** + * + * File ..................: m_ff.c + * Purpose ...............: Filefind Setup + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_ff.h" +#include "m_lang.h" +#include "m_marea.h" + + +int FilefindUpdated = 0; + + +/* + * Count nr of scanmgr records in the database. + * Creates the database if it doesn't exist. + */ +int CountFilefind(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + scanmgrhdr.hdrsize = sizeof(scanmgrhdr); + scanmgrhdr.recsize = sizeof(scanmgr); + fwrite(&scanmgrhdr, sizeof(scanmgrhdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - scanmgrhdr.hdrsize) / scanmgrhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenFilefind(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = scanmgrhdr.recsize; + if (oldsize != sizeof(scanmgr)) + FilefindUpdated = 1; + else + FilefindUpdated = 0; + scanmgrhdr.hdrsize = sizeof(scanmgrhdr); + scanmgrhdr.recsize = sizeof(scanmgr); + fwrite(&scanmgrhdr, sizeof(scanmgrhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&scanmgr, 0, sizeof(scanmgr)); + while (fread(&scanmgr, oldsize, 1, fin) == 1) { + fwrite(&scanmgr, sizeof(scanmgr), 1, fout); + memset(&scanmgr, 0, sizeof(scanmgr)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseFilefind(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *fff = NULL, *tmp; + + sprintf(fin, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + + if (FilefindUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&scanmgrhdr, scanmgrhdr.hdrsize, 1, fi); + fwrite(&scanmgrhdr, scanmgrhdr.hdrsize, 1, fo); + + while (fread(&scanmgr, scanmgrhdr.recsize, 1, fi) == 1) + if (!scanmgr.Deleted) + fill_stlist(&fff, scanmgr.Comment, ftell(fi) - scanmgrhdr.recsize); + sort_stlist(&fff); + + for (tmp = fff; tmp; tmp=tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&scanmgr, scanmgrhdr.recsize, 1, fi); + fwrite(&scanmgr, scanmgrhdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + tidy_stlist(&fff); + unlink(fout); + Syslog('+', "Updated \"scanmgr.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendFilefind(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&scanmgr, 0, sizeof(scanmgr)); + /* + * Fill in default values + */ + fwrite(&scanmgr, sizeof(scanmgr), 1, fil); + fclose(fil); + FilefindUpdated = 1; + return 0; + } else + return -1; +} + + + +void FFScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "13. EDIT FILEFIND AREAS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Comment"); + mvprintw( 8, 2, "2. Origin"); + mvprintw( 9, 2, "3. Aka to use"); + mvprintw(10, 2, "4. Scan area"); + mvprintw(11, 2, "5. Reply area"); + mvprintw(12, 2, "6. Language"); + mvprintw(13, 2, "7. Template"); + mvprintw(14, 2, "8. Active"); + mvprintw(15, 2, "9. Deleted"); + mvprintw(16, 2, "10. Net. reply"); + mvprintw(17, 2, "11. Hi Ascii"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditFfRec(int Area) +{ + FILE *fil; + char mfile[81], temp1[2]; + long offset; + unsigned long crc, crc1; + int i; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Filefind"); + + sprintf(mfile, "%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fil); + offset = scanmgrhdr.hdrsize + ((Area -1) * scanmgrhdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&scanmgr, scanmgrhdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&scanmgr, crc, scanmgrhdr.recsize); + working(0, 0, 0); + + for (;;) { + FFScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,55, scanmgr.Comment); + show_str( 8,18,50, scanmgr.Origin); + show_str( 9,18,35, aka2str(scanmgr.Aka)); + show_str( 10,18,50, scanmgr.ScanBoard); + show_str( 11,18,50, scanmgr.ReplBoard); + sprintf(temp1, "%c", scanmgr.Language); + show_str( 12,18,2, temp1); + show_str( 13,18,14, scanmgr.template); + show_bool(14,18, scanmgr.Active); + show_bool(15,18, scanmgr.Deleted); + show_bool(16,18, scanmgr.NetReply); + show_bool(17,18, scanmgr.HiAscii); + + switch(select_menu(11)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&scanmgr, crc1, scanmgrhdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&scanmgr, scanmgrhdr.recsize, 1, fil); + fclose(fil); + FilefindUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,55, scanmgr.Comment, "The ^comment^ for this area") + case 2: E_STR( 8,18,50, scanmgr.Origin, "The ^origin^ line to append, leave blank for random lines") + case 3: i = PickAka((char *)"13.3", TRUE); + if (i != -1) + scanmgr.Aka = CFG.aka[i]; + break; + case 4: strcpy(scanmgr.ScanBoard, PickMsgarea((char *)"13.4")); + break; + case 5: strcpy(scanmgr.ReplBoard, PickMsgarea((char *)"13.5")); + break; + case 6: scanmgr.Language = PickLanguage((char *)"13.6"); + break; + case 7: E_STR( 13,18,14, scanmgr.template, "The ^template^ file to use for the report") + case 8: E_BOOL(14,18, scanmgr.Active, "If this report is ^active^") + case 9: E_BOOL(15,18, scanmgr.Deleted, "If this record is ^deleted^") + case 10:E_BOOL(16,18, scanmgr.NetReply, "If reply's via ^netmail^ instead of echomail") + case 11:E_BOOL(17,18, scanmgr.HiAscii, "Allow ^Hi ASCII^ in this area") + } + } +} + + + +void EditFilefind(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountFilefind(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenFilefind() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "13. FILEFIND AREAS"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(scanmgrhdr) + (((o + i) - 1) * scanmgrhdr.recsize); + fseek(fil, offset, 0); + fread(&scanmgr, scanmgrhdr.recsize, 1, fil); + if (scanmgr.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, scanmgr.Comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseFilefind(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendFilefind() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditFfRec(atoi(pick)); + } +} + + + +int ff_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 13, 0, page, (char *)"Filefind areas"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, no); + + while ((fread(&scanmgr, scanmgrhdr.recsize, 1, no)) == 1) { + + if (j == 5) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Area comment %s\n", scanmgr.Comment); + fprintf(fp, " Origin line %s\n", scanmgr.Origin); + fprintf(fp, " Aka to use %s\n", aka2str(scanmgr.Aka)); + fprintf(fp, " Scan msg board %s\n", scanmgr.ScanBoard); + fprintf(fp, " Reply msg board %s\n", scanmgr.ReplBoard); + fprintf(fp, " Language %c\n", scanmgr.Language); + fprintf(fp, " Active %s\n", getboolean(scanmgr.Active)); + fprintf(fp, " Netmail reply %s\n", getboolean(scanmgr.NetReply)); + fprintf(fp, "\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_ff.h b/mbsetup/m_ff.h new file mode 100644 index 00000000..c7b5b47c --- /dev/null +++ b/mbsetup/m_ff.h @@ -0,0 +1,10 @@ +#ifndef _FILEFIND_H +#define _FILEFIND_H + + +int CountFilefind(void); +void EditFilefind(void); +int ff_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_fgroup.c b/mbsetup/m_fgroup.c new file mode 100644 index 00000000..07d8bcb9 --- /dev/null +++ b/mbsetup/m_fgroup.c @@ -0,0 +1,585 @@ +/***************************************************************************** + * + * File ..................: setup/m_fgroups.c + * Purpose ...............: Setup FGroups. + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_node.h" +#include "m_ticarea.h" +#include "m_fgroup.h" + + + +int FGrpUpdated = 0; + + +/* + * Count nr of fgroup records in the database. + * Creates the database if it doesn't exist. + */ +int CountFGroup(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + fgrouphdr.hdrsize = sizeof(fgrouphdr); + fgrouphdr.recsize = sizeof(fgroup); + fwrite(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&fgrouphdr, fgrouphdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - fgrouphdr.hdrsize) / fgrouphdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenFGroup(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + FGrpUpdated = 0; + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&fgrouphdr, fgrouphdr.hdrsize, 1, fin); + if (fgrouphdr.hdrsize != sizeof(fgrouphdr)) { + fgrouphdr.hdrsize = sizeof(fgrouphdr); + fgrouphdr.lastupd = time(NULL); + FGrpUpdated = 1; + } + + /* + * In case we are automaitc upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = fgrouphdr.recsize; + if (oldsize != sizeof(fgroup)) + FGrpUpdated = 1; + fgrouphdr.hdrsize = sizeof(fgrouphdr); + fgrouphdr.recsize = sizeof(fgroup); + fwrite(&fgrouphdr, sizeof(fgrouphdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&fgroup, 0, sizeof(fgroup)); + while (fread(&fgroup, oldsize, 1, fin) == 1) { + fwrite(&fgroup, sizeof(fgroup), 1, fout); + memset(&fgroup, 0, sizeof(fgroup)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseFGroup(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *fgr = NULL, *tmp; + + sprintf(fin, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + + if (FGrpUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&fgrouphdr, fgrouphdr.hdrsize, 1, fi); + fwrite(&fgrouphdr, fgrouphdr.hdrsize, 1, fo); + + while (fread(&fgroup, fgrouphdr.recsize, 1, fi) == 1) + if (!fgroup.Deleted) + fill_stlist(&fgr, fgroup.Name, ftell(fi) - fgrouphdr.recsize); + sort_stlist(&fgr); + + for (tmp = fgr; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&fgroup, fgrouphdr.recsize, 1, fi); + fwrite(&fgroup, fgrouphdr.recsize, 1, fo); + } + + tidy_stlist(&fgr); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"fgroups.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendFGroup(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&fgroup, 0, sizeof(fgroup)); + time(&fgroup.StartDate); + fgroup.DivideCost = TRUE; + fwrite(&fgroup, sizeof(fgroup), 1, fil); + fclose(fil); + FGrpUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Check if field can be edited without screwing up the database + */ +int CheckFgroup(void); +int CheckFgroup(void) +{ + int ncnt, tcnt; + + working(1, 0, 0); + ncnt = GroupInNode(fgroup.Name, FALSE); + tcnt = GroupInTic(fgroup.Name); + working(0, 0, 0); + if (ncnt || tcnt) { + errmsg((char *)"Error, %d node(s) and/or %d tic area(s) connected", ncnt, tcnt); + return TRUE; + } + return FALSE; +} + + + +void FgScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10.1 EDIT FILE GROUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Name"); + mvprintw( 8, 6, "2. Comment"); + mvprintw( 9, 6, "3. Active"); + mvprintw(10, 6, "4. Use Aka"); + mvprintw(11, 6, "5. Uplink"); + mvprintw(12, 6, "6. Areas"); + mvprintw(13, 6, "7. Unit Cost"); + mvprintw(14, 6, "8. Unit Size"); + mvprintw(15, 6, "9. Add Prom."); + mvprintw(16, 6, "10. Divide"); + mvprintw(17, 6, "11. Deleted"); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditFGrpRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j, tmp; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit FileGroup"); + + sprintf(mfile, "%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(fgrouphdr) + ((Area -1) * sizeof(fgroup)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&fgroup, sizeof(fgroup), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&fgroup, crc, sizeof(fgroup)); + working(0, 0, 0); + FgScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,20,12, fgroup.Name); + show_str( 8,20,55, fgroup.Comment); + show_bool( 9,20, fgroup.Active); + show_aka( 10,20, fgroup.UseAka); + show_aka( 11,20, fgroup.UpLink); + show_str( 12,20,12, fgroup.AreaFile); + show_int( 13,20, fgroup.UnitCost); + show_int( 14,20, fgroup.UnitSize); + show_int( 15,20, fgroup.AddProm); + show_bool(16,20, fgroup.DivideCost); + show_bool(17,20, fgroup.Deleted); + + j = select_menu(11); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&fgroup, crc1, sizeof(fgroup)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&fgroup, sizeof(fgroup), 1, fil); + fclose(fil); + FGrpUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: if (CheckFgroup()) + break; + E_UPS( 7,20,12,fgroup.Name, "The ^name^ of this file group") + case 2: E_STR( 8,20,55,fgroup.Comment, "The ^description^ of this file group") + case 3: if (CheckFgroup()) + break; + E_BOOL( 9,20, fgroup.Active, "Is this file group ^active^") + case 4: tmp = PickAka((char *)"10.1.4", TRUE); + if (tmp != -1) + fgroup.UseAka = CFG.aka[tmp]; + FgScreen(); + break; + case 5: fgroup.UpLink = PullUplink((char *)"10.1.5"); + FgScreen(); + break; + case 6: E_STR( 12,20,12,fgroup.AreaFile, "The name of the ^Areas File^ from the uplink") + case 7: E_INT( 13,20, fgroup.UnitCost, "The ^cost per size unit^ for this file") + case 8: E_INT( 14,20, fgroup.UnitSize, "The ^unit size^ in KBytes, 0 means cost per file") + case 9: E_INT( 15,20, fgroup.AddProm, "The ^Promillage^ to add or substract of the filecost") + case 10:E_BOOL(16,20, fgroup.DivideCost, "^Divide^ the cost over all downlinks or charge each link full cost") + case 11:if (CheckFgroup()) + break; + E_BOOL(17,20, fgroup.Deleted, "Is this file group ^Deleted^") + } + } + + return 0; +} + + + +void EditFGroup(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountFGroup(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenFGroup() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "10.1 FILE GROUPS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11 ) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(fgrouphdr) + (((o + i) - 1) * fgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&fgroup, fgrouphdr.recsize, 1, fil); + if (fgroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, fgroup.Name, fgroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseFGroup(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendFGroup() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditFGrpRec(atoi(pick)); + } +} + + + +char *PickFGroup(char *shdr) +{ + static char FGrp[21] = ""; + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return FGrp; + } + + records = CountFGroup(); + if (records == -1) { + working(2, 0, 0); + return FGrp; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. FILE GROUP SELECT", shdr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(fgrouphdr) + (((o + i) - 1) * fgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&fgroup, fgrouphdr.recsize, 1, fil); + if (fgroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, fgroup.Name, fgroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return FGrp; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + fil = fopen(temp, "r"); + offset = fgrouphdr.hdrsize + ((atoi(pick) - 1) * fgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&fgroup, fgrouphdr.recsize, 1, fil); + fclose(fil); + strcpy(FGrp, fgroup.Name); + return (FGrp); + } + } +} + + + +int tic_group_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + addtoc(fp, toc, 10, 1, page, (char *)"File processing groups"); + j = 0; + fprintf(fp, "\n\n"); + + fread(&fgrouphdr, sizeof(fgrouphdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&fgrouphdr, fgrouphdr.hdrsize, 1, no); + + while ((fread(&fgroup, fgrouphdr.recsize, 1, no)) == 1) { + if (j == 3) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Name %s\n", fgroup.Name); + fprintf(fp, " Comment %s\n", fgroup.Comment); + fprintf(fp, " Active %s\n", getboolean(fgroup.Active)); + fprintf(fp, " Use Aka %s\n", aka2str(fgroup.UseAka)); + fprintf(fp, " Uplink %s\n", aka2str(fgroup.UpLink)); + fprintf(fp, " Areas file %s\n", fgroup.AreaFile); + fprintf(fp, " Start date %s", ctime(&fgroup.StartDate)); + fprintf(fp, " Last date %s\n", ctime(&fgroup.LastDate)); + +// fprintf(fp, " Total This month Last month\n"); +// fprintf(fp, " ---------- ---------- ----------\n"); +// fprintf(fp, " Files %-10ld %-10ld %-10ld\n", fgroup.Total.files, fgroup.ThisMonth.files, fgroup.LastMonth.files); +// fprintf(fp, " KBytes %-10ld %-10ld %-10ld\n", fgroup.Total.kbytes, fgroup.ThisMonth.kbytes, fgroup.LastMonth.kbytes); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(no); + return page; +} + + + diff --git a/mbsetup/m_fgroup.h b/mbsetup/m_fgroup.h new file mode 100644 index 00000000..bf429b95 --- /dev/null +++ b/mbsetup/m_fgroup.h @@ -0,0 +1,12 @@ +#ifndef _FGROUP_H +#define _FGROUP_H + + +int CountFGroup(void); +void EditFGroup(void); +char *PickFGroup(char *); +int tic_group_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_fido.c b/mbsetup/m_fido.c new file mode 100644 index 00000000..0128a4e6 --- /dev/null +++ b/mbsetup/m_fido.c @@ -0,0 +1,558 @@ +/***************************************************************************** + * + * File ..................: setup/m_fido.c + * Purpose ...............: Setup Fidonet structure. + * Last modification date : 13-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_fido.h" + + + +int FidoUpdated = 0; + + +/* + * Count nr of fidonet records in the database. + * Creates the database if it doesn't exist. + */ +int CountFidonet(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + fidonethdr.hdrsize = sizeof(fidonethdr); + fidonethdr.recsize = sizeof(fidonet); + fwrite(&fidonethdr, sizeof(fidonethdr), 1, fil); + /* + * Fill in the defaults + */ + memset(&fidonet, 0, sizeof(fidonet)); + sprintf(fidonet.comment, "Fidonet network"); + sprintf(fidonet.domain, "fidonet"); + sprintf(fidonet.nodelist, "NODELIST"); + sprintf(fidonet.seclist[0].nodelist, "REGION28"); + fidonet.seclist[0].zone = 2; + fidonet.seclist[0].net = 28; + fidonet.zone[0] = 2; + fidonet.zone[1] = 1; + fidonet.zone[2] = 3; + fidonet.zone[3] = 4; + fidonet.zone[4] = 5; + fidonet.zone[5] = 6; + fidonet.available = TRUE; + fwrite(&fidonet, sizeof(fidonet), 1, fil); + memset(&fidonet, 0, sizeof(fidonet)); + sprintf(fidonet.comment, "Virus network"); + sprintf(fidonet.domain, "virnet"); + sprintf(fidonet.nodelist, "VIRNODES"); + fidonet.zone[0] = 9; + fidonet.available = TRUE; + fwrite(&fidonet, sizeof(fidonet), 1, fil); + fclose(fil); + return 2; + } else + return -1; + } + + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - fidonethdr.hdrsize) / fidonethdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenFidonet(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&fidonethdr, sizeof(fidonethdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = fidonethdr.recsize; + if (oldsize != sizeof(fidonet)) + FidoUpdated = 1; + else + FidoUpdated = 0; + fidonethdr.hdrsize = sizeof(fidonethdr); + fidonethdr.recsize = sizeof(fidonet); + fwrite(&fidonethdr, sizeof(fidonethdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&fidonet, 0, sizeof(fidonet)); + while (fread(&fidonet, oldsize, 1, fin) == 1) { + fwrite(&fidonet, sizeof(fidonet), 1, fout); + memset(&fidonet, 0, sizeof(fidonet)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseFidonet(void) +{ + char fin[81], fout[81], temp[10]; + FILE *fi, *fo; + st_list *fid = NULL, *tmp; + + sprintf(fin, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + + if (FidoUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&fidonethdr, fidonethdr.hdrsize, 1, fi); + fwrite(&fidonethdr, fidonethdr.hdrsize, 1, fo); + + while (fread(&fidonet, fidonethdr.recsize, 1, fi) == 1) + if (!fidonet.deleted) { + sprintf(temp, "%05d", fidonet.zone[0]); + fill_stlist(&fid, temp, ftell(fi) - fidonethdr.recsize); + } + sort_stlist(&fid); + + for (tmp = fid; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&fidonet, fidonethdr.recsize, 1, fi); + fwrite(&fidonet, fidonethdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + unlink(fout); + tidy_stlist(&fid); + + Syslog('+', "Updated \"fidonet.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendFidonet(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&fidonet, 0, sizeof(fidonet)); + fwrite(&fidonet, sizeof(fidonet), 1, fil); + fclose(fil); + FidoUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditFidoRec(int Area) +{ + FILE *fil; + char mfile[81], *temp; + long offset; + int i, j = 0; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Fidonet"); + + sprintf(mfile, "%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(fidonethdr) + ((Area -1) * sizeof(fidonet)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&fidonet, sizeof(fidonet), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&fidonet, crc, sizeof(fidonet)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 6, "2. EDIT FIDONET NETWORK"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Comment"); + mvprintw( 8, 6, "2. Domain name"); + mvprintw( 9, 6, "3. Available"); + mvprintw(10, 6, "4. Deleted"); + mvprintw(11, 6, "5. Main Nodelist"); + mvprintw(12, 6, "6. Merge list #1"); + mvprintw(13, 6, "7. Merge list #2"); + mvprintw(14, 6, "8. Merge list #3"); + mvprintw(15, 6, "9. Merge list #4"); + mvprintw(16, 6, "10. Merge list #5"); + mvprintw(17, 6, "11. Merge list #6"); + mvprintw(12,55, "12. Primary zone"); + mvprintw(13,55, "13. Zone number #2"); + mvprintw(14,55, "14. Zone number #3"); + mvprintw(15,55, "15. Zone number #4"); + mvprintw(16,55, "16. Zone number #5"); + mvprintw(17,55, "17. Zone number #6"); + temp = calloc(18, sizeof(char)); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,26,40, fidonet.comment); + show_str( 8,26,12, fidonet.domain); + show_bool(9,26, fidonet.available); + show_bool(10,26, fidonet.deleted); + show_str(11,26,8, fidonet.nodelist); + for (i = 0; i < 6; i++) { + if ((fidonet.seclist[i].zone) || strlen(fidonet.seclist[i].nodelist)) { + show_str(i + 12,26,8, fidonet.seclist[i].nodelist); + sprintf(temp, "%d:%d/%d", fidonet.seclist[i].zone, fidonet.seclist[i].net, fidonet.seclist[i].node); + show_str(i + 12, 36,17, temp); + } else + show_str(i + 12,26,27, (char *)" "); + show_int(i + 12,74, fidonet.zone[i]); + } + + j = select_menu(17); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&fidonet, crc1, sizeof(fidonet)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + free(temp); + return -1; + } + fseek(fil, offset, 0); + fwrite(&fidonet, sizeof(fidonet), 1, fil); + fclose(fil); + FidoUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + free(temp); + return 0; + case 1: + E_STR(7,26,40, fidonet.comment, "The ^Comment^ for this network name") + + case 2: + E_STR(8, 26,12, fidonet.domain, "The ^Name^ of the network without dots") + + case 3: + E_BOOL(9,26, fidonet.available, "Is this network ^Available^ for use") + + case 4: + E_BOOL(10,26, fidonet.deleted, "Is this netword ^Deleted^") + + case 5: + E_STR(11,26,8, fidonet.nodelist, "The name of the ^Primary Nodelist^ for this network") + + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + strcpy(fidonet.seclist[j-6].nodelist, edit_str(j+6,26,8, fidonet.seclist[j-6].nodelist, (char *)"The secondary ^nodelist^ or ^pointlist^ name for this domain")); + if (strlen(fidonet.seclist[j-6].nodelist)) { + do { + sprintf(temp, "%d:%d/%d", fidonet.seclist[j-6].zone, fidonet.seclist[j-6].net, fidonet.seclist[j-6].node); + strcpy(temp, edit_str(j+6,36,17, temp, (char *)"The top ^fidonet aka^ for this nodelist (zone:net/node)")); + if ((strstr(temp, ":") == NULL) || (strstr(temp, "/") == NULL)) { + working(2, 0, 0); + working(0, 0, 0); + } + } while ((strstr(temp, ":") == NULL) || (strstr(temp, "/") == NULL)); + fidonet.seclist[j-6].zone = atoi(strtok(temp, ":")); + fidonet.seclist[j-6].net = atoi(strtok(NULL, "/")); + fidonet.seclist[j-6].node = atoi(strtok(NULL, "")); + } else { + fidonet.seclist[j-6].zone = 0; + fidonet.seclist[j-6].net = 0; + fidonet.seclist[j-6].node = 0; + } + break; + + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + E_INT(j,74, fidonet.zone[j-12], "A ^Zone number^ which belongs to this domain (1..4095)") + } + } + + return 0; +} + + + +void EditFidonet(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountFidonet(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenFidonet() == -1) { + working(2, 0, 0); + return; + } + IsDoing("Browsing Menu"); + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "2. FIDONET SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(fidonethdr) + ((i - 1) * fidonethdr.recsize); + fseek(fil, offset, 0); + fread(&fidonet, fidonethdr.recsize, 1, fil); + if (fidonet.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + if (i == 11) { + x = 42; + y = 7; + } + sprintf(temp, "%3d. z%d: %-32s", i, fidonet.zone[0], fidonet.comment); + temp[38] = 0; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseFidonet(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendFidonet() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditFidoRec(atoi(pick)); + } +} + + + +void gold_akamatch(FILE *fp) +{ + char temp[81]; + FILE *fido; + faddr *want; + int i; + + sprintf(temp, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fido = fopen(temp, "r")) == NULL) + return; + + fprintf(fp, "; AKA Matching\n;\n"); + want = (faddr *)malloc(sizeof(faddr)); + + fread(&fidonethdr, sizeof(fidonethdr), 1, fido); + while ((fread(&fidonet, fidonethdr.recsize, 1, fido)) == 1) { + + for (i = 0; i < 6; i++) + if (fidonet.zone[i]) { + want->zone = fidonet.zone[0]; + want->net = 0; + want->node = 0; + want->point = 0; + want->name = NULL; + want->domain = NULL; + fprintf(fp, "AKAMATCH %d:* %s\n", fidonet.zone[i], ascfnode(bestaka_s(want), 0xf)); + } + } + + free(want); + fprintf(fp, ";\n"); + fprintf(fp, "AKAMATCHNET YES\n"); + fprintf(fp, "AKAMATCHECHO YES\n"); /* On request, should work better */ + fprintf(fp, "AKAMATCHLOCAL NO\n\n"); + + fprintf(fp, "; NODELISTS\n;\n"); + fprintf(fp, "NODEPATH %s/\n", CFG.nodelists); + fseek(fido, fidonethdr.hdrsize, SEEK_SET); + while ((fread(&fidonet, fidonethdr.recsize, 1, fido)) == 1) { + fprintf(fp, "NODELIST %s.*\n", fidonet.nodelist); + for (i = 0; i < 6; i++) + if (strlen(fidonet.seclist[i].nodelist) || fidonet.seclist[i].zone) + fprintf(fp, "NODELIST %s.*\n", fidonet.seclist[i].nodelist); + } +// fprintf(fp, "USERLIST golded.lst\n"); + fprintf(fp, "LOOKUPNET YES\n"); + fprintf(fp, "LOOKUPECHO NO\n"); + fprintf(fp, "LOOKUPLOCAL NO\n\n"); + fclose(fido); +} + + + +int fido_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *fido; + int i, j; + + sprintf(temp, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fido = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 2, 0, page, (char *)"Fidonet networks"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&fidonethdr, sizeof(fidonethdr), 1, fido); + while ((fread(&fidonet, fidonethdr.recsize, 1, fido)) == 1) { + + if (j == 6) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Comment %s\n", fidonet.comment); + fprintf(fp, " Domain %s\n", fidonet.domain); + fprintf(fp, " Available %s\n", getboolean(fidonet.available)); + fprintf(fp, " Nodelist %s\n", fidonet.nodelist); + for (i = 0; i < 6; i++) + if (strlen(fidonet.seclist[i].nodelist) || fidonet.seclist[i].zone) { + fprintf(fp, " Merge list %d %-8s %d:%d/%d\n", i+1, + fidonet.seclist[i].nodelist, fidonet.seclist[i].zone, + fidonet.seclist[i].net, fidonet.seclist[i].node); + } + fprintf(fp, " Zone(s) "); + for (i = 0; i < 6; i++) + if (fidonet.zone[i]) + fprintf(fp, "%d ", fidonet.zone[i]); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(fido); + return page; +} + + + diff --git a/mbsetup/m_fido.h b/mbsetup/m_fido.h new file mode 100644 index 00000000..06f4119e --- /dev/null +++ b/mbsetup/m_fido.h @@ -0,0 +1,11 @@ +#ifndef _FIDO_H +#define _FIDO_H + + +int CountFidonet(void); +void EditFidonet(void); +void gold_akamatch(FILE *); +int fido_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_global.c b/mbsetup/m_global.c new file mode 100644 index 00000000..90323f4a --- /dev/null +++ b/mbsetup/m_global.c @@ -0,0 +1,1995 @@ +/**************************************************************************** + * + * File ..................: m_global.c + * Purpose ...............: Global Setup Program + * Last modification date : 05-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_node.h" +#include "m_marea.h" +#include "m_ticarea.h" +#include "m_global.h" + + +char *some_fn; +int some_fd; + +#define WRLONG cnt = write(some_fd, &longvar, sizeof(longvar)); + + + +void config_check(char *path) +{ + static char buf[PATH_MAX]; + + sprintf(buf, "%s/etc/config.data", path); + some_fn = buf; + + /* + * Check if the configuration file exists. If not, exit. + */ + some_fd = open(some_fn, O_RDONLY); + if (some_fd == -1) { + perror(""); + fprintf(stderr, "Fatal, %s/etc/config.data not found, is mbtask running?\n", path); + exit(1); + } + close(some_fd); +} + + + +int config_read(void) +{ + some_fd = open(some_fn, O_RDONLY); + if (some_fd == -1) + return -1; + + memset(&CFG, 0, sizeof(CFG)); + read(some_fd, &CFG, sizeof(CFG)); + close(some_fd); + return 0; +} + + + +int config_write(void) +{ + some_fd = open(some_fn, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (some_fd == -1) + return -1; + + write(some_fd, &CFG, sizeof(CFG)); + close(some_fd); + return 0; +} + + + +int cf_open(void) +{ + clr_index(); + working(1, 0, 0); + IsDoing("Edit Global"); + working(1, 0, 0); + if (0 == config_read()) { + working(0, 0, 0); + return 0; + } + + working(2, 0, 0); + return -1; +} + + + +void cf_close(void) +{ + working(1, 0, 0); + if (config_write() != 0) + working(2, 0, 0); + working(0, 0, 0); +} + + + +void e_reginfo(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.1 EDIT REGISTRATION INFO"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. System name"); + mvprintw( 8, 6, "2. Domain name"); + mvprintw( 9, 6, "3. Sysop uid"); + mvprintw(10, 6, "4. Sysop Fido"); + mvprintw(11, 6, "5. Location"); + mvprintw(12, 6, "6. QWK/Bluewave"); + mvprintw(13, 6, "7. Omen id"); + mvprintw(14, 6, "8. Comment"); + mvprintw(15, 6, "9. Origin line"); + mvprintw(16, 6, "10. Startup uid"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,25,35, CFG.bbs_name); + show_str( 8,25,35, CFG.sysdomain); + show_str( 9,25, 8, CFG.sysop); + show_str(10,25,35, CFG.sysop_name); + show_str(11,25,35, CFG.location); + show_str(12,25, 8, CFG.bbsid); + show_str(13,25, 2, CFG.bbsid2); + show_str(14,25,55, CFG.comment); + show_str(15,25,50, CFG.origin); + show_str(16,25, 8, CFG.startname); + + switch(select_menu(10)) { + case 0: return; + case 1: E_STR( 7,25,35, CFG.bbs_name, "Name of this ^BBS^ system") + case 2: E_STR( 8,25,35, CFG.sysdomain, "Full internet ^domain^ name of this system") + case 3: E_STR( 9,25, 8, CFG.sysop, "^Unix name^ of the sysop") + case 4: E_STR(10,25,35, CFG.sysop_name, "^Fidonet name^ of the sysop") + case 5: E_STR(11,25,35, CFG.location, "^Location^ (city) of this system") + case 6: E_UPS(12,25, 8, CFG.bbsid, "^QWK/Bluewave^ packets name") + case 7: E_UPS(13,25, 2, CFG.bbsid2, "^Omen offline^ reader ID characters") + case 8: E_STR(14,25,55, CFG.comment, "Some ^comment^ you may like to give") + case 9: E_STR(15,25,50, CFG.origin, "Default ^origin^ line under echomail messages") + case 10:E_STR(16,25, 8, CFG.startname, "The ^Unix username^ that is used to start the bbs") + } + }; +} + + + + +void e_filenames(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.2 EDIT GLOBAL FILENAMES"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. System logfile"); + mvprintw( 8, 6, "2. Error logfile"); + mvprintw( 9, 6, "3. Default Menu"); + mvprintw(10, 6, "4. Default Language"); + mvprintw(11, 6, "5. Chat Logfile"); + mvprintw(12, 6, "6. Welcome Logo"); + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,28,14, CFG.logfile); + show_str( 8,28,14, CFG.error_log); + show_str( 9,28,14, CFG.default_menu); + show_str(10,28,14, CFG.current_language); + show_str(11,28,14, CFG.chat_log); + show_str(12,28,14, CFG.welcome_logo); + + switch(select_menu(6)) { + case 0: return; + case 1: E_STR( 7,28,14, CFG.logfile, "The name of the ^system^ logfile.") + case 2: E_STR( 8,28,14, CFG.error_log, "The name of the ^errors^ logfile.") + case 3: E_STR( 9,28,14, CFG.default_menu, "The name of the ^default^ (top) ^menu^.") + case 4: E_STR(10,28,14, CFG.current_language, "The name of the ^default language^.") + case 5: E_STR(11,28,14, CFG.chat_log, "The name of the ^chat^ logfile.") + case 6: E_STR(12,28,14, CFG.welcome_logo, "The name of the ^BBS logo^ file.") + } + }; +} + + + +void e_global(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 6, "1.3 EDIT GLOBAL PATHS"); + set_color(CYAN, BLACK); + mvprintw( 6, 2, "1. BBS menus"); + mvprintw( 7, 2, "2. Txtfiles"); + mvprintw( 8, 2, "3. Home dirs"); + mvprintw( 9, 2, "4. Nodelists"); + mvprintw(10, 2, "5. Inbound"); + mvprintw(11, 2, "6. Prot inb."); + mvprintw(12, 2, "7. Outbound"); + mvprintw(13, 2, "8. Bad TIC's"); + mvprintw(14, 2, "9. TIC queue"); + mvprintw(15, 2, "10. Magic's"); + mvprintw(16, 2, "11. DOS path"); + mvprintw(17, 2, "12. Unix path"); + mvprintw(18, 2, "13. LeaveCase"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6,16,64, CFG.bbs_menus); + show_str( 7,16,64, CFG.bbs_txtfiles); + show_str( 8,16,64, CFG.bbs_usersdir); + show_str( 9,16,64, CFG.nodelists); + show_str(10,16,64, CFG.inbound); + show_str(11,16,64, CFG.pinbound); + show_str(12,16,64, CFG.outbound); + show_str(13,16,64, CFG.badtic); + show_str(14,16,64, CFG.ticout); + show_str(15,16,64, CFG.req_magic); + show_str(16,16,64, CFG.dospath); + show_str(17,16,64, CFG.uxpath); + show_bool(18,16, CFG.leavecase); + + switch(select_menu(13)) { + case 0: return; + case 1: E_PTH( 6,16,64, CFG.bbs_menus, "The path to the ^default menus^.") + case 2: E_PTH( 7,16,64, CFG.bbs_txtfiles, "The path to the ^default textfiles^.") + case 3: E_PTH( 8,16,64, CFG.bbs_usersdir, "The path to the ^users home^ directories.") + case 4: E_PTH( 9,16,64, CFG.nodelists, "The path to the ^nodelists^.") + case 5: E_PTH(10,16,64, CFG.inbound, "The path to the ^inbound^ for unknown systems.") + case 6: E_PTH(11,16,64, CFG.pinbound, "The path to the ^nodelists^ for protected systems.") + case 7: E_PTH(12,16,64, CFG.outbound, "The path to the base ^outbound^ directory.") + case 8: E_PTH(13,16,64, CFG.badtic, "The path to the ^bad tic files^.") + case 9: E_PTH(14,16,64, CFG.ticout, "The path to the ^outgoing TIC^ files.") + case 10:E_PTH(15,16,64, CFG.req_magic, "The path to the ^magic filerequest^ files.") + case 11:E_STR(16,16,64, CFG.dospath, "The translated ^DOS^ drive and path.") + case 12:E_PTH(17,16,64, CFG.uxpath, "The translated ^Unix^ path.") + case 13:E_BOOL(18,16, CFG.leavecase, "^Leave^ outbound flo filenames as is, ^No^ forces uppercase.") + } + }; +} + + + +void b_screen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.4 EDIT GLOBAL SETTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Private system"); + mvprintw( 8, 2, "2. Exclude Sysop"); + mvprintw( 9, 2, "3. Show Connect"); + mvprintw(10, 2, "4. Ask Protocols"); + mvprintw(11, 2, "5. Sysop Level"); + mvprintw(12, 2, "6. Password Length"); + mvprintw(13, 2, "7. Passwd Character"); + mvprintw(14, 2, "8. Idle timeout"); + mvprintw(15, 2, "9. Login Enters"); + mvprintw(16, 2, "10. Login Attempts"); + mvprintw(17, 2, "11. Homedir Quota"); + + mvprintw( 7,37, "12. Location length"); + mvprintw( 8,37, "13. Show new msgarea"); + mvprintw( 9,37, "14. OLR Max. msgs."); + mvprintw(10,37, "15. OLR Newfile days"); + mvprintw(11,37, "16. OLR Max Filereq"); + mvprintw(12,37, "17. BBS Log Level"); + mvprintw(13,37, "18. Utils loglevel"); + mvprintw(14,37, "19. Utils slowly"); + mvprintw(15,37, "20. CrashMail level"); + mvprintw(16,37, "21. FileAttach level"); + mvprintw(17,37, "22. Min diskspace MB"); + + set_color(WHITE, BLACK); + show_bool( 7,24, CFG.elite_mode); + show_bool( 8,24, CFG.exclude_sysop); + show_bool( 9,24, CFG.iConnectString); + show_bool(10,24, CFG.iAskFileProtocols); + show_int( 11,24, CFG.sysop_access); + show_int( 12,24, CFG.password_length); + show_int( 13,24, CFG.iPasswd_Char); + show_int( 14,24, CFG.idleout); + show_int( 15,24, CFG.iCRLoginCount); + show_int( 16,24, CFG.max_login); + show_int( 17,24, CFG.iQuota); + + show_int( 7,59, CFG.CityLen); + show_bool( 8,59, CFG.NewAreas); + show_int( 9,59, CFG.OLR_MaxMsgs); + show_int( 10,59, CFG.OLR_NewFileLimit); + show_int( 11,59, CFG.OLR_MaxReq); + show_logl(12,59, CFG.bbs_loglevel); + show_logl(13,59, CFG.util_loglevel); + show_bool(14,59, CFG.slow_util); + show_int( 15,59, CFG.iCrashLevel); + show_int( 16,59, CFG.iAttachLevel); + show_int( 17,59, CFG.freespace); +} + + + +void e_bbsglob(void) +{ + b_screen(); + + for (;;) { + switch(select_menu(22)) { + case 0: return; + case 1: E_BOOL( 7,24, CFG.elite_mode, "^Private^ system.") + case 2: E_BOOL( 8,24, CFG.exclude_sysop, "^Exclude^ sysop from lists.") + case 3: E_BOOL( 9,24, CFG.iConnectString, "Show ^connect string^ at logon") + case 4: E_BOOL(10,24, CFG.iAskFileProtocols, "Ask ^file protocol^ before every up- download") + case 5: E_INT( 11,24, CFG.sysop_access, "Sysop ^access level^") + case 6: E_INT( 12,24, CFG.password_length, "Mimimum ^password^ length.") + case 7: E_INT( 13,24, CFG.iPasswd_Char, "Ascii number of ^password^ character") + case 8: E_INT( 14,24, CFG.idleout, "^Idle timeout^ in minutes") + case 9: E_INT( 15,24, CFG.iCRLoginCount, "Maximum ^Login Return^ count") + case 10:E_INT( 16,24, CFG.max_login, "Maximum ^Login^ attempts") + case 11:E_INT( 17,24, CFG.iQuota, "Maximum ^Quota^ in MBytes in users homedirectory"); + + case 12:E_INT( 7,59, CFG.CityLen, "Minimum ^Location name^ length (3..6)") + case 13:E_BOOL( 8,59, CFG.NewAreas, "Show ^new^ or ^deleted^ message areas to the user at login.") + case 14:E_INT( 9,59, CFG.OLR_MaxMsgs, "^Maximum messages^ to pack for download (0=unlimited)") + case 15:E_INT( 10,59, CFG.OLR_NewFileLimit, "^Limit Newfiles^ listing for maximum days") + case 16:E_INT( 11,59, CFG.OLR_MaxReq, "Maximum ^Filerequests^ to honor") + case 17:E_LOGL(CFG.bbs_loglevel, "1.4.17", b_screen) + case 18:E_LOGL(CFG.util_loglevel, "1.4.18", b_screen) + case 19:E_BOOL(14,59, CFG.slow_util, "Let background utilities run ^slowly^") + case 20:E_INT( 15,59, CFG.iCrashLevel, "The user level to allow sending ^CrashMail^") + case 21:E_INT( 16,59, CFG.iAttachLevel, "The user level to allow sending ^File Attaches^") + case 22:E_INT( 17,59, CFG.freespace, "Minimum ^free diskspace^ in MBytes on filesystems") + } + }; +} + + + +void s_newuser(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.5 EDIT NEW USERS DEFAULTS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Access level"); + mvprintw( 8, 6, "2. Cap. Username"); + mvprintw( 9, 6, "3. Ask ANSI"); + mvprintw(10, 6, "4. Ask Sex"); + mvprintw(11, 6, "5. Ask Voicephone"); + mvprintw(12, 6, "6. Ask Dataphone"); + mvprintw(13, 6, "7. Telephone scan"); + mvprintw(14, 6, "8. Ask Handle"); + + mvprintw( 8,46, "9. Ask Birth date"); + mvprintw( 9,46, "10. Ask Location"); + mvprintw(10,46, "11. Ask Hot-Keys"); + mvprintw(11,46, "12. One word names"); + mvprintw(12,46, "13. Ask Address"); + mvprintw(13,46, "14. Give email"); +} + + + +void e_newuser(void) +{ + s_newuser(); + for (;;) { + set_color(WHITE, BLACK); + show_sec( 7,28, CFG.newuser_access); + show_bool( 8,28, CFG.iCapUserName); + show_bool( 9,28, CFG.iAnsi); + show_bool(10,28, CFG.iSex); + show_bool(11,28, CFG.iVoicePhone); + show_bool(12,28, CFG.iDataPhone); + show_bool(13,28, CFG.iTelephoneScan); + show_bool(14,28, CFG.iHandle); + + show_bool( 8,68, CFG.iDOB); + show_bool( 9,68, CFG.iLocation); + show_bool(10,68, CFG.iHotkeys); + show_bool(11,68, CFG.iOneName); + show_bool(12,68, CFG.AskAddress); + show_bool(13,68, CFG.GiveEmail); + + switch(select_menu(14)) { + case 0: return; + case 1: E_SEC( 7,28, CFG.newuser_access, "1.6.1 NEWUSER SECURITY", s_newuser) + case 2: E_BOOL( 8,28, CFG.iCapUserName, "^Capitalize^ username") + case 3: E_BOOL( 9,28, CFG.iAnsi, "Ask user if he wants ^ANSI^ colors") + case 4: E_BOOL(10,28, CFG.iSex, "Ask users ^sex^") + case 5: E_BOOL(11,28, CFG.iVoicePhone, "Ask users ^Voice^ phone number") + case 6: E_BOOL(12,28, CFG.iDataPhone, "Ask users ^Data^ phone number") + case 7: E_BOOL(13,28, CFG.iTelephoneScan, "Perform ^Telephone^ number scan") + case 8: E_BOOL(14,28, CFG.iHandle, "Ask users ^handle^") + + case 9: E_BOOL( 8,68, CFG.iDOB, "Ask users ^Date of Birth^") + case 10:E_BOOL( 9,68, CFG.iLocation, "Ask users ^Location^") + case 11:E_BOOL(10,68, CFG.iHotkeys, "Ask user if he wants ^Hot-Keys^") + case 12:E_BOOL(11,68, CFG.iOneName, "Allow ^one word^ (not in Unixmode) usernames") + case 13:E_BOOL(12,68, CFG.AskAddress, "Aks users ^home address^ in 3 lines") + case 14:E_BOOL(13,68, CFG.GiveEmail, "Give new users an ^private email^ box") + } + }; +} + + + +void e_colors(void) +{ + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.6 EDIT TEXT COLOURS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Normal text"); + mvprintw( 8, 6, "2. Underline"); + mvprintw( 9, 6, "3. Input lines"); + mvprintw(10, 6, "4. CR text"); + mvprintw(11, 6, "5. More prompt"); + mvprintw(12, 6, "6. Hilite text"); + mvprintw(13, 6, "7. File name"); + mvprintw(14, 6, "8. File size"); + mvprintw(15, 6, "9. File date"); + mvprintw(16, 6, "10. File descr."); + mvprintw(17, 6, "11. Msg. input"); + S_COL( 7,24, "Normal Text ", CFG.TextColourF, CFG.TextColourB) + S_COL( 8,24, "Underline Text ", CFG.UnderlineColourF, CFG.UnderlineColourB) + S_COL( 9,24, "Input Text ", CFG.InputColourF, CFG.InputColourB) + S_COL(10,24, "CR Text ", CFG.CRColourF, CFG.CRColourB) + S_COL(11,24, "More Prompt ", CFG.MoreF, CFG.MoreB) + S_COL(12,24, "Hilite Text ", CFG.HiliteF, CFG.HiliteB) + S_COL(13,24, "File Name ", CFG.FilenameF, CFG.FilenameB) + S_COL(14,24, "File Size ", CFG.FilesizeF, CFG.FilesizeB) + S_COL(15,24, "File Date ", CFG.FiledateF, CFG.FiledateB) + S_COL(16,24, "File Description", CFG.FiledescF, CFG.FiledescB) + S_COL(17,24, "Message Input ", CFG.MsgInputColourF, CFG.MsgInputColourB) + + switch(select_menu(11)) { + case 0: return; + case 1: edit_color(&CFG.TextColourF, &CFG.TextColourB, (char *)"normal text"); break; + case 2: edit_color(&CFG.UnderlineColourF, &CFG.UnderlineColourB, (char *)"underline"); break; + case 3: edit_color(&CFG.InputColourF, &CFG.InputColourB, (char *)"input"); break; + case 4: edit_color(&CFG.CRColourF, &CFG.CRColourB, (char *)""); break; + case 5: edit_color(&CFG.MoreF, &CFG.MoreB, (char *)"more prompt"); break; + case 6: edit_color(&CFG.HiliteF, &CFG.HiliteB, (char *)"hilite text"); break; + case 7: edit_color(&CFG.FilenameF, &CFG.FilenameB, (char *)"file name"); break; + case 8: edit_color(&CFG.FilesizeF, &CFG.FilesizeB, (char *)"file size"); break; + case 9: edit_color(&CFG.FiledateF, &CFG.FiledateB, (char *)"file date"); break; + case 10:edit_color(&CFG.FiledescF, &CFG.FiledescB, (char *)"file description"); break; + case 11:edit_color(&CFG.MsgInputColourF, &CFG.MsgInputColourB, (char *)"message input"); break; + } + }; +} + + + +void e_nu_door(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.7 EDIT NEXT USER DOOR"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Text file"); + mvprintw( 8, 2, "2. Quote"); + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,17,49, CFG.sNuScreen); + show_str( 8,17,64, CFG.sNuQuote); + + switch(select_menu(2)) { + case 0: return; + case 1: E_STR(7,17,49, CFG.sNuScreen, "The ^text file^ to display to the next user.") + case 2: E_STR(8,17,64, CFG.sNuQuote, "The ^quote^ to insert in the next user text.") + } + }; +} + + + +void e_safe_door(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.8 EDIT SAFE DOOR"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Digit 1"); + mvprintw( 8, 2, "2. Digit 2"); + mvprintw( 9, 2, "3. Digit 3"); + mvprintw(10, 2, "4. Max trys"); + mvprintw(11, 2, "5. Max numb"); + mvprintw(12, 2, "6. Num gen"); + mvprintw(13, 2, "7. Prize"); + mvprintw(14, 2, "8. Welcome"); + mvprintw(15, 2, "9. Opened"); + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,15, CFG.iSafeFirstDigit); + show_int( 8,15, CFG.iSafeSecondDigit); + show_int( 9,15, CFG.iSafeThirdDigit); + show_int(10,15, CFG.iSafeMaxTrys); + show_int(11,15, CFG.iSafeMaxNumber); + show_bool(12,15, CFG.iSafeNumGen); + show_str(13,15,64, CFG.sSafePrize); + show_str(14,15,64, CFG.sSafeWelcome); + show_str(15,15,64, CFG.sSafeOpened); + + switch(select_menu(9)) { + case 0: return; + case 1: E_INT( 7,15, CFG.iSafeFirstDigit, "Enter ^first^ digit of the safe") + case 2: E_INT( 8,15, CFG.iSafeSecondDigit, "Enter ^second^ digit of the safe") + case 3: E_INT( 9,15, CFG.iSafeThirdDigit, "Enter ^third^ digit of the safe") + case 4: E_INT( 10,15, CFG.iSafeMaxTrys, "Maximum ^trys^ per day") + case 5: E_INT( 11,15, CFG.iSafeMaxNumber, "^Maximum number^ of each digit") + case 6: E_BOOL(12,15, CFG.iSafeNumGen, "^Automatic^ number generation") + case 7: E_STR( 13,15,64, CFG.sSafePrize, "The ^prize^ the user wins when he opens the safe") + case 8: E_STR( 14,15,64, CFG.sSafeWelcome, "The ^welcome^ screen for the safe door") + case 9: E_STR( 15,15,64, CFG.sSafeOpened, "The file to display when the safe is ^opened^") + } + }; +} + + + +void e_timebank(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.9 EDIT TIME BANK"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Users time balance"); + mvprintw( 8, 6, "2. Max time withdraw"); + mvprintw( 9, 6, "3. Max time deposit"); + mvprintw(10, 6, "4. Users Kb. balance"); + mvprintw(11, 6, "5. Max Kb. withdraw"); + mvprintw(12, 6, "6. Max Kb. deposit"); + mvprintw(13, 6, "7. Users time ratio"); + mvprintw(14, 6, "8. Users Kb. ratio"); + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,31, CFG.iMaxTimeBalance); + show_int( 8,31, CFG.iMaxTimeWithdraw); + show_int( 9,31, CFG.iMaxTimeDeposit); + show_int(10,31, CFG.iMaxByteBalance); + show_int(11,31, CFG.iMaxByteWithdraw); + show_int(12,31, CFG.iMaxByteDeposit); + show_str(13,31,6, CFG.sTimeRatio); + show_str(14,31,6, CFG.sByteRatio); + + switch(select_menu(8)) { + case 0: return; + case 1: E_INT( 7,31, CFG.iMaxTimeBalance, "Maximum ^time balance^") + case 2: E_INT( 8,31, CFG.iMaxTimeWithdraw, "Maximum ^time withdraw^") + case 3: E_INT( 9,31, CFG.iMaxTimeDeposit, "Maximum ^time deposit^") + case 4: E_INT(10,31, CFG.iMaxByteBalance, "Maximum ^bytes balance^") + case 5: E_INT(11,31, CFG.iMaxByteWithdraw, "Maximum ^bytes withdraw^") + case 6: E_INT(12,31, CFG.iMaxByteDeposit, "Maximum ^bytes deposit^") + case 7: E_STR(13,31,6, CFG.sTimeRatio, "^Time ratio^") + case 8: E_STR(14,31,6, CFG.sByteRatio, "^Bytes ratio^") + } + }; +} + + + +void e_paging(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.10 EDIT SYSOP PAGING"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Ext. Chat"); + mvprintw( 8, 2, "2. Chat Device"); + mvprintw( 9, 2, "3. Call Script"); + mvprintw(10, 2, "4. Page Length"); + mvprintw(11, 2, "5. Page Times"); + mvprintw(12, 2, "6. Sysop Area"); + mvprintw(13, 2, "7. Ask Reason"); + mvprintw(14, 2, "8. Use Extern"); + mvprintw(15, 2, "9. Log Chat"); + mvprintw(16, 2, "10. Prompt Chk."); + mvprintw(17, 2, "11. Freeze Time"); + + mvprintw(11,42, "12. Sunday"); + mvprintw(12,42, "13. Monday"); + mvprintw(13,42, "14. Tuesday"); + mvprintw(14,42, "15. Wednesday"); + mvprintw(15,42, "16. Thursday"); + mvprintw(16,42, "17. Friday"); + mvprintw(17,42, "18. Saterday"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,20,49, CFG.sExternalChat); + show_str( 8,20,19, CFG.sChatDevice); + show_str( 9,20,50, CFG.sCallScript); + show_int(10,20, CFG.iPageLength); + show_int(11,20, CFG.iMaxPageTimes); + show_int(12,20, CFG.iSysopArea); + show_bool(13,20, CFG.iAskReason); + show_bool(14,20, CFG.iExternalChat); + show_bool(15,20, CFG.iAutoLog); + show_bool(16,20, CFG.iChatPromptChk); + show_bool(17,20, CFG.iStopChatTime); + + show_str(11,58,5, CFG.cStartTime[0]); + show_str(12,58,5, CFG.cStartTime[1]); + show_str(13,58,5, CFG.cStartTime[2]); + show_str(14,58,5, CFG.cStartTime[3]); + show_str(15,58,5, CFG.cStartTime[4]); + show_str(16,58,5, CFG.cStartTime[5]); + show_str(17,58,5, CFG.cStartTime[6]); + + show_str(11,65,5, CFG.cStopTime[0]); + show_str(12,65,5, CFG.cStopTime[1]); + show_str(13,65,5, CFG.cStopTime[2]); + show_str(14,65,5, CFG.cStopTime[3]); + show_str(15,65,5, CFG.cStopTime[4]); + show_str(16,65,5, CFG.cStopTime[5]); + show_str(17,65,5, CFG.cStopTime[6]); + + switch(select_menu(18)) { + case 0: return; + + case 1: E_STR( 7,20,49, CFG.sExternalChat, "The name of the ^External Chat^ program.") + case 2: E_STR( 8,20,19, CFG.sChatDevice, "The ^device^ to use for chat") + case 3: E_STR( 9,20,50, CFG.sCallScript, "The ^Call Script^ to connect to remote sysop") + case 4: E_INT( 10,20, CFG.iPageLength, "The ^Length^ of paging in seconds") + case 5: E_INT( 11,20, CFG.iMaxPageTimes, "The ^Maximum times^ a user may page in a session") + case 6: E_INT( 12,20, CFG.iSysopArea, "The ^Message Area^ for ^Message to sysop^ when page fails") + case 7: E_BOOL(13,20, CFG.iAskReason, "Ask the user the ^reason for chat^") + case 8: E_BOOL(14,20, CFG.iExternalChat, "Use ^External Chat^ program") + case 9: E_BOOL(15,20, CFG.iAutoLog, "^Automatic log^ chat sessions") + case 10:E_BOOL(16,20, CFG.iChatPromptChk, "Check for chat at the ^prompt^") + case 11:E_BOOL(17,20, CFG.iStopChatTime, "^Stop^ users time during chat") + case 12:strcpy(CFG.cStartTime[0], edit_str(11,58,5, CFG.cStartTime[0], (char *)"Start Time paging on ^Sunday^")); + strcpy(CFG.cStopTime[0], edit_str(11,65,5, CFG.cStopTime[0], (char *)"Stop Time paging on ^Sunday^")); + break; + case 13:strcpy(CFG.cStartTime[1], edit_str(12,58,5, CFG.cStartTime[1], (char *)"Start Time paging on ^Monday^")); + strcpy(CFG.cStopTime[1], edit_str(12,65,5, CFG.cStopTime[1], (char *)"Stop Time paging on ^Monday^")); + break; + case 14:strcpy(CFG.cStartTime[2], edit_str(13,58,5, CFG.cStartTime[2], (char *)"Start Time paging on ^Tuesday^")); + strcpy(CFG.cStopTime[2], edit_str(13,65,5, CFG.cStopTime[2], (char *)"Stop Time paging on ^Tuesday^")); + break; + case 15:strcpy(CFG.cStartTime[3], edit_str(14,58,5, CFG.cStartTime[3], (char *)"Start Time paging on ^Wednesday^")); + strcpy(CFG.cStopTime[3], edit_str(14,65,5, CFG.cStopTime[3], (char *)"Stop Time paging on ^Wednesday^")); + break; + case 16:strcpy(CFG.cStartTime[4], edit_str(15,58,5, CFG.cStartTime[4], (char *)"Start Time paging on ^Thursday^")); + strcpy(CFG.cStopTime[4], edit_str(15,65,5, CFG.cStopTime[4], (char *)"Stop Time paging on ^Thursday^")); + break; + case 17: + strcpy(CFG.cStartTime[5], edit_str(16,58,5, CFG.cStartTime[5], (char *)"Start Time paging on ^Friday^")); + strcpy(CFG.cStopTime[5], edit_str(16,65,5, CFG.cStopTime[5], (char *)"Stop Time paging on ^Friday^")); + break; + case 18:strcpy(CFG.cStartTime[6], edit_str(17,58,5, CFG.cStartTime[6], (char *)"Start Time paging on ^Saterday^")); + strcpy(CFG.cStopTime[6], edit_str(17,65,5, CFG.cStopTime[6], (char *)"Stop Time paging on ^Saterday^")); + break; + } + }; +} + + + +void e_flags(void) +{ + int i, x, y, z; + char temp[80]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.11 EDIT FLAG DESCRIPTIONS"); + set_color(CYAN, BLACK); + for (i = 0; i < 32; i++) { + if (i < 11) + mvprintw(i + 7, 2, (char *)"%d.", i+1); + else + if (i < 22) + mvprintw(i - 4, 28, (char *)"%d.", i+1); + else + mvprintw(i - 15, 54, (char *)"%d.", i+1); + } + for (;;) { + set_color(WHITE, BLACK); + for (i = 0; i < 32; i++) { + if (i < 11) + show_str(i + 7, 6, 16, CFG.fname[i]); + else + if (i < 22) + show_str(i - 4, 32, 16, CFG.fname[i]); + else + show_str(i -15, 58, 16, CFG.fname[i]); + } + + z = select_menu(32); + if (z == 0) + return; + + if (z < 12) { + x = 6; + y = z + 6; + } else + if (z < 23) { + x = 32; + y = z - 5; + } else { + x = 58; + y = z - 16; + } + sprintf(temp, "Enter a short ^description^ of flag bit %d", z); + strcpy(CFG.fname[z-1], edit_str(y, x, 16, CFG.fname[z-1], temp)); + }; +} + + + +void e_ticconf(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.12 EDIT FILEECHO PROCESSING"); + set_color(CYAN, BLACK); + + mvprintw( 7, 2, "1. Keep days"); + mvprintw( 8, 2, "2. Hatch pwd"); + mvprintw( 9, 2, "3. Drv space"); + mvprintw(10, 2, "4. Systems"); + mvprintw(11, 2, "5. Groups"); + mvprintw(12, 2, "6. Max. dupes"); + mvprintw(13, 2, "7. Keep date"); + mvprintw(14, 2, "8. Keep netm"); + mvprintw(15, 2, "9. Res future"); + mvprintw(16, 2, "10. Loc resp"); + + mvprintw( 7,42, "11. Repl ext"); + mvprintw( 8,42, "12. Plus all"); + mvprintw( 9,42, "13. Notify"); + mvprintw(10,42, "14. Passwd"); + mvprintw(11,42, "15. Message"); + mvprintw(12,42, "16. Tic on/off"); + mvprintw(13,42, "17. Pause"); + + for (;;) { + set_color(WHITE, BLACK); + + show_int( 7,18, CFG.tic_days); + show_str( 8,18,20, (char *)"********************"); + show_int( 9,18, CFG.drspace); + show_int(10,18, CFG.tic_systems); + show_int(11,18, CFG.tic_groups); + show_int(12,18, CFG.tic_dupes); + show_bool(13,18, CFG.ct_KeepDate); + show_bool(14,18, CFG.ct_KeepMgr); + show_bool(15,18, CFG.ct_ResFuture); + show_bool(16,18, CFG.ct_LocalRep); + show_bool( 7,58, CFG.ct_ReplExt); + show_bool( 8,58, CFG.ct_PlusAll); + show_bool( 9,58, CFG.ct_Notify); + show_bool(10,58, CFG.ct_Passwd); + show_bool(11,58, CFG.ct_Message); + show_bool(12,58, CFG.ct_TIC); + show_bool(13,58, CFG.ct_Pause); + + switch(select_menu(17)) { + case 0: return; + + case 1: E_INT( 7,18, CFG.tic_days, "Number of days to ^keep^ files on hold.") + case 2: E_STR( 8,18,20, CFG.hatchpasswd, "Enter the internal ^hatch^ password.") + case 3: E_INT( 9,18, CFG.drspace, "Enter the minimal ^free drivespace^ in KBytes.") + case 4: CFG.tic_systems = edit_int(10,18, CFG.tic_systems, (char *)"Enter the maximum number of ^connected systems^ in the database."); + if ((OpenTicarea() == 0)) + CloseTicarea(TRUE); + working(0, 0, 0); + break; + case 5: CFG.tic_groups = edit_int(11,18, CFG.tic_groups, (char *)"Enter the maximum number of ^fileecho groups^ in the database."); + if ((OpenNoderec() == 0)) + CloseNoderec(TRUE); + working(0, 0, 0); + break; + case 6: E_INT( 12,18, CFG.tic_dupes, "Enter the maximum number of ^dupes^ in the dupe database.") + + case 7: E_BOOL(13,18, CFG.ct_KeepDate, "^Keep^ original filedate on import") + case 8: E_BOOL(14,18, CFG.ct_KeepMgr, "Keep ^Areamgr^ netmails.") + case 9: E_BOOL(15,18, CFG.ct_ResFuture, "Reset ^future^ filedates.") + case 10:E_BOOL(16,18, CFG.ct_LocalRep, "Respond to local ^filesearch^ requests.") + case 11:E_BOOL( 7,58, CFG.ct_ReplExt, "Replace file ^extention^ to * during filesearch") + case 12:E_BOOL( 8,58, CFG.ct_PlusAll, "Allow ^+%*^ (Plus all) in areamgr requests.") + case 13:E_BOOL( 9,58, CFG.ct_Notify, "Allow turning ^notify^ messages on or off.") + case 14:E_BOOL(10,58, CFG.ct_Passwd, "Allow changing the areamgr ^password^.") + case 15:E_BOOL(11,58, CFG.ct_Message, "Allow turning areamgr ^messages^ on or off.") + case 16:E_BOOL(12,58, CFG.ct_TIC, "Allow turning ^TIC^ files on or off.") + case 17:E_BOOL(13,58, CFG.ct_Pause, "Allow the ^pause^ areamgr command.") + } + }; +} + + + +void s_fidomailcfg(void); +void s_fidomailcfg(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 5, "1.13 EDIT FIDONET MAIL AND ECHOMAIL PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Badboard"); + mvprintw( 8, 2, "2. Dupeboard"); + mvprintw( 9, 2, "3. Pktdate"); + mvprintw(10, 2, "4. Max pkts."); + mvprintw(11, 2, "5. Max arcs."); + mvprintw(12, 2, "6. Keep days"); + mvprintw(13, 2, "7. Echo dupes"); + mvprintw(14, 2, "8. Reject old"); + mvprintw(15, 2, "9. Max msgs"); + mvprintw(16, 1, "10. Days old"); + + mvprintw(12,42, "11. Max systems"); + mvprintw(13,42, "12. Max groups"); + mvprintw(14,42, "13. 4d address"); + mvprintw(15,42, "14. Split at"); + mvprintw(16,42, "15. Force at"); + + set_color(WHITE, BLACK); + show_str( 7,16,64, CFG.badboard); + show_str( 8,16,64, CFG.dupboard); + show_str( 9,16,64, CFG.pktdate); + show_int( 10,16, CFG.maxpktsize); + show_int( 11,16, CFG.maxarcsize); + show_int( 12,16, CFG.toss_days); + show_int( 13,16, CFG.toss_dupes); + show_int( 14,16, CFG.toss_old); + show_int( 15,16, CFG.defmsgs); + show_int( 16,16, CFG.defdays); + + show_int( 12,58, CFG.toss_systems); + show_int( 13,58, CFG.toss_groups); + show_bool(14,58, CFG.addr4d); + show_int( 15,58, CFG.new_split); + show_int( 16,58, CFG.new_force); +} + + + +void e_fidomailcfg(void) +{ + s_fidomailcfg(); + for (;;) { + switch(select_menu(15)) { + case 0: return; + case 1: E_JAM( 7,16,64, CFG.badboard, "The path to the ^bad echomail^ board.") + case 2: E_JAM( 8,16,64, CFG.dupboard, "The path to the ^dupe echomail^ board.") + case 3: E_STR( 9,16,64, CFG.pktdate, "The filename and parameters to the ^pktdate^ program.") + case 4: E_INT( 10,16, CFG.maxpktsize, "The maximum size in KB for mail ^packets^, 0 if unlimited.") + case 5: E_INT( 11,16, CFG.maxarcsize, "The maximum size in KB for ^arcmail^ archives, 0 if unlimited.") + case 6: E_INT( 12,16, CFG.toss_days, "The number of ^days^ to keep mail on hold.") + case 7: E_INT( 13,16, CFG.toss_dupes, "The number of ^dupes^ to store in the echomail dupes database.") + case 8: E_INT( 14,16, CFG.toss_old, "^Reject^ mail older then days, 0 means never reject.") + case 9: E_INT( 15,16, CFG.defmsgs, "The default maximum number of ^messages^ in each mail area.") + case 10:E_INT( 16,16, CFG.defdays, "The default maximum ^age in days^ in each mail area.") + + case 11:CFG.toss_systems = edit_int(12,58, CFG.toss_systems, (char *)"The maximum number of connected ^systems^ in the database."); + if ((OpenMsgarea() == 0)) + CloseMsgarea(TRUE); + working(0, 0, 0); + break; + case 12:CFG.toss_groups = edit_int(13,58, CFG.toss_groups, (char *)"The maximum number of ^groups^ in the database."); + if ((OpenNoderec() == 0)) + CloseNoderec(TRUE); + working(0, 0, 0); + break; + case 13:E_BOOL(14,58, CFG.addr4d, "Use ^4d^ addressing instead of ^5d^ addressing.") + case 14:E_INT( 15,58, CFG.new_split, "Gently ^split^ newfiles reports after n kilobytes (12..60).") + case 15:E_INT( 16,58, CFG.new_force, "Force ^split^ of newfiles reports after n kilobytes (16..64).") + } + }; +} + + + +void s_intmailcfg(void); +void s_intmailcfg(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 5, "1.14 EDIT INTERNET MAIL AND NEWS PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. POP3 node"); + mvprintw( 8, 2, "2. SMTP node"); + switch (CFG.newsfeed) { + case FEEDINN: mvprintw( 9, 2, "3. N/A"); + mvprintw(10, 2, "4. NNTP node"); + mvprintw(11, 2, "5. NNTP m.r."); + mvprintw(12, 2, "6. NNTP user"); + mvprintw(13, 2, "7. NNTP pass"); + break; + case FEEDRNEWS: mvprintw( 9, 2, "3. Path rnews"); + mvprintw(10, 2, "4. N/A"); + mvprintw(11, 2, "5. N/A"); + mvprintw(12, 2, "6. N/A"); + mvprintw(13, 2, "7. N/A"); + break; + case FEEDUUCP: mvprintw( 9, 2, "3. UUCP path"); + mvprintw(10, 2, "4. UUCP node"); + mvprintw(11, 2, "5. N/A"); + mvprintw(12, 2, "6. N/A"); + mvprintw(13, 2, "7. N/A"); + break; + } + mvprintw(14, 2, "8. News dupes"); + mvprintw(15, 2, "9. Email aka"); + mvprintw(16, 1, "10. UUCP aka"); + mvprintw(17, 1, "11. Emailmode"); + + mvprintw(13,42, "12. News mode"); + mvprintw(14,42, "13. Split at"); + mvprintw(15,42, "14. Force at"); + mvprintw(16,42, "15. Control ok"); + mvprintw(17,42, "16. No regate"); + + set_color(WHITE, BLACK); + show_str( 7,16,64, CFG.popnode); + show_str( 8,16,64, CFG.smtpnode); + show_str( 9,16,64, CFG.rnewspath); + show_str(10,16,64, CFG.nntpnode); + show_bool(11,16, CFG.modereader); + show_str(12,16,15, CFG.nntpuser); + show_str(13,16,15, (char *)"**************"); + + show_int(14,16, CFG.nntpdupes); + show_aka(15,16, CFG.EmailFidoAka); + show_aka(16,16, CFG.UUCPgate); + show_emailmode(17,16, CFG.EmailMode); + + show_newsmode(13,57, CFG.newsfeed); + show_int( 14,57, CFG.new_split); + show_int( 15,57, CFG.new_force); + show_bool(16,57, CFG.allowcontrol); + show_bool(17,57, CFG.dontregate); +} + + + +/* + * Edit UUCP gateway, return -1 if there are errors, 0 if ok. + */ +void e_uucp(void) +{ + int j; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.14 EDIT UUCP GATEWAY"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Zone"); + mvprintw( 8, 6, "2. Net"); + mvprintw( 9, 6, "3. Node"); + mvprintw(10, 6, "4. Point"); + mvprintw(11, 6, "5. Domain"); + + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,19, CFG.UUCPgate.zone); + show_int( 8,19, CFG.UUCPgate.net); + show_int( 9,19, CFG.UUCPgate.node); + show_int(10,19, CFG.UUCPgate.point); + show_str(11,19,12, CFG.UUCPgate.domain); + + j = select_menu(5); + switch(j) { + case 0: return; + case 1: E_INT( 7,19, CFG.UUCPgate.zone, "The ^zone^ number for the UUCP gateway") + case 2: E_INT( 8,19, CFG.UUCPgate.net, "The ^Net^ number for the UUCP gateway") + case 3: E_INT( 9,19, CFG.UUCPgate.node, "The ^Node^ number for the UUCP gateway") + case 4: E_INT( 10,19, CFG.UUCPgate.point, "The ^Point^ number for the UUCP gateway") + case 5: E_STR( 11,19,11, CFG.UUCPgate.domain, "The ^FTN Domain^ for the UUCP gateway without a dot") + } + } +} + + + +void e_intmailcfg(void) +{ + int tmp; + + s_intmailcfg(); + for (;;) { + switch(select_menu(16)) { + case 0: return; + case 1: E_STR( 7,16,64, CFG.popnode, "The ^FQDN^ of the node where the ^POP3^ server runs.") + case 2: E_STR( 8,16,64, CFG.smtpnode, "The ^FQDN^ of the node where the ^SMTP^ server runs.") + case 3: if (CFG.newsfeed == FEEDRNEWS) + strcpy(CFG.rnewspath, edit_pth(9,16,64, CFG.rnewspath, (char *)"The path and filename to the ^rnews^ command.")); + if (CFG.newsfeed == FEEDUUCP) + strcpy(CFG.rnewspath, edit_pth(9,16,64, CFG.rnewspath, (char *)"The path to the ^uucppublic^ directory.")); + break; + case 4: if (CFG.newsfeed == FEEDINN) + strcpy(CFG.nntpnode, edit_str(10,16,64, CFG.nntpnode, (char *)"The ^FQDN^ of the node where the ^NNTP^ server runs.")); + if (CFG.newsfeed == FEEDUUCP) + strcpy(CFG.nntpnode, edit_str(10,16,64, CFG.nntpnode, (char *)"The ^UUCP^ nodename of the remote UUCP system")); + break; + case 5: E_BOOL(11,16, CFG.modereader, "Does the NNTP server needs the ^Mode Reader^ command.") + case 6: E_STR( 12,16,15, CFG.nntpuser, "The ^Username^ for the NNTP server if needed.") + case 7: E_STR( 13,16,15, CFG.nntppass, "The ^Password^ for the NNTP server if needed.") + case 8: E_INT( 14,16, CFG.nntpdupes, "The number of ^dupes^ to store in the news articles dupes database.") + case 9: tmp = PickAka((char *)"1.14.8", FALSE); + if (tmp != -1) + CFG.EmailFidoAka = CFG.aka[tmp]; + s_intmailcfg(); + break; + case 10:e_uucp(); + s_intmailcfg(); + break; + case 11:CFG.EmailMode = edit_emailmode(17,16, CFG.EmailMode); + s_intmailcfg(); + break; + + case 12:CFG.newsfeed = edit_newsmode(13,57, CFG.newsfeed); + s_intmailcfg(); + break; + case 13:E_INT( 14,57, CFG.new_split, "Gently ^split^ messages after n kilobytes (12..60).") + case 14:E_INT( 15,57, CFG.new_force, "Force ^split^ of messages after n kilobytes (16..64).") + case 15:E_BOOL(16,57, CFG.allowcontrol, "^Allow control^ messages for news to be gated.") + case 16:E_BOOL(17,57, CFG.dontregate, "Don't ^regate^ already gated messages.") + } + }; +} + + + +void s_newfiles(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.15 ALLFILES & NEWFILES LISTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Ftp base"); + mvprintw( 8, 2, "2. New days"); + mvprintw( 9, 2, "3. Security"); + mvprintw(10, 2, "4. Groups"); +} + + + +void e_newfiles(void) +{ + s_newfiles(); + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16,64, CFG.ftp_base); + show_int( 8,16, CFG.newdays); + show_sec( 9,16, CFG.security); + show_int(10,16, CFG.new_groups); + + switch(select_menu(4)) { + case 0: return; + case 1: E_PTH(7,16,64, CFG.ftp_base, "The ^FTP home^ directory to strip of the real directory") + case 2: E_INT(8,16, CFG.newdays, "Add files younger than this in newfiles report.") + case 3: E_SEC(9,16, CFG.security, "1.14 NEWFILES REPORTS SECURITY", s_newfiles) + case 4: E_INT(10,16, CFG.new_groups, "The maximum of ^newfiles^ groups in the newfiles database") + } + }; +} + + + +/* + * Edit one aka, return -1 if there are errors, 0 if ok. + */ +void e_aka(int Area) +{ + int j; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.16 EDIT AKA"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Zone"); + mvprintw( 8, 6, "2. Net"); + mvprintw( 9, 6, "3. Node"); + mvprintw(10, 6, "4. Point"); + mvprintw(11, 6, "5. Domain"); + mvprintw(12, 6, "6. Active"); + + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,19, CFG.aka[Area].zone); + show_int( 8,19, CFG.aka[Area].net); + show_int( 9,19, CFG.aka[Area].node); + show_int(10,19, CFG.aka[Area].point); + show_str(11,19,12, CFG.aka[Area].domain); + show_bool(12,19, CFG.akavalid[Area]); + + j = select_menu(6); + switch(j) { + case 0: return; + case 1: E_INT( 7,19, CFG.aka[Area].zone, "The ^zone^ number for this aka") + case 2: E_INT( 8,19, CFG.aka[Area].net, "The ^Net^ number for this aka") + case 3: E_INT( 9,19, CFG.aka[Area].node, "The ^Node^ number for this aka") + case 4: E_INT( 10,19, CFG.aka[Area].point, "The ^Point^ number for this node (if any)") + case 5: E_STR( 11,19,11, CFG.aka[Area].domain, "The ^FTN Domain^ for this aka without a dot (ie no .org)") + case 6: E_BOOL(12,19, CFG.akavalid[Area], "Is this aka ^available^") + } + } +} + + + +void e_fidoakas(void) +{ + int i, x, y, o; + char pick[12]; + char temp[121]; + + o = 0; + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.16 EDIT FIDONET AKA'S"); + set_color(CYAN, BLACK); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= 40) { + if (CFG.akavalid[o+i-1]) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + if (CFG.akavalid[o+i-1]) { + sprintf(temp, "%3d %s", o+i, aka2str(CFG.aka[o+i-1])); + temp[38] = '\0'; + } else + sprintf(temp, "%3d", o+i); + mvprintw(y, x, temp); + y++; + } + } + strcpy(pick, select_pick(40, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < 40) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= 40)) + e_aka(atoi(pick)-1); + } +} + + + +void s_mailer(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.17 EDIT MAILER SETTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Mailer logl."); + mvprintw( 8, 2, "2. Default phone"); + mvprintw( 9, 2, "3. TCP/IP flags"); + mvprintw(10, 2, "4. Default speed"); + mvprintw(11, 2, "5. Timeout reset"); + mvprintw(12, 2, "6. Timeout connect"); + mvprintw(13, 2, "7. Dial delay"); + mvprintw(14, 2, "8. No Filerequests"); + mvprintw(15, 2, "9. No callout"); + mvprintw(16, 2, "10. No Hold mail"); + mvprintw(17, 2, "11. No pickup all"); + + mvprintw(12,31, "12. No EMSI session"); + mvprintw(13,31, "13. No Yooho/2U2"); + mvprintw(14,31, "14. No Zmodem"); + mvprintw(15,31, "15. No Zedzap"); + mvprintw(16,31, "16. No Hydra"); + mvprintw(17,31, "17. No TCP/IP"); + + mvprintw(12,59, "18. Phonetrans 1-10"); + mvprintw(13,59, "19. Phonetrans 11-20"); + mvprintw(14,59, "20. Phonetrans 21-30"); + mvprintw(15,59, "21. Phonetrans 31-40"); + mvprintw(16,59, "22. Max. files"); + mvprintw(17,59, "23. Max. MB."); +} + + + +void e_trans(int start) +{ + int i, j; + char temp[21]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.17 EDIT PHONE TRANSLATION"); + set_color(CYAN, BLACK); + mvprintw( 7, 12, "String to match String to replace"); + for (i = 0; i < 10; i++) { + sprintf(temp, "%2d.", i+1); + mvprintw( 9+i, 6, temp); + } + for (;;) { + set_color(WHITE, BLACK); + for (i = 0; i < 10; i++) { + show_str( 9+i,12,20,CFG.phonetrans[i+start].match); + show_str( 9+i,34,20,CFG.phonetrans[i+start].repl); + } + + j = select_menu(10); + if (j == 0) { + s_mailer(); + return; + } + strcpy(CFG.phonetrans[j+start-1].match, edit_str(j+8,12,20, CFG.phonetrans[j+start-1].match, (char *)"The phone entry to ^match^")); + strcpy(CFG.phonetrans[j+start-1].repl, edit_str(j+8,34,20, CFG.phonetrans[j+start-1].repl, (char *)"The phone string to ^replace^")); + } +} + + + +void e_mailer(void) +{ + s_mailer(); + for (;;) { + set_color(WHITE, BLACK); + show_logl( 7,23, CFG.cico_loglevel); + show_str( 8,23,20,CFG.Phone); + show_str( 9,23,30,CFG.Flags); + show_int( 10,23, CFG.Speed); + show_int( 11,23, CFG.timeoutreset); + show_int( 12,23, CFG.timeoutconnect); + show_int( 13,23, CFG.dialdelay); + show_bool(14,23, CFG.NoFreqs); + show_bool(15,23, CFG.NoCall); + show_bool(16,23, CFG.NoHold); + show_bool(17,23, CFG.NoPUA); + + show_bool(12,52, CFG.NoEMSI); + show_bool(13,52, CFG.NoWazoo); + show_bool(14,52, CFG.NoZmodem); + show_bool(15,52, CFG.NoZedzap); + show_bool(16,52, CFG.NoHydra); + show_bool(17,52, CFG.NoTCP); + + show_int( 16,75, CFG.Req_Files); + show_int( 17,75, CFG.Req_MBytes); + + switch(select_menu(23)) { + case 0: return; + case 1: E_LOGL(CFG.cico_loglevel, "1.17.1", s_mailer) + case 2: E_STR( 8,23,20,CFG.Phone, "The mailer default ^phone number^ for this system") + case 3: E_STR( 9,23,30,CFG.Flags, "The mailer ^TCP/IP capability flags^ for this system") + case 4: E_INT( 10,23, CFG.Speed, "The mailer ^default linespeed^ for this system") + case 5: E_INT( 11,23, CFG.timeoutreset, "The modem ^reset timeout^ in seconds") + case 6: E_INT( 12,23, CFG.timeoutconnect, "The modem ^wait for connect timeout^ in seconds") + case 7: E_INT( 13,23, CFG.dialdelay, "The ^random dialdelay^ in seconds ((^n^ <= delay) and (^n^ > (delay / 10)))") + case 8: E_BOOL(14,23, CFG.NoFreqs, "Set to true if ^No Filerequests^ are allowed") + case 9: E_BOOL(15,23, CFG.NoCall, "Set to true if ^No Calls^ are allowed") + case 10:E_BOOL(16,23, CFG.NoHold, "Set to true if we send ^Hold packets^ when we initiate the session") + case 11:E_BOOL(17,23, CFG.NoPUA, "Set to true for ^pickup mail^ only from the primary address") + + case 12:E_BOOL(12,52, CFG.NoEMSI, "If set then ^EMSI handshake^ is diabled") + case 13:E_BOOL(13,52, CFG.NoWazoo, "If set then ^YooHoo/2U2^ (FTSC-0006) is disabled") + case 14:E_BOOL(14,52, CFG.NoZmodem, "If set then the ^Zmodem^ protocol is disabled") + case 15:E_BOOL(15,52, CFG.NoZedzap, "If set then the ^Zedzap^ protocol is disabled") + case 16:E_BOOL(16,52, CFG.NoHydra, "If set then the ^Hydra^ protocol is disabled") + case 17:E_BOOL(17,52, CFG.NoTCP, "If set then the ^TCP/IP^ protocol is disabled"); + case 18:e_trans(0); + break; + case 19:e_trans(10); + break; + case 20:e_trans(20); + break; + case 21:e_trans(30); + break; + case 22:E_INT(16,75, CFG.Req_Files, "Maximum ^files^ to request, 0 is unlimited") + case 23:E_INT(17,75, CFG.Req_MBytes, "Maximum ^MBytes^ to request, 0 is unlimited") + } + }; +} + + + +void e_ftpd(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.18 EDIT FTPD SETTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Base path"); + mvprintw( 8, 2, "2. Upload pth"); + mvprintw( 9, 2, "3. Banner msg"); + mvprintw(10, 2, "4. Pth filter"); + mvprintw(11, 2, "5. Pth msg"); + mvprintw(12, 2, "6. Email addr"); + mvprintw(13, 2, "7. Shutdown"); + mvprintw(14, 2, "8. Rdm login"); + mvprintw(15, 2, "9. Rdm cwd*"); + mvprintw(16, 1,"10. Msg login"); + mvprintw(17, 1,"11. Msg cwd*"); + mvprintw(18, 1,"12. Userslimit"); + mvprintw(19, 1,"13. Loginfails"); + + mvprintw(14,60,"14. Compress"); + mvprintw(15,60,"15. Tar"); + mvprintw(16,60,"16. Mkdir ok"); + mvprintw(17,60,"17. Log cmds"); + mvprintw(18,60,"18. Anonymous"); + mvprintw(19,60,"19. User mbse"); + + set_color(WHITE, BLACK); + show_str( 7,18,59, CFG.ftp_base); + show_str( 8,18,59, CFG.ftp_upl_path); + show_str( 9,18,59, CFG.ftp_banner); + show_str(10,18,40, CFG.ftp_pth_filter); + show_str(11,18,59, CFG.ftp_pth_message); + show_str(12,18,40, CFG.ftp_email); + show_str(13,18,40, CFG.ftp_msg_shutmsg); + show_str(14,18,20, CFG.ftp_readme_login); + show_str(15,18,20, CFG.ftp_readme_cwd); + show_str(16,18,20, CFG.ftp_msg_login); + show_str(17,18,20, CFG.ftp_msg_cwd); + show_int(18,18, CFG.ftp_limit); + show_int(19,18, CFG.ftp_loginfails); + + show_bool(14,75, CFG.ftp_compress); + show_bool(15,75, CFG.ftp_tar); + show_bool(16,75, CFG.ftp_upl_mkdir); + show_bool(17,75, CFG.ftp_log_cmds); + show_bool(18,75, CFG.ftp_anonymousok); + show_bool(19,75, CFG.ftp_mbseok); + + for (;;) { + set_color(WHITE, BLACK); + + switch(select_menu(19)) { + case 0: return; + case 1: E_STR( 7,18,59, CFG.ftp_base, "Public ^base path^ to the files") + case 2: E_STR( 8,18,59, CFG.ftp_upl_path, "Public ^upload^ path, must be in the base path") + case 3: E_STR( 9,18,59, CFG.ftp_banner, "^Banner^ file to show before login") + case 4: E_STR(10,18,40, CFG.ftp_pth_filter, "^Filter^ with allowed characters in upload filename") + case 5: E_STR(11,18,59, CFG.ftp_pth_message, "^Message^ to display if illegal characters in filename") + case 6: E_STR(12,18,40, CFG.ftp_email, "^Email^ address of the ftp server administrator") + case 7: E_STR(13,18,40, CFG.ftp_msg_shutmsg, "^Shutdown message^, if this file is present, login if forbidden") + case 8: E_STR(14,18,20, CFG.ftp_readme_login,"^README^ file to display at login") + case 9: E_STR(15,18,20, CFG.ftp_readme_cwd, "^README^ file to display when entering a new directory") + case 10:E_STR(16,18,20, CFG.ftp_msg_login, "^Message^ file to display at login") + case 11:E_STR(17,18,20, CFG.ftp_msg_cwd, "^Message^ file to display when entering a new directory") + case 12:E_INT(18,18, CFG.ftp_limit, "^Limit^ the number of concurent ftp users") + case 13:E_INT(19,18, CFG.ftp_loginfails, "Maximum ^login fails^ before a user is disconnected") + case 14:E_BOOL(14,75, CFG.ftp_compress, "Allow the use of the ^compress^ command") + case 15:E_BOOL(15,75, CFG.ftp_tar, "Allow the use if the ^tar^ command") + case 16:E_BOOL(16,75, CFG.ftp_upl_mkdir, "Allow ^mkdir^ in the upload directory") + case 17:E_BOOL(17,75, CFG.ftp_log_cmds, "^Log^ all user ^commands^") + case 18:E_BOOL(18,75, CFG.ftp_anonymousok, "Allow ^anonymous^ users to login") + case 19:E_BOOL(19,75, CFG.ftp_mbseok, "Allow the ^mbse^ user to login") + } + }; +} + + + +void e_html(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.19 EDIT HTML SETTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Docs root"); + mvprintw( 8, 2, "2. Link to ftp"); + mvprintw( 9, 2, "3. URL name"); + mvprintw(10, 2, "4. Charset"); + mvprintw(11, 2, "5. Table color"); + mvprintw(12, 2, "6. Hdr. color"); + mvprintw(13, 2, "7. Author name"); + mvprintw(14, 2, "8. Convert cmd"); + mvprintw(15, 2, "9. Files/page"); + mvprintw(16, 1,"10. Icon Home"); + mvprintw(17, 1,"11. Text Home"); + mvprintw(18, 1,"12. Icon Back"); + mvprintw(19, 1,"13. Text Back"); + mvprintw(16,41,"14. Icon Prev."); + mvprintw(17,41,"15. Text Prev."); + mvprintw(18,41,"16. Icon Next"); + mvprintw(19,41,"17. Text Next"); + + set_color(WHITE, BLACK); + show_str( 7,18,59, CFG.www_root); + show_str( 8,18,20, CFG.www_link2ftp); + show_str( 9,18,40, CFG.www_url); + show_str(10,18,20, CFG.www_charset); + show_str(11,18,20, CFG.www_tbgcolor); + show_str(12,18,20, CFG.www_hbgcolor); + show_str(13,18,40, CFG.www_author); + show_str(14,18,59, CFG.www_convert); + show_int(15,18, CFG.www_files_page); + show_str(16,18,20, CFG.www_icon_home); + show_str(17,18,20, CFG.www_name_home); + show_str(18,18,20, CFG.www_icon_back); + show_str(19,18,20, CFG.www_name_back); + show_str(16,58,20, CFG.www_icon_prev); + show_str(17,58,20, CFG.www_name_prev); + show_str(18,58,20, CFG.www_icon_next); + show_str(19,58,20, CFG.www_name_next); + + for (;;) { + set_color(WHITE, BLACK); + + switch(select_menu(17)) { + case 0: return; + case 1: E_STR( 7,18,59, CFG.www_root, "The ^Document root^ of your http server") + case 2: E_STR( 8,18,20, CFG.www_link2ftp, "The ^link^ name from the Document root to the FTP base directory") + case 3: E_STR( 9,18,40, CFG.www_url, "The ^URL^ name of your http server") + case 4: E_STR(10,18,20, CFG.www_charset, "The ^ISO character set^ name to include in the web pages") + case 5: E_STR(11,18,20, CFG.www_tbgcolor, "The ^Tables background color^ to use") + case 6: E_STR(12,18,20, CFG.www_hbgcolor, "The ^Table headers background color^ to use") + case 7: E_STR(13,18,40, CFG.www_author, "The ^Author name^ to include in the http headers") + case 8: E_STR(14,18,59, CFG.www_convert, "The ^convert^ command to create thumbnails") + case 9: E_INT(15,18, CFG.www_files_page, "The number of files on each web page") + case 10:E_STR(16,18,20, CFG.www_icon_home, "The ^Home icon^ filename") + case 11:E_STR(17,18,20, CFG.www_name_home, "The ^Home text^ to appear") + case 12:E_STR(18,18,20, CFG.www_icon_back, "The ^Back icon^ filename") + case 13:E_STR(19,18,20, CFG.www_name_back, "The ^Back text^ to appear") + case 14:E_STR(16,58,20, CFG.www_icon_prev, "The ^Previous page icon^ filename") + case 15:E_STR(17,58,20, CFG.www_name_prev, "The ^Previous page text^ to appear") + case 16:E_STR(18,58,20, CFG.www_icon_next, "The ^Next Page icon^ filename") + case 17:E_STR(19,58,20, CFG.www_name_next, "The ^Next Page text^ to appear") + } + }; +} + + + +void global_menu(void) +{ + unsigned long crc, crc1; + + if (cf_open() == -1) + return; + + Syslog('+', "Opened main config"); + crc = 0xffffffff; + crc = upd_crc32((char *)&CFG, crc, sizeof(CFG)); + + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1. GLOBAL SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Registration Info"); + mvprintw( 8, 6, "2. Edit Global Filenames"); + mvprintw( 9, 6, "3. Edit Global Paths"); + mvprintw(10, 6, "4. Edit Global Settings"); + mvprintw(11, 6, "5. Edit New Users defaults"); + mvprintw(12, 6, "6. Edit Text Colors"); + mvprintw(13, 6, "7. Edit Next User Door"); + mvprintw(14, 6, "8. Edit Safe Door"); + mvprintw(15, 6, "9. Edit Time Bank Door"); + mvprintw(16, 6, "10. Edit Sysop Paging"); + + mvprintw( 7,46, "11. Edit Flag Descriptions"); + mvprintw( 8,46, "12. Edit Files Processing"); + mvprintw( 9,46, "13. Edit Fidonet Mail/Echomail"); + mvprintw(10,46, "14. Edit Internet Mail/News"); + mvprintw(11,46, "15. Edit All-/Newfiles lists"); + mvprintw(12,46, "16. Edit Fidonet Aka's"); + mvprintw(13,46, "17. Edit Mailer setup"); + mvprintw(14,46, "18. Edit Ftp daemon setup"); + mvprintw(15,46, "19. Edit HTML pages setup"); + + switch(select_menu(19)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&CFG, crc1, sizeof(CFG)); + if (crc != crc1) { + if (yes_no((char *)"Configuration is changed, save") == 1) { + cf_close(); + Syslog('+', "Saved main config"); + } + } + return; + case 1: + e_reginfo(); + break; + case 2: + e_filenames(); + break; + case 3: + e_global(); + break; + case 4: + e_bbsglob(); + break; + case 5: + e_newuser(); + break; + case 6: + e_colors(); + break; + case 7: + e_nu_door(); + break; + case 8: + e_safe_door(); + break; + case 9: + e_timebank(); + break; + case 10: + e_paging(); + break; + case 11: + e_flags(); + break; + case 12: + e_ticconf(); + break; + case 13: + e_fidomailcfg(); + break; + case 14: + e_intmailcfg(); + break; + case 15: + e_newfiles(); + break; + case 16: + e_fidoakas(); + break; + case 17: + e_mailer(); + break; + case 18: + e_ftpd(); + break; + case 19: + e_html(); + break; + } + } +} + + + +int PickAka(char *msg, int openit) +{ + char temp[81]; + static char pick[12]; + int i, o = 0, x, y; + + if (openit) { + if (cf_open() == -1) + return -1; + cf_close(); + } + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. AKA SELECT", msg); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + x = 2; + y = 7; + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= 40) { + if (CFG.akavalid[o+i-1]) { + set_color(CYAN, BLACK); + sprintf(temp, "%3d %s", o+i, aka2str(CFG.aka[o+i-1])); + temp[38] = '\0'; + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d", o+i); + } + mvprintw(y, x, temp); + y++; + } + } + strcpy(pick, select_pick(40, 20)); + + if (strncmp(pick, "-", 1) == 0) + return -1; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < 40) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= 40) && (CFG.akavalid[atoi(pick)-1])) + return (atoi(pick) -1); + } +} + + +char Co[16][16] = { + "Black", "Blue", "Green", "Cyan", + "Red", "Magenta", "Brown", "Lightgray", + "Darkgary", "Lightblue", "Lightgreen", "Lightcyan", + "Lightred", "Lightmagenta", "Yellow", "White" }; + + +int global_doc(FILE *fp, FILE *toc, int page) +{ + int i, j; + struct utsname utsbuf; + time_t now; + char *p; + + if (config_read()) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 1, 0, page, (char *)"Global system setup"); + addtoc(fp, toc, 1, 1, page, (char *)"Host system information"); + + memset(&utsbuf, 0, sizeof(utsbuf)); + if (uname(&utsbuf) == 0) { + fprintf(fp, " Node name %s\n", utsbuf.nodename); +#ifdef __USE_GNU + fprintf(fp, " Domain name %s\n", utsbuf.domainname); +#else + fprintf(fp, " Domain name %s\n", utsbuf.__domainname); +#endif + fprintf(fp, " Operating system %s %s\n", utsbuf.sysname, utsbuf.release); + fprintf(fp, " Kernel version %s\n", utsbuf.version); + fprintf(fp, " Machine type %s\n", utsbuf.machine); + } + fprintf(fp, " MBSE_ROOT %s\n", getenv("MBSE_ROOT")); + time(&now); + fprintf(fp, " Date created %s", ctime(&now)); + + addtoc(fp, toc, 1, 2, page, (char *)"Registration information"); + + fprintf(fp, " System name %s\n", CFG.bbs_name); + fprintf(fp, " Domain name %s\n", CFG.sysdomain); + fprintf(fp, " Sysop unix name %s\n", CFG.sysop); + fprintf(fp, " Sysop fido name %s\n", CFG.sysop_name); + fprintf(fp, " System location %s\n", CFG.location); + fprintf(fp, " QWK/Bluewave id %s\n", CFG.bbsid); + fprintf(fp, " Omen id %s\n", CFG.bbsid2); + fprintf(fp, " Comment %s\n", CFG.comment); + fprintf(fp, " Origin line %s\n", CFG.origin); + fprintf(fp, " Start unix name %s\n", CFG.startname); + + addtoc(fp, toc, 1, 3, page, (char *)"Global filenames"); + + fprintf(fp, " System logfile %s\n", CFG.logfile); + fprintf(fp, " Error logfile %s\n", CFG.error_log); + fprintf(fp, " Default menu %s\n", CFG.default_menu); + fprintf(fp, " Default language %s\n", CFG.current_language); + fprintf(fp, " Chat logfile %s\n", CFG.chat_log); + fprintf(fp, " Welcome logo %s\n", CFG.welcome_logo); + + addtoc(fp, toc, 1, 4, page, (char *)"Pathnames"); + + fprintf(fp, " Menufiles %s\n", CFG.bbs_menus); + fprintf(fp, " Textfiles %s\n", CFG.bbs_txtfiles); + fprintf(fp, " Users homedirs %s\n", CFG.bbs_usersdir); + fprintf(fp, " Nodelists %s\n", CFG.nodelists); + fprintf(fp, " Unsafe inbound %s\n", CFG.inbound); + fprintf(fp, " Known inbound %s\n", CFG.pinbound); + fprintf(fp, " Bad TIC's %s\n", CFG.badtic); + fprintf(fp, " TIC queue %s\n", CFG.ticout); + fprintf(fp, " Magic filereq. %s\n", CFG.req_magic); + fprintf(fp, " DOS path %s\n", CFG.dospath); + fprintf(fp, " Unix path %s\n", CFG.uxpath); + fprintf(fp, " Leave case as is %s\n", getboolean(CFG.leavecase)); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 5, page, (char *)"Global settings"); + + fprintf(fp, " Private system %s\n", getboolean(CFG.elite_mode)); + fprintf(fp, " Show new msgarea %s\n", getboolean(CFG.NewAreas)); + fprintf(fp, " Exclude sysop %s\n", getboolean(CFG.exclude_sysop)); + fprintf(fp, " Show connect %s\n", getboolean(CFG.iConnectString)); + fprintf(fp, " Ask protocols %s\n", getboolean(CFG.iAskFileProtocols)); + fprintf(fp, " Sysop level %d\n", CFG.sysop_access); + fprintf(fp, " Password length %d\n", CFG.password_length); + p = getloglevel(CFG.bbs_loglevel); + fprintf(fp, " BBS loglevel %s\n", p); + free(p); + p = getloglevel(CFG.util_loglevel); + fprintf(fp, " Util loglevel %s\n", p); + free(p); + fprintf(fp, " Password char %c\n", CFG.iPasswd_Char); + fprintf(fp, " Idle timeout %d mins\n", CFG.idleout); + fprintf(fp, " Login enters %d\n", CFG.iCRLoginCount); + fprintf(fp, " Login attempts %d\n", CFG.max_login); + fprintf(fp, " Homedir quota %d MB.\n", CFG.iQuota); + fprintf(fp, " Location length %d\n", CFG.CityLen); + fprintf(fp, " OLR Max. msgs. %d\n", CFG.OLR_MaxMsgs); + fprintf(fp, " OLR Newfile days %d\n", CFG.OLR_NewFileLimit); + fprintf(fp, " OLR Max Freq's %d\n", CFG.OLR_MaxReq); + fprintf(fp, " Slow utilities %s\n", getboolean(CFG.slow_util)); + fprintf(fp, " CrashMail level %d\n", CFG.iCrashLevel); + fprintf(fp, " FileAttach level %d\n", CFG.iAttachLevel); + fprintf(fp, " Free diskspace %d MB.\n", CFG.freespace); + + addtoc(fp, toc, 1, 6, page, (char *)"New users defaults"); + + fprintf(fp, " Access level %s\n", get_secstr(CFG.newuser_access)); + fprintf(fp, " Cap. username %s\n", getboolean(CFG.iCapUserName)); + fprintf(fp, " Ask ANSI %s\n", getboolean(CFG.iAnsi)); + fprintf(fp, " Ask Sex %s\n", getboolean(CFG.iSex)); + fprintf(fp, " Ask voicephone %s\n", getboolean(CFG.iVoicePhone)); + fprintf(fp, " Ask dataphone %s\n", getboolean(CFG.iDataPhone)); + fprintf(fp, " Telephone scan %s\n", getboolean(CFG.iTelephoneScan)); + fprintf(fp, " Ask handle %s\n", getboolean(CFG.iHandle)); + fprintf(fp, " Ask birthdate %s\n", getboolean(CFG.iDOB)); + fprintf(fp, " Ask location %s\n", getboolean(CFG.iLocation)); + fprintf(fp, " Ask hotkeys %s\n", getboolean(CFG.iHotkeys)); + fprintf(fp, " One word names %s\n", getboolean(CFG.iOneName)); + fprintf(fp, " Ask address %s\n", getboolean(CFG.AskAddress)); + fprintf(fp, " Give email box %s\n", getboolean(CFG.GiveEmail)); + + addtoc(fp, toc, 1, 7, page, (char *)"Text colors"); + + fprintf(fp, " Normal text %s on %s\n", Co[CFG.TextColourF], Co[CFG.TextColourB]); + fprintf(fp, " Underline text %s on %s\n", Co[CFG.UnderlineColourF], Co[CFG.UnderlineColourB]); + fprintf(fp, " Input text %s on %s\n", Co[CFG.InputColourF], Co[CFG.InputColourB]); + fprintf(fp, " CR text %s on %s\n", Co[CFG.CRColourF], Co[CFG.CRColourB]); + fprintf(fp, " More prompt %s on %s\n", Co[CFG.MoreF], Co[CFG.MoreB]); + fprintf(fp, " Hilite text %s on %s\n", Co[CFG.HiliteF], Co[CFG.HiliteB]); + fprintf(fp, " File name %s on %s\n", Co[CFG.FilenameF], Co[CFG.FilenameB]); + fprintf(fp, " File size %s on %s\n", Co[CFG.FilesizeF], Co[CFG.FilesizeB]); + fprintf(fp, " File date %s on %s\n", Co[CFG.FiledateF], Co[CFG.FiledateB]); + fprintf(fp, " File description %s on %s\n", Co[CFG.FiledescF], Co[CFG.FiledescB]); + fprintf(fp, " Message input %s on %s\n", Co[CFG.MsgInputColourF], Co[CFG.MsgInputColourB]); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 8, page, (char *)"Next user door"); + + fprintf(fp, " Text file %s\n", CFG.sNuScreen); + fprintf(fp, " Quote %s\n", CFG.sNuQuote); + + addtoc(fp, toc, 1, 9, page, (char *)"Safecracker door"); + + fprintf(fp, " Digit nr 1 %d\n", CFG.iSafeFirstDigit); + fprintf(fp, " Digit nr 2 %d\n", CFG.iSafeSecondDigit); + fprintf(fp, " Digit nr 3 %d\n", CFG.iSafeThirdDigit); + fprintf(fp, " Maximum tries %d\n", CFG.iSafeMaxTrys); + fprintf(fp, " Maximum number %d\n", CFG.iSafeMaxNumber); + fprintf(fp, " Show generator %s\n", getboolean(CFG.iSafeNumGen)); + fprintf(fp, " Prize %s\n", CFG.sSafePrize); + fprintf(fp, " Safe welcome %s\n", CFG.sSafeWelcome); + fprintf(fp, " Safe opened file %s\n", CFG.sSafeOpened); + + addtoc(fp, toc, 1, 10, page, (char *)"Timebank door"); + + fprintf(fp, " Users time balance %d\n", CFG.iMaxTimeBalance); + fprintf(fp, " Max. time withdraw %d\n", CFG.iMaxTimeWithdraw); + fprintf(fp, " Max. time deposit %d\n", CFG.iMaxTimeDeposit); + fprintf(fp, " Users kb. balance %d\n", CFG.iMaxByteBalance); + fprintf(fp, " Max. Kb. withdraw %d\n", CFG.iMaxByteWithdraw); + fprintf(fp, " Max. Kb. deposit %d\n", CFG.iMaxByteDeposit); + fprintf(fp, " Users time ratio %s\n", CFG.sTimeRatio); + fprintf(fp, " Users Kb. ratio %s\n", CFG.sByteRatio); + + addtoc(fp, toc, 1, 11, page, (char *)"Sysop paging"); + + fprintf(fp, " Ext. Chat program %s\n", CFG.sExternalChat); + fprintf(fp, " Chat device %s\n", CFG.sChatDevice); + fprintf(fp, " Call sysop script %s\n", CFG.sCallScript); + fprintf(fp, " Page length %d seconds\n", CFG.iPageLength); + fprintf(fp, " Page times %d\n", CFG.iMaxPageTimes); + fprintf(fp, " Sysop msg area %d\n", CFG.iSysopArea); + fprintf(fp, " Ask chat reason %s\n", getboolean(CFG.iAskReason)); + fprintf(fp, " Use external chat %s\n", getboolean(CFG.iExternalChat)); + fprintf(fp, " Log chat %s\n", getboolean(CFG.iAutoLog)); + fprintf(fp, " Check at prompt %s\n", getboolean(CFG.iChatPromptChk)); + fprintf(fp, " Freeze online time %s\n", getboolean(CFG.iStopChatTime)); + + fprintf(fp, "\n Weekday Start Stop\n"); + fprintf(fp, " ------------- ----- -----\n"); + fprintf(fp, " Sunday %s %s\n", CFG.cStartTime[0], CFG.cStopTime[0]); + fprintf(fp, " Monday %s %s\n", CFG.cStartTime[1], CFG.cStopTime[1]); + fprintf(fp, " Tuesday %s %s\n", CFG.cStartTime[2], CFG.cStopTime[2]); + fprintf(fp, " Wednesday %s %s\n", CFG.cStartTime[3], CFG.cStopTime[3]); + fprintf(fp, " Thursday %s %s\n", CFG.cStartTime[4], CFG.cStopTime[4]); + fprintf(fp, " Friday %s %s\n", CFG.cStartTime[5], CFG.cStopTime[5]); + fprintf(fp, " Saterday %s %s\n", CFG.cStartTime[6], CFG.cStopTime[6]); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 12, page, (char *)"Flag descriptions"); + + fprintf(fp, " 1 1 2 2 3 3\n"); + fprintf(fp, " 1 5 0 5 0 5 0 2\n"); + fprintf(fp, " --------------------------------\n"); + fprintf(fp, " ||||||||||||||||||||||||||||||||\n"); + + for (i = 0; i < 32; i++) { + fprintf(fp, " "); + + for (j = 0; j < (31 - i); j++) + fprintf(fp, "|"); + fprintf(fp, "+"); + for (j = (32 - i); j < 32; j++) + fprintf(fp, "-"); + + fprintf(fp, " %s\n", CFG.fname[31 - i]); + } + + page = newpage(fp, page); + addtoc(fp, toc, 1, 13, page, (char *)"Fileecho processing"); + + fprintf(fp, " Keep days on hold %d\n", CFG.tic_days); + fprintf(fp, " Hatch password %s\n", CFG.hatchpasswd); + fprintf(fp, " Free drivespave %lu\n", CFG.drspace); + fprintf(fp, " Max. systems %ld\n", CFG.tic_systems); + fprintf(fp, " Max. groups %ld\n", CFG.tic_groups); + fprintf(fp, " Max. dupes %ld\n", CFG.tic_dupes); + fprintf(fp, " Keep filedate %s\n", getboolean(CFG.ct_KeepDate)); + fprintf(fp, " Keep mgr netmail %s\n", getboolean(CFG.ct_KeepMgr)); + fprintf(fp, " Reset future dates %s\n", getboolean(CFG.ct_ResFuture)); + fprintf(fp, " Local requests %s\n", getboolean(CFG.ct_LocalRep)); + fprintf(fp, " Replace extention %s\n", getboolean(CFG.ct_ReplExt)); + fprintf(fp, " Areamgr: allow +%%* %s\n", getboolean(CFG.ct_PlusAll)); + fprintf(fp, " Areamgr: notify %s\n", getboolean(CFG.ct_Notify)); + fprintf(fp, " Areamgr: passwd %s\n", getboolean(CFG.ct_Passwd)); + fprintf(fp, " Areamgr: message %s\n", getboolean(CFG.ct_Message)); + fprintf(fp, " Areamgr: TIC %s\n", getboolean(CFG.ct_TIC)); + fprintf(fp, " Areamgr: pause %s\n", getboolean(CFG.ct_Pause)); + + addtoc(fp, toc, 1, 14, page, (char *)"Fidonet Mail and Echomail processing"); + + fprintf(fp, " Max .pkt size %d Kb.\n", CFG.maxpktsize); + fprintf(fp, " Max archive size %d Kb.\n", CFG.maxarcsize); + fprintf(fp, " Bad mail board %s\n", CFG.badboard); + fprintf(fp, " Dupe mail board %s\n", CFG.dupboard); + fprintf(fp, " Pktdate program %s\n", CFG.pktdate); + fprintf(fp, " Keep on hold %d days\n", CFG.toss_days); + fprintf(fp, " Dupes in database %d\n", CFG.toss_dupes); + fprintf(fp, " Default max msgs %d\n", CFG.defmsgs); + fprintf(fp, " Default days %d\n", CFG.defdays); + fprintf(fp, " Reject older then %d days\n", CFG.toss_old); + fprintf(fp, " Maximum systems %ld\n", CFG.toss_systems); + fprintf(fp, " Maximum groups %ld\n", CFG.toss_groups); + fprintf(fp, " Use 4d addressing %s\n", getboolean(CFG.addr4d)); + + addtoc(fp, toc, 1, 15, page, (char *)"Internet Mail and News processing"); + + fprintf(fp, " Split messages at %d KBytes\n", CFG.new_split); + fprintf(fp, " Force split at %d KBytes\n", CFG.new_force); + fprintf(fp, " ISP Email Mode %s\n", getemailmode(CFG.EmailMode)); + fprintf(fp, " Email fido aka %s\n", aka2str(CFG.EmailFidoAka)); + fprintf(fp, " UUCP gateway %s\n", aka2str(CFG.UUCPgate)); + fprintf(fp, " POP3 host %s\n", CFG.popnode); + fprintf(fp, " SMTP host %s\n", CFG.smtpnode); + fprintf(fp, " News transfermode %s\n", getnewsmode(CFG.newsfeed)); + switch (CFG.newsfeed) { + case FEEDINN: fprintf(fp, " NNTP host %s\n", CFG.nntpnode); + fprintf(fp, " NNTP mode reader %s\n", getboolean(CFG.modereader)); + fprintf(fp, " NNTP username %s\n", CFG.nntpuser); + fprintf(fp, " NNTP password %s\n", getboolean(strlen(CFG.nntppass))); + break; + case FEEDRNEWS: fprintf(fp, " Path to rnews %s\n", CFG.rnewspath); + break; + case FEEDUUCP: fprintf(fp, " NNTP host %s\n", CFG.nntpnode); + fprintf(fp, " Path to rnews %s\n", CFG.rnewspath); + break; + } + fprintf(fp, " Allow control msgs %s\n", getboolean(CFG.allowcontrol)); + fprintf(fp, " Don't regate msgs %s\n", getboolean(CFG.dontregate)); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 16, page, (char *)"Newfile reports"); + + fprintf(fp, " FTP base path %s\n", CFG.ftp_base); + fprintf(fp, " New files days %d\n", CFG.newdays); + fprintf(fp, " Highest sec. level %s\n", get_secstr(CFG.security)); + fprintf(fp, " Max. newfile grps %ld\n", CFG.new_groups); + + addtoc(fp, toc, 1, 17, page, (char *)"System fidonet addresses"); + for (i = 0; i < 40; i++) + if (CFG.akavalid[i]) + fprintf(fp, " Aka %2d %s\n", i+1, aka2str(CFG.aka[i])); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 18, page, (char *)"Mailer setup"); + + p = getloglevel(CFG.cico_loglevel); + fprintf(fp, " Mailer loglevel %s\n", p); + free(p); + fprintf(fp, " Res. modem timeout %ld\n", CFG.timeoutreset); + fprintf(fp, " Connect timeout %ld\n", CFG.timeoutconnect); + fprintf(fp, " Random dialdelay %ld\n", CFG.dialdelay); + fprintf(fp, " Default phone nr. %s\n", CFG.Phone); + fprintf(fp, " Default speed %lu\n", CFG.Speed); + fprintf(fp, " TCP/IP flags %s\n", CFG.Flags); + fprintf(fp, " No Filerequests %s\n", getboolean(CFG.NoFreqs)); + fprintf(fp, " No Calls %s\n", getboolean(CFG.NoCall)); + fprintf(fp, " No Hold %s\n", getboolean(CFG.NoHold)); + fprintf(fp, " No Pickup All %s\n", getboolean(CFG.NoPUA)); + fprintf(fp, " No EMSI %s\n", getboolean(CFG.NoEMSI)); + fprintf(fp, " No YooHoo/2U2 %s\n", getboolean(CFG.NoWazoo)); + fprintf(fp, " No Zmodem %s\n", getboolean(CFG.NoZmodem)); + fprintf(fp, " No Zedzap %s\n", getboolean(CFG.NoZedzap)); + fprintf(fp, " No Hydra %s\n", getboolean(CFG.NoHydra)); + fprintf(fp, " No TCP/IP %s\n", getboolean(CFG.NoTCP)); + fprintf(fp, " Max request files %d\n", CFG.Req_Files); + fprintf(fp, " Max request MBytes %d\n", CFG.Req_MBytes); + + for (i = 0; i < 40; i++) + if ((CFG.phonetrans[i].match[0] != '\0') || + (CFG.phonetrans[i].repl[0] != '\0')) + fprintf(fp, " Translate %-20s %s\n", CFG.phonetrans[i].match, CFG.phonetrans[i].repl); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 19, page, (char *)"FTP server setup"); + + fprintf(fp, " Connections limit %d\n", CFG.ftp_limit); + fprintf(fp, " Login fails %d\n", CFG.ftp_loginfails); + fprintf(fp, " Allow compress %s\n", getboolean(CFG.ftp_compress)); + fprintf(fp, " Allow tar %s\n", getboolean(CFG.ftp_tar)); + fprintf(fp, " Log commands %s\n", getboolean(CFG.ftp_log_cmds)); + fprintf(fp, " Anonymous login %s\n", getboolean(CFG.ftp_anonymousok)); + fprintf(fp, " User mbse login %s\n", getboolean(CFG.ftp_mbseok)); + fprintf(fp, " Base path %s\n", CFG.ftp_base); + fprintf(fp, " Shutdown message %s\n", CFG.ftp_msg_shutmsg); + fprintf(fp, " Upload path %s\n", CFG.ftp_upl_path); + fprintf(fp, " README login %s\n", CFG.ftp_readme_login); + fprintf(fp, " README cwd* %s\n", CFG.ftp_readme_cwd); + fprintf(fp, " Message login %s\n", CFG.ftp_msg_login); + fprintf(fp, " Message cwd* %s\n", CFG.ftp_msg_cwd); + fprintf(fp, " Login banner %s\n", CFG.ftp_banner); + fprintf(fp, " Email address %s\n", CFG.ftp_email); + fprintf(fp, " Path filter %s\n", CFG.ftp_pth_filter); + fprintf(fp, " Path message %s\n", CFG.ftp_pth_message); + + addtoc(fp, toc, 1, 20, page, (char *)"WWW server setup"); + + fprintf(fp, " HTML root %s\n", CFG.www_root); + fprintf(fp, " Link to FTP base %s\n", CFG.www_link2ftp); + fprintf(fp, " Webserver URL %s\n", CFG.www_url); + fprintf(fp, " Character set %s\n", CFG.www_charset); + fprintf(fp, " Table bgcolor %s\n", CFG.www_tbgcolor); + fprintf(fp, " Header bgcolor %s\n", CFG.www_hbgcolor); + fprintf(fp, " Author name %s\n", CFG.www_author); + fprintf(fp, " Convert command %s\n", CFG.www_convert); + fprintf(fp, " Icon Home %s\n", CFG.www_icon_home); + fprintf(fp, " String for Home %s\n", CFG.www_name_home); + fprintf(fp, " Icon Back %s\n", CFG.www_icon_back); + fprintf(fp, " String for Back %s\n", CFG.www_name_back); + fprintf(fp, " Icon Previous %s\n", CFG.www_icon_home); + fprintf(fp, " String for Prev. %s\n", CFG.www_name_home); + fprintf(fp, " Icon Next %s\n", CFG.www_icon_back); + fprintf(fp, " String for Next %s\n", CFG.www_name_back); + fprintf(fp, " File per webpage %d\n", CFG.www_files_page); + + return page; +} + + + diff --git a/mbsetup/m_global.h b/mbsetup/m_global.h new file mode 100644 index 00000000..c5028904 --- /dev/null +++ b/mbsetup/m_global.h @@ -0,0 +1,16 @@ +/* m_global.h */ + +#ifndef _GLOBAL_H +#define _GLOBAL_H + +void config_check(char *path); +int config_open(void); +void config_close(void); +int config_read(void); +int config_write(void); +void global_menu(void); +int PickAka(char *, int); +int global_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_hatch.c b/mbsetup/m_hatch.c new file mode 100644 index 00000000..ef990f1e --- /dev/null +++ b/mbsetup/m_hatch.c @@ -0,0 +1,625 @@ +/***************************************************************************** + * + * File ..................: m_hatch.c + * Purpose ...............: Hatch Setup + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_fgroup.h" +#include "m_ticarea.h" +#include "m_hatch.h" + + +int HatchUpdated = 0; +char *Days[] = {(char *)"Sun",(char *)"Mon",(char *)"Tue",(char *)"Wed", + (char *)"Thu",(char *)"Fri",(char *)"Sat"}; +char *Month[] = {(char *)"1", (char *)"2", (char *)"3", (char *)"4", + (char *)"5", (char *)"6", (char *)"7", (char *)"8", + (char *)"9", (char *)"10",(char *)"11",(char *)"12", + (char *)"13",(char *)"14",(char *)"15",(char *)"16", + (char *)"17",(char *)"18",(char *)"19",(char *)"20", + (char *)"21",(char *)"22",(char *)"23",(char *)"24", + (char *)"25",(char *)"26",(char *)"27",(char *)"28", + (char *)"29",(char *)"30",(char *)"31",(char *)"Last"}; + +/* + * Count nr of hatch records in the database. + * Creates the database if it doesn't exist. + */ +int CountHatch(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + hatchhdr.hdrsize = sizeof(hatchhdr); + hatchhdr.recsize = sizeof(hatch); + hatchhdr.lastupd = time(NULL); + fwrite(&hatchhdr, sizeof(hatchhdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&hatchhdr, sizeof(hatchhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - hatchhdr.hdrsize) / hatchhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenHatch(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + int FieldPatch = FALSE; + + sprintf(fnin, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/hatch.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&hatchhdr, sizeof(hatchhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = hatchhdr.recsize; + if (oldsize != sizeof(hatch)) { + HatchUpdated = 1; + if ((oldsize + 8) == sizeof(hatch)) { + FieldPatch = TRUE; + Syslog('?', "Hatch: performing FieldPatch"); + } + } else + HatchUpdated = 0; + hatchhdr.hdrsize = sizeof(hatchhdr); + hatchhdr.recsize = sizeof(hatch); + fwrite(&hatchhdr, sizeof(hatchhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&hatch, 0, sizeof(hatch)); + while (fread(&hatch, oldsize, 1, fin) == 1) { + if (FieldPatch) { + memmove(&hatch.Replace, &hatch.Name[13], oldsize-12); + memset(&hatch.Name[13], 0, 8); + } + fwrite(&hatch, sizeof(hatch), 1, fout); + memset(&hatch, 0, sizeof(hatch)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseHatch(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *hat = NULL, *tmp; + + sprintf(fin, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/hatch.temp", getenv("MBSE_ROOT")); + + if (HatchUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&hatchhdr, hatchhdr.hdrsize, 1, fi); + fwrite(&hatchhdr, hatchhdr.hdrsize, 1, fo); + + while (fread(&hatch, hatchhdr.recsize, 1, fi) == 1) + if (!hatch.Deleted) + fill_stlist(&hat, hatch.Spec, ftell(fi) - hatchhdr.recsize); + sort_stlist(&hat); + + for (tmp = hat; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&hatch, hatchhdr.recsize, 1, fi); + fwrite(&hatch, hatchhdr.recsize, 1, fo); + } + + tidy_stlist(&hat); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"hatch.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendHatch(void) +{ + FILE *fil; + char ffile[81]; + int i; + + sprintf(ffile, "%s/etc/hatch.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&hatch, 0, sizeof(hatch)); + /* + * Fill in default values + */ + hatch.DupeCheck = TRUE; + for (i = 0; i < 7; i++) + hatch.Days[i] = TRUE; + fwrite(&hatch, sizeof(hatch), 1, fil); + fclose(fil); + HatchUpdated = 1; + return 0; + } else + return -1; +} + + + +void HatchScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "10.3 EDIT HATCH MANAGER"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Mask"); + mvprintw( 8, 2, "2. Area"); + mvprintw( 9, 2, "3. Replace"); + mvprintw(10, 2, "4. Magic"); + mvprintw(11, 2, "5. Desc"); + mvprintw(12, 2, "6. Dupe"); + mvprintw(13, 2, "7. Active"); + mvprintw(14, 2, "8. Deleted"); + mvprintw(15, 2, "9. Days"); + mvprintw(16, 2, "10. Month"); +} + + + +void EditDates(void); +void EditDates(void) +{ + int i, x, y; + + clr_index(); + for (;;) { + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10.3.9 EDIT DATES IN MONTH"); + set_color(CYAN, BLACK); + y = 7; + x = 5; + for (i = 0; i < 32; i++) { + mvprintw(y, x, (char *)"%2d. %s", i+1, Month[i]); + y++; + if (y == 17) { + y = 7; + x += 20; + } + } + set_color(WHITE, BLACK); + y = 7; + x = 15; + for (i = 0; i < 32; i++) { + show_bool(y,x, hatch.Month[i]); + y++; + if (y == 17) { + y = 7; + x += 20; + } + } + + i = select_menu(32); + if (i == 0) + return; + if (i < 11) { + y = 6 + i; + x = 15; + } else if (i < 21) { + y = i - 4; + x = 35; + } else if (i < 31) { + y = i - 14; + x = 55; + } else { + y = i - 24; + x = 75; + } + if (i == 32) + hatch.Month[i-1] = edit_bool(y, x, hatch.Month[i-1], (char *)"Hatch file in the ^last^ day of the month"); + else + hatch.Month[i-1] = edit_bool(y, x, hatch.Month[i-1], (char *)"Hatch file on this date"); + } +} + + + +void EditDays(void); +void EditDays(void) +{ + int i; + + clr_index(); + for (;;) { + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10.3.8 EDIT DAYS IN WEEK"); + set_color(CYAN, BLACK); + for (i = 0; i < 7; i++) + mvprintw(7+i, 6, (char *)"%d. %s", i+1, Days[i]); + set_color(WHITE, BLACK); + for (i = 0; i < 7; i++) + show_bool(7+i,14, hatch.Days[i]); + + i = select_menu(7); + if (i == 0) + return; + hatch.Days[i-1] = edit_bool(6+i, 14, hatch.Days[i-1], (char *)"Hatch file on this day"); + } +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditHatchRec(int Area) +{ + FILE *fil; + char mfile[81]; + static char *tmp = NULL; + long offset; + unsigned long crc, crc1; + int i, All; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Hatch"); + + sprintf(mfile, "%s/etc/hatch.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&hatchhdr, sizeof(hatchhdr), 1, fil); + offset = hatchhdr.hdrsize + ((Area -1) * hatchhdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&hatch, hatchhdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&hatch, crc, hatchhdr.recsize); + working(0, 0, 0); + + for (;;) { + HatchScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,55, hatch.Spec); + show_str( 8,18,20, hatch.Name); + show_str( 9,18,14, hatch.Replace); + show_str( 10,18,14, hatch.Magic); + show_str( 11,18,55, hatch.Desc); + show_bool(12,18, hatch.DupeCheck); + show_bool(13,18, hatch.Active); + show_bool(14,18, hatch.Deleted); + + for (i = 0; i < 7; i++) + if (hatch.Days[i]) { + if (tmp == NULL) { + tmp = xstrcpy(Days[i]); + } else { + tmp = xstrcat(tmp, (char *)", "); + tmp = xstrcat(tmp, Days[i]); + } + } + if (tmp == NULL) + tmp = xstrcpy((char *)"None"); + show_str( 15,18,55, tmp); + if (tmp != NULL) { + free(tmp); + tmp = NULL; + } + All = TRUE; + for (i = 0; i < 32; i++) + if (!hatch.Month[i]) + All = FALSE; + if (!All) { + for (i = 0; i < 32; i++) + if (hatch.Month[i]) { + if (tmp == NULL) { + tmp = xstrcpy(Month[i]); + } else { + tmp = xstrcat(tmp, (char *)", "); + tmp = xstrcat(tmp, Month[i]); + } + } + } else + tmp = xstrcpy((char *)"All dates"); + if (tmp == NULL) + tmp = xstrcpy((char *)"None"); + show_str( 16,18,55, tmp); + if (tmp != NULL) { + free(tmp); + tmp = NULL; + } + + switch(select_menu(10)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&hatch, crc1, hatchhdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&hatch, hatchhdr.recsize, 1, fil); + fclose(fil); + HatchUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,55, hatch.Spec, "Hatch ^path/filespec^. ^?^ is any char, '@' is any alpha, '#' is any number") + case 2: strcpy(hatch.Name, PickTicarea((char *)"10.3.2")); + break; + case 3: E_UPS( 9,18,14, hatch.Replace, "The ^filename^ to replace by this file") + case 4: E_UPS( 10,18,14, hatch.Magic, "The ^magic^ filename for this file") + case 5: E_STR( 11,18,55, hatch.Desc, "The ^description^ for this file") + case 6: E_BOOL(12,18, hatch.DupeCheck, "Check if this files is a ^duplicate^ hatch") + case 7: E_BOOL(13,18, hatch.Active, "If this file is ^active^") + case 8: E_BOOL(14,18, hatch.Deleted, "If this record is ^Deleted^") + case 9: EditDays(); + break; + case 10:EditDates(); + break; + } + } +} + + + +void EditHatch(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountHatch(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenHatch() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "10.3. HATCH MANAGER"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/hatch.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&hatchhdr, sizeof(hatchhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(hatchhdr) + (((o + i) - 1) * hatchhdr.recsize); + fseek(fil, offset, 0); + fread(&hatch, hatchhdr.recsize, 1, fil); + if (hatch.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, hatch.Spec); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseHatch(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendHatch() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditHatchRec(atoi(pick)); + } +} + + + +int tic_hatch_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81], *tmp = NULL; + FILE *no; + int i, j, All; + + sprintf(temp, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 10, 3, page, (char *)"Hatch manager"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&hatchhdr, sizeof(hatchhdr), 1, no); + + while ((fread(&hatch, hatchhdr.recsize, 1, no)) == 1) { + + if (j == 5) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " File spec %s\n", hatch.Spec); + fprintf(fp, " File echo %s\n", hatch.Name); + fprintf(fp, " Replace file %s\n", hatch.Replace); + fprintf(fp, " Magic filename %s\n", hatch.Magic); + fprintf(fp, " Description %s\n", hatch.Desc); + fprintf(fp, " Dupe check %s\n", getboolean(hatch.DupeCheck)); + fprintf(fp, " Active %s\n", getboolean(hatch.Active)); + tmp = NULL; + for (i = 0; i < 7; i++) + if (hatch.Days[i]) { + if (tmp == NULL) { + tmp = xstrcpy(Days[i]); + } else { + tmp = xstrcat(tmp, (char *)", "); + tmp = xstrcat(tmp, Days[i]); + } + } + if (tmp == NULL) + tmp = xstrcpy((char *)"None"); + fprintf(fp, " Hatch on days %s\n", tmp); + if (tmp != NULL) { + free(tmp); + tmp = NULL; + } + All = TRUE; + for (i = 0; i < 32; i++) + if (!hatch.Month[i]) + All = FALSE; + if (!All) { + for (i = 0; i < 32; i++) + if (hatch.Month[i]) { + if (tmp == NULL) { + tmp = xstrcpy(Month[i]); + } else { + tmp = xstrcat(tmp, (char *)", "); + tmp = xstrcat(tmp, Month[i]); + } + } + } else + tmp = xstrcpy((char *)"All dates"); + if (tmp == NULL) + tmp = xstrcpy((char *)"None"); + fprintf(fp, " Hatch on dates %s\n", tmp); + if (tmp != NULL) { + free(tmp); + tmp = NULL; + } + fprintf(fp, "\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_hatch.h b/mbsetup/m_hatch.h new file mode 100644 index 00000000..aa0f35f8 --- /dev/null +++ b/mbsetup/m_hatch.h @@ -0,0 +1,10 @@ +#ifndef _HATCH_H +#define _HATCH_H + + +int CountHatch(void); +void EditHatch(void); +int tic_hatch_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_lang.c b/mbsetup/m_lang.c new file mode 100644 index 00000000..23025572 --- /dev/null +++ b/mbsetup/m_lang.c @@ -0,0 +1,527 @@ +/***************************************************************************** + * + * File ..................: setup/m_language.c + * Purpose ...............: Setup Languages. + * Last modification date : 25-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_lang.h" + + + +int LangUpdated = 0; + + +/* + * Count nr of lang records in the database. + * Creates the database if it doesn't exist. + */ +int CountLanguage(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/language.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + langhdr.hdrsize = sizeof(langhdr); + langhdr.recsize = sizeof(lang); + fwrite(&langhdr, sizeof(langhdr), 1, fil); + + /* + * Setup default records + */ + memset(&lang, 0, sizeof(lang)); + sprintf(lang.Name, "English"); + sprintf(lang.LangKey, "E"); + sprintf(lang.MenuPath, "%s/english/menus", getenv("MBSE_ROOT")); + sprintf(lang.TextPath, "%s/english/txtfiles", getenv("MBSE_ROOT")); + sprintf(lang.MacroPath, "%s/english/macro", getenv("MBSE_ROOT")); + sprintf(lang.Filename, "english.lang"); + lang.Available = TRUE; + fwrite(&lang, sizeof(lang), 1, fil); + + memset(&lang, 0, sizeof(lang)); + sprintf(lang.Name, "Nederlands"); + sprintf(lang.LangKey, "N"); + sprintf(lang.MenuPath, "%s/dutch/menus", getenv("MBSE_ROOT")); + sprintf(lang.TextPath, "%s/dutch/txtfiles", getenv("MBSE_ROOT")); + sprintf(lang.MacroPath, "%s/dutch/macro", getenv("MBSE_ROOT")); + sprintf(lang.Filename, "dutch.lang"); + lang.Available = TRUE; + fwrite(&lang, sizeof(lang), 1, fil); + + memset(&lang, 0, sizeof(lang)); + sprintf(lang.Name, "Italian"); + sprintf(lang.LangKey, "I"); + sprintf(lang.MenuPath, "%s/italian/menus", getenv("MBSE_ROOT")); + sprintf(lang.TextPath, "%s/italian/txtfiles", getenv("MBSE_ROOT")); + sprintf(lang.MacroPath, "%s/italian/macro", getenv("MBSE_ROOT")); + sprintf(lang.Filename, "italian.lang"); + lang.Available = TRUE; + fwrite(&lang, sizeof(lang), 1, fil); + + memset(&lang, 0, sizeof(lang)); + sprintf(lang.Name, "Spanish"); + sprintf(lang.LangKey, "S"); + sprintf(lang.MenuPath, "%s/spanish/menus", getenv("MBSE_ROOT")); + sprintf(lang.TextPath, "%s/spanish/txtfiles", getenv("MBSE_ROOT")); + sprintf(lang.MacroPath, "%s/spanish/macro", getenv("MBSE_ROOT")); + sprintf(lang.Filename, "spanish.lang"); + lang.Available = TRUE; + fwrite(&lang, sizeof(lang), 1, fil); + + fclose(fil); + return 2; + } else + return -1; + } + + fread(&langhdr, sizeof(langhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - langhdr.hdrsize) / langhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenLanguage(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/language.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/language.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&langhdr, sizeof(langhdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = langhdr.recsize; + if (oldsize != sizeof(lang)) + LangUpdated = 1; + else + LangUpdated = 0; + langhdr.hdrsize = sizeof(langhdr); + langhdr.recsize = sizeof(lang); + fwrite(&langhdr, sizeof(langhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&lang, 0, sizeof(lang)); + while (fread(&lang, oldsize, 1, fin) == 1) { + fwrite(&lang, sizeof(lang), 1, fout); + memset(&lang, 0, sizeof(lang)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseLanguage(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *lan = NULL, *tmp; + + sprintf(fin, "%s/etc/language.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/language.temp", getenv("MBSE_ROOT")); + + if (LangUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&langhdr, langhdr.hdrsize, 1, fi); + fwrite(&langhdr, langhdr.hdrsize, 1, fo); + + while (fread(&lang, langhdr.recsize, 1, fi) == 1) + if (!lang.Deleted) + fill_stlist(&lan, lang.LangKey , ftell(fi) - langhdr.recsize); + sort_stlist(&lan); + + for (tmp = lan; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&lang, langhdr.recsize, 1, fi); + fwrite(&lang, langhdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + unlink(fout); + tidy_stlist(&lan); + Syslog('+', "Updated \"language.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendLanguage(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/language.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&lang, 0, sizeof(lang)); + fwrite(&lang, sizeof(lang), 1, fil); + fclose(fil); + LangUpdated = 1; + return 0; + } else + return -1; +} + + + +void s_lang(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "8.2 EDIT LANGUAGE"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Select"); + mvprintw( 8, 2, "2. Name"); + mvprintw( 9, 2, "3. Menupath"); + mvprintw(10, 2, "4. Textpath"); + mvprintw(11, 2, "5. Macropath"); + mvprintw(12, 2, "6. Available"); + mvprintw(13, 2, "7. Datafile"); + mvprintw(14, 2, "8. Security"); + mvprintw(15, 2, "9. Deleted"); +} + + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditLangRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Language"); + + sprintf(mfile, "%s/etc/language.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(langhdr) + ((Area -1) * sizeof(lang)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&lang, sizeof(lang), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&lang, crc, sizeof(lang)); + working(0, 0, 0); + + s_lang(); + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16, 1, lang.LangKey); + show_str( 8,16,30, lang.Name); + show_str( 9,16,64, lang.MenuPath); + show_str( 10,16,64, lang.TextPath); + show_str( 11,16,64, lang.MacroPath); + show_bool(12,16, lang.Available); + show_str( 13,16,24, lang.Filename); + show_sec( 14,16, lang.Security); + show_bool(15,16, lang.Deleted); + + j = select_menu(9); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&lang, crc1, sizeof(lang)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&lang, sizeof(lang), 1, fil); + fclose(fil); + LangUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_UPS( 7,16,1, lang.LangKey, "The ^Key^ to select this language") + case 2: E_STR( 8,16,30,lang.Name, "The ^name^ of this language") + case 3: E_PTH( 9,16,64,lang.MenuPath, "The ^Menus Path^ of this language") + case 4: E_PTH( 10,16,64,lang.TextPath, "The ^Textfile path^ of this language") + case 5: E_PTH( 11,16,64,lang.MacroPath,"The ^Macro template path^ if this language") + case 6: E_BOOL(12,16, lang.Available,"Is this language ^available^") + case 7: E_STR( 13,16,24,lang.Filename, "The ^Filename^ (without path) of the language datafile") + case 8: E_SEC( 14,16, lang.Security, "8.2. LANGUAGE SECURITY", s_lang) + case 9: E_BOOL(15,16, lang.Deleted, "Is this language record ^Deleted^") + } + } + + return 0; +} + + + +void EditLanguage(void) +{ + int records, i, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountLanguage(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenLanguage() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.2 LANGUAGE SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/language.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&langhdr, sizeof(langhdr), 1, fil); + x = 4; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(langhdr) + ((i - 1) * langhdr.recsize); + fseek(fil, offset, 0); + fread(&lang, langhdr.recsize, 1, fil); + if (i == 11) + x = 44; + if (lang.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %-30s", i, lang.LangKey, lang.Name); + mvprintw(i + 6, x, temp); + } + fclose(fil); + } + /* Show records here */ + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseLanguage(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendLanguage() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditLangRec(atoi(pick)); + } +} + + + +int PickLanguage(char *nr) +{ + int Lang = '\0'; + int records, i, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return Lang; + } + + records = CountLanguage(); + if (records == -1) { + working(2, 0, 0); + return Lang; + } + + working(0, 0, 0); + + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. LANGUAGE SELECT", nr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&langhdr, sizeof(langhdr), 1, fil); + x = 2; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(langhdr) + ((i - 1) * langhdr.recsize); + fseek(fil, offset, 0); + fread(&lang, langhdr.recsize, 1, fil); + if (i == 11) + x = 42; + if (lang.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %-28s", i, lang.LangKey, lang.Name); + mvprintw(i + 6, x, temp); + } + strcpy(pick, select_pick(records, 20)); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = sizeof(langhdr) + ((atoi(pick) - 1) * langhdr.recsize); + fseek(fil, offset, 0); + fread(&lang, langhdr.recsize, 1, fil); + Lang = lang.LangKey[0]; + } + fclose(fil); + } + } + return Lang; +} + + + +int bbs_lang_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 8, 2, page, (char *)"BBS Language setup"); + j = 0; + fprintf(fp, "\n\n"); + fread(&langhdr, sizeof(langhdr), 1, no); + + while ((fread(&lang, langhdr.recsize, 1, no)) == 1) { + + if (j == 5) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Language key %s\n", lang.LangKey); + fprintf(fp, " Language name %s\n", lang.Name); + fprintf(fp, " Available %s\n", getboolean(lang.Available)); + fprintf(fp, " Menu path %s\n", lang.MenuPath); + fprintf(fp, " Textfiles path %s\n", lang.TextPath); + fprintf(fp, " Macrofiles path %s\n", lang.MacroPath); + fprintf(fp, " Language file %s\n", lang.Filename); + fprintf(fp, " Security level %s\n", get_secstr(lang.Security)); + fprintf(fp, "\n\n"); + j++; + } + + fclose(no); + return page; +} + + + diff --git a/mbsetup/m_lang.h b/mbsetup/m_lang.h new file mode 100644 index 00000000..64654c33 --- /dev/null +++ b/mbsetup/m_lang.h @@ -0,0 +1,12 @@ +#ifndef _LANG_H +#define _LANG_H + + +int CountLanguage(void); +void EditLanguage(void); +int PickLanguage(char *); +int bbs_lang_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_limits.c b/mbsetup/m_limits.c new file mode 100644 index 00000000..090a688c --- /dev/null +++ b/mbsetup/m_limits.c @@ -0,0 +1,593 @@ +/***************************************************************************** + * + * File ..................: setup/m_limits.c + * Purpose ...............: Setup Limits. + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_limits.h" + + + +int LimUpdated = 0; + + +/* + * Count nr of LIMIT records in the database. + * Creates the database if it doesn't exist. + */ +int CountLimits(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/limits.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + LIMIThdr.hdrsize = sizeof(LIMIThdr); + LIMIThdr.recsize = sizeof(LIMIT); + fwrite(&LIMIThdr, sizeof(LIMIThdr), 1, fil); + + /* + * Create default limits + */ + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 0; + LIMIT.Time = 5; + LIMIT.DownK = 1; + LIMIT.DownF = 1; + sprintf(LIMIT.Description, "Twit"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 5; + LIMIT.Time = 15; + LIMIT.DownK = 100; + LIMIT.DownF = 2; + sprintf(LIMIT.Description, "New User"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 20; + LIMIT.Time = 60; + LIMIT.DownK = 10240; + LIMIT.DownF = 25; + sprintf(LIMIT.Description, "Normal User"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 50; + LIMIT.Time = 90; + LIMIT.DownK = 20480; + LIMIT.DownF = 100; + sprintf(LIMIT.Description, "V.I.P. User"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 80; + LIMIT.Time = 120; + LIMIT.DownK = 40960; + sprintf(LIMIT.Description, "Fellow Sysop or Point"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 100; + LIMIT.Time = 180; + LIMIT.DownK = 40960; + sprintf(LIMIT.Description, "Co-Sysop"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 32000; + LIMIT.Time = 240; + LIMIT.DownK = 40960; + sprintf(LIMIT.Description, "Sysop"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + fclose(fil); + return 7; + } else + return -1; + } + + fread(&LIMIThdr, sizeof(LIMIThdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - LIMIThdr.hdrsize) / LIMIThdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenLimits(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/limits.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/limits.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&LIMIThdr, sizeof(LIMIThdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = LIMIThdr.recsize; + if (oldsize != sizeof(LIMIT)) + LimUpdated = 1; + else + LimUpdated = 0; + LIMIThdr.hdrsize = sizeof(LIMIThdr); + LIMIThdr.recsize = sizeof(LIMIT); + fwrite(&LIMIThdr, sizeof(LIMIThdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&LIMIT, 0, sizeof(LIMIT)); + while (fread(&LIMIT, oldsize, 1, fin) == 1) { + fwrite(&LIMIT, sizeof(LIMIT), 1, fout); + memset(&LIMIT, 0, sizeof(LIMIT)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseLimits(void) +{ + char fin[81], fout[81], temp[20]; + FILE *fi, *fo; + st_list *lim = NULL, *tmp; + + sprintf(fin, "%s/etc/limits.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/limits.temp", getenv("MBSE_ROOT")); + + if (LimUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&LIMIThdr, LIMIThdr.hdrsize, 1, fi); + fwrite(&LIMIThdr, LIMIThdr.hdrsize, 1, fo); + + while (fread(&LIMIT, LIMIThdr.recsize, 1, fi) == 1) + if (!LIMIT.Deleted) { + sprintf(temp, "%014ld", LIMIT.Security); + fill_stlist(&lim, temp, ftell(fi) - LIMIThdr.recsize); + } + sort_stlist(&lim); + + for (tmp = lim; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&LIMIT, LIMIThdr.recsize, 1, fi); + fwrite(&LIMIT, LIMIThdr.recsize, 1, fo); + } + + tidy_stlist(&lim); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"limits.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendLimits(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/limits.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&LIMIT, 0, sizeof(LIMIT)); + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + fclose(fil); + LimUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditLimRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Limits"); + + sprintf(mfile, "%s/etc/limits.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(LIMIThdr) + ((Area -1) * sizeof(LIMIT)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&LIMIT, sizeof(LIMIT), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&LIMIT, crc, sizeof(LIMIT)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.1 EDIT SECURITY LIMIT"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Access Level"); + mvprintw( 8, 6, "2. Maximum Time"); + mvprintw( 9, 6, "3. Download Kb."); + mvprintw(10, 6, "4. Download Files"); + mvprintw(11, 6, "5. Description"); + mvprintw(12, 6, "6. Available"); + mvprintw(13, 6, "7. Deleted"); + + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,25, LIMIT.Security); + show_int( 8,25, LIMIT.Time); + show_int( 9,25, LIMIT.DownK); + show_int(10,25, LIMIT.DownF); + show_str(11,25,40, LIMIT.Description); + show_bool(12,25, LIMIT.Available); + show_bool(13,25, LIMIT.Deleted); + + j = select_menu(7); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&LIMIT, crc1, sizeof(LIMIT)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + fclose(fil); + LimUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_INT( 7,25, LIMIT.Security, "The ^Security^ level for this limit") + case 2: E_INT( 8,25, LIMIT.Time, "The maxmimum ^Time online^ per day for this limit") + case 3: E_INT( 9,25, LIMIT.DownK, "The ^Kilobytes^ download limit per day, 0 = don't care") + case 4: E_INT( 10,25, LIMIT.DownF, "The ^nr of files^ to download per day, 0 = don't care") + case 5: E_STR( 11,25,40,LIMIT.Description,"A short ^description^ for this limit") + case 6: E_BOOL(12,25, LIMIT.Available, "Is this record ^avaiable^") + case 7: E_BOOL(13,25, LIMIT.Deleted, "Is this level ^Deleted^") + } + } + + return 0; +} + + + +void EditLimits(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountLimits(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenLimits() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 7, "8.1 LIMITS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/limits.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&LIMIThdr, sizeof(LIMIThdr), 1, fil); + x = 5; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(LIMIThdr) + ((i - 1) * LIMIThdr.recsize); + fseek(fil, offset, 0); + fread(&LIMIT, LIMIThdr.recsize, 1, fil); + if (i == 11) { + x = 45; + y = 7; + } + if (LIMIT.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-6ld %-40s", i, LIMIT.Security, LIMIT.Description); + temp[37] = '\0'; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseLimits(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendLimits() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditLimRec(atoi(pick)); + } +} + + + +char *PickLimits(int nr) +{ + static char Lim[21] = ""; + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return Lim; + } + + records = CountLimits(); + if (records == -1) { + working(2, 0, 0); + return Lim; + } + + working(0, 0, 0); + + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%d. LIMITS SELECT", nr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/limits.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&LIMIThdr, sizeof(LIMIThdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(LIMIThdr) + ((i - 1) * LIMIThdr.recsize); + fseek(fil, offset, 0); + fread(&LIMIT, LIMIThdr.recsize, 1, fil); + if (i == 11) { + x = 42; + y = 7; + } + if (LIMIT.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-6ld %-40s", i, LIMIT.Security, LIMIT.Description); + temp[37] = '\0'; + mvprintw(y, x, temp); + y++; + } + strcpy(pick, select_pick(records, 20)); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = sizeof(LIMIThdr) + ((atoi(pick) - 1) * LIMIThdr.recsize); + fseek(fil, offset, 0); + fread(&LIMIT, LIMIThdr.recsize, 1, fil); + sprintf(Lim, "%ld", LIMIT.Security); + } + fclose(fil); + } + } + return Lim; +} + + + +int bbs_limits_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + + sprintf(temp, "%s/etc/limits.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + addtoc(fp, toc, 8, 1, page, (char *)"BBS user limits"); + + fread(&LIMIThdr, sizeof(LIMIThdr), 1, no); + + fprintf(fp, "\n"); + fprintf(fp, " Access Max. Down Down\n"); + fprintf(fp, " Level time Kb. files Active Description\n"); + fprintf(fp, " ------ ------ ------ ------ ------ ------------------------------\n"); + + while ((fread(&LIMIT, LIMIThdr.recsize, 1, no)) == 1) { + fprintf(fp, " %6ld %6ld %6ld %6d %s %s\n", LIMIT.Security, LIMIT.Time, LIMIT.DownK, + LIMIT.DownF, getboolean(LIMIT.Available), LIMIT.Description); + } + + fclose(no); + return page; +} + + + +int limit_users_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no, *us; + int line = 0, j; + + sprintf(temp, "%s/etc/limits.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((us = fopen(temp, "r")) == NULL) { + fclose(no); + return page; + } + + page = newpage(fp, page); + addtoc(fp, toc, 1, 0, page, (char *)"Access limits and users"); + + fread(&LIMIThdr, sizeof(LIMIThdr), 1, no); + fread(&usrconfighdr, sizeof(usrconfighdr), 1, us); + + while (fread(&LIMIT, LIMIThdr.recsize, 1, no) == 1) { + if (LIMIT.Available) { + if (line > 52) { + page = newpage(fp, page); + line = 0; + } + fprintf(fp, "\n\n"); + fprintf(fp, " Level %ld - %s\n\n", LIMIT.Security, LIMIT.Description); + line += 4; + j = 2; + fseek(us, usrconfighdr.hdrsize, SEEK_SET); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, us) == 1) { + if ((!usrconfig.Deleted) && strlen(usrconfig.sUserName) && + (usrconfig.Security.level == LIMIT.Security)) { + if (j == 2) { + j = 0; + fprintf(fp, " %-35s", usrconfig.sUserName); + } else { + fprintf(fp, " %s\n", usrconfig.sUserName); + line++; + if (line > 56) { + page = newpage(fp, page); + line = 0; + } + } + j++; + } + } + if (j != 2) + fprintf(fp, "\n"); + } + } + + fclose(us); + fclose(no); + return page; +} + + diff --git a/mbsetup/m_limits.h b/mbsetup/m_limits.h new file mode 100644 index 00000000..ddd54c5b --- /dev/null +++ b/mbsetup/m_limits.h @@ -0,0 +1,13 @@ +#ifndef _LIMITSS_H +#define _LIMITSS_H + + +int CountLimits(void); +void EditLimits(void); +char *PickLimits(int); +int bbs_limits_doc(FILE *, FILE *, int); +int limit_users_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_magic.c b/mbsetup/m_magic.c new file mode 100644 index 00000000..f5df63a8 --- /dev/null +++ b/mbsetup/m_magic.c @@ -0,0 +1,537 @@ +/***************************************************************************** + * + * File ..................: setup/m_magic.c + * Purpose ...............: Edit Magics + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_ticarea.h" +#include "m_global.h" +#include "m_magic.h" + + + +int MagicUpdated = 0; + + +/* + * Count nr of magic records in the database. + * Creates the database if it doesn't exist. + */ +int CountMagics(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/magic.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + magichdr.hdrsize = sizeof(magichdr); + magichdr.recsize = sizeof(magic); + fwrite(&magichdr, sizeof(magichdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&magichdr, sizeof(magichdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - magichdr.hdrsize) / magichdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenMagics(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + int FieldPatch = FALSE; + + sprintf(fnin, "%s/etc/magic.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/magic.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&magichdr, sizeof(magichdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = magichdr.recsize; + if (oldsize != sizeof(magic)) { + MagicUpdated = 1; + if ((oldsize + 16) == sizeof(magic)) { + FieldPatch = TRUE; + Syslog('?', "Magic: performing FieldPatch"); + } + } else + MagicUpdated = 0; + magichdr.hdrsize = sizeof(magichdr); + magichdr.recsize = sizeof(magic); + fwrite(&magichdr, sizeof(magichdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&magic, 0, sizeof(magic)); + while (fread(&magic, oldsize, 1, fin) == 1) { + if (FieldPatch) { + memmove(&magic.Path, &magic.From[13], oldsize-12); + memset(&magic.From[13], 0, 8); + } + fwrite(&magic, sizeof(magic), 1, fout); + memset(&magic, 0, sizeof(magic)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseMagics(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *mag = NULL, *tmp; + + sprintf(fin, "%s/etc/magic.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/magic.temp", getenv("MBSE_ROOT")); + + if (MagicUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&magichdr, magichdr.hdrsize, 1, fi); + fwrite(&magichdr, magichdr.hdrsize, 1, fo); + + while (fread(&magic, magichdr.recsize, 1, fi) == 1) + if (!magic.Deleted) + fill_stlist(&mag, magic.Mask, ftell(fi) - magichdr.recsize); + sort_stlist(&mag); + + for (tmp = mag; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&magic, magichdr.recsize, 1, fi); + fwrite(&magic, magichdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + tidy_stlist(&mag); + unlink(fout); + Syslog('+', "Updated \"magic.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendMagics(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/magic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&magic, 0, sizeof(magic)); + fwrite(&magic, sizeof(magic), 1, fil); + fclose(fil); + MagicUpdated = 1; + return 0; + } else + return -1; +} + + + +void ScreenM(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "10.4. EDIT MAGIC"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Magic"); + mvprintw( 8, 2, "2. Filemask"); + mvprintw( 9, 2, "3. Active"); + mvprintw(10, 2, "4. Deleted"); + mvprintw(11, 2, "5. Area"); + + switch(magic.Attrib) { + case MG_ADOPT: + case MG_MOVE: + mvprintw(12, 2, "6. To Area"); + break; + + case MG_EXEC: + mvprintw(12, 2, "6. Command"); + mvprintw(13, 2, "7. Compile"); + break; + + case MG_COPY: + case MG_OTHER: + case MG_UNPACK: + mvprintw(12, 2, "6. To path"); + if (magic.Attrib != MG_OTHER) + mvprintw(13, 2, "7. Compile"); + break; + + case MG_KEEPNUM: + mvprintw(12, 2, "6. Keep Num"); + break; + } +} + + + +void FieldsM(void) +{ + set_color(WHITE, BLACK); + show_str( 7,16,20, getmagictype(magic.Attrib)); + show_str( 8,16,14, magic.Mask); + show_str( 9,16, 3, getboolean(magic.Active)); + show_str(10,16, 3, getboolean(magic.Deleted)); + show_str(11,16,20, magic.From); + + switch(magic.Attrib) { + case MG_ADOPT: + case MG_MOVE: + show_str(12,16,20, magic.ToArea); + break; + case MG_EXEC: + show_str(12,16,64, magic.Cmd); + show_bool(13,16, magic.Compile); + break; + case MG_UNPACK: + case MG_COPY: + show_bool(13,16, magic.Compile); + case MG_OTHER: + show_str(12,16,64, magic.Path); + break; + case MG_KEEPNUM: + show_int(12,16, magic.KeepNum); + break; + } +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditMagicRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j, choices; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Magics"); + + sprintf(mfile, "%s/etc/magic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(magichdr) + ((Area -1) * sizeof(magic)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&magic, sizeof(magic), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&magic, crc, sizeof(magic)); + working(0, 0, 0); + + for (;;) { + ScreenM(); + FieldsM(); + + switch(magic.Attrib) { + case MG_UPDALIAS: + case MG_DELETE: + choices = 5; + break; + case MG_EXEC: + case MG_COPY: + case MG_UNPACK: + choices = 7; + break; + default: + choices = 6; + } + + j = select_menu(choices); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&magic, crc1, sizeof(magic)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&magic, sizeof(magic), 1, fil); + fclose(fil); + MagicUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: magic.Attrib = edit_magictype(7,16, magic.Attrib); + break; + + case 2: E_STR( 8,16,14, magic.Mask, "File ^mask^ to test for this magic") + case 3: E_BOOL( 9,16, magic.Active, "Is this magic ^active^") + case 4: E_BOOL(10,16, magic.Deleted,"Is this record ^deleted^") + case 5: strcpy(magic.From, PickTicarea((char *)"10.4.5")); + break; + case 6: switch(magic.Attrib) { + case MG_ADOPT: + case MG_MOVE: + strcpy(magic.ToArea, PickTicarea((char *)"10.4.6")); + break; + + case MG_COPY: + case MG_OTHER: + case MG_UNPACK: + E_PTH(12,16,64, magic.Path, "The ^path^ to use") + + case MG_EXEC: + E_STR(12,16,64, magic.Cmd, "The ^command^ to execute") + + case MG_KEEPNUM: + E_INT(12,16, magic.KeepNum,"The number of files to ^keep^") + } + break; + + case 7: E_BOOL(13,16, magic.Compile, "Trigger the ^compile nodelist^ flag") + } + } + return 0; +} + + + +void EditMagics(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountMagics(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenMagics() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "10.4. MAGICS EDITOR"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/magic.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&magichdr, sizeof(magichdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(magichdr) + (((i + o) - 1) * magichdr.recsize); + fseek(fil, offset, 0); + fread(&magic, magichdr.recsize, 1, fil); + if (magic.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %s", o + i, getmagictype(magic.Attrib), magic.Mask); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseMagics(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendMagics() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditMagicRec(atoi(pick)); + } +} + + + +int tic_magic_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/magic.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 10, 4, page, (char *)"File Magic processing"); + j = 0; + fprintf(fp, "\n\n"); + + fread(&magichdr, sizeof(magichdr), 1, no); + while (fread(&magic, magichdr.recsize, 1, no) == 1) { + if (j == 4) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Filemask %s\n", magic.Mask); + fprintf(fp, " Type %s\n", getmagictype(magic.Attrib)); + fprintf(fp, " Active %s\n", getboolean(magic.Active)); + fprintf(fp, " Area %s\n", magic.From); + + switch (magic.Attrib) { + case MG_ADOPT: + case MG_MOVE: + fprintf(fp, " To area %s\n", magic.ToArea); + break; + + case MG_EXEC: + fprintf(fp, " Command %s\n", magic.Cmd); + fprintf(fp, " Compile NL %s\n", getboolean(magic.Compile)); + break; + + case MG_UNPACK: + case MG_COPY: + fprintf(fp, " Compile NL %s\n", getboolean(magic.Compile)); + case MG_OTHER: + fprintf(fp, " Path %s\n", magic.Path); + break; + + case MG_KEEPNUM:fprintf(fp, " Keep # file %d\n", magic.KeepNum); + break; + } + + fprintf(fp, "\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_magic.h b/mbsetup/m_magic.h new file mode 100644 index 00000000..fa8fe150 --- /dev/null +++ b/mbsetup/m_magic.h @@ -0,0 +1,11 @@ +#ifndef _MAGIC_H +#define _MAGIC_H + + +int CountMagics(void); +void EditMagics(void); +int tic_magic_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_mail.c b/mbsetup/m_mail.c new file mode 100644 index 00000000..ce5109ac --- /dev/null +++ b/mbsetup/m_mail.c @@ -0,0 +1,91 @@ +/***************************************************************************** + * + * File ..................: m_mail.c + * Purpose ...............: Mail Setup Program + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_marea.h" +#include "m_mgroup.h" +#include "m_mail.h" + + + + +void mail_menu(void) +{ + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "9. MAIL PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Echomail Groups"); + mvprintw( 8, 6, "2. Edit Echomail Areas"); + + switch(select_menu(2)) { + case 0: + return; + case 1: + EditMGroup(); + break; + case 2: + EditMsgarea(); + break; + } + } +} + + + +int mail_doc(FILE *fp, FILE *toc, int page) +{ + page = newpage(fp, page); + addtoc(fp, toc, 9, 0, page, (char *)"Mail setup"); + + page = mail_group_doc(fp, toc, page); + page = mail_area_doc(fp, toc, page); + + return page; +} + + diff --git a/mbsetup/m_mail.h b/mbsetup/m_mail.h new file mode 100644 index 00000000..c5eae97c --- /dev/null +++ b/mbsetup/m_mail.h @@ -0,0 +1,12 @@ +#ifndef _MAIL_H +#define _MAIL_H + + +int CountMsgarea(void); +void EditMsgarea(void); +void mail_menu(void); +int mail_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_marea.c b/mbsetup/m_marea.c new file mode 100644 index 00000000..863a293a --- /dev/null +++ b/mbsetup/m_marea.c @@ -0,0 +1,1469 @@ +/***************************************************************************** + * + * File ..................: m_mail.c + * Purpose ...............: Mail Setup Program + * Last modification date : 22-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "grlist.h" +#include "m_global.h" +#include "m_node.h" +#include "m_mgroup.h" +#include "m_marea.h" + + +int MsgUpdated = 0; +unsigned long MsgCrc; +FILE *tfil = NULL; + + + +/* + * Count nr of msgs records in the database. + * Creates the database if it doesn't exist. + */ +int CountMsgarea(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + Syslog('+', "Created mareas.data"); + msgshdr.hdrsize = sizeof(msgshdr); + msgshdr.recsize = sizeof(msgs); + msgshdr.syssize = CFG.toss_systems * sizeof(sysconnect); + msgshdr.lastupd = time(NULL); + fwrite(&msgshdr, sizeof(msgshdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - msgshdr.hdrsize) / (msgshdr.recsize + msgshdr.syssize); + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenMsgarea(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize, oldsys; + struct _sysconnect syscon; + int i, oldsystems; + + sprintf(fnin, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + Syslog('+', "Opened \"mareas.data\""); + MsgUpdated = 0; + fread(&msgshdr, sizeof(msgshdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, fin); + if (msgshdr.hdrsize != sizeof(msgshdr)) { + msgshdr.hdrsize = sizeof(msgshdr); + msgshdr.lastupd = time(NULL); + MsgUpdated = 1; + } + + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = msgshdr.recsize; + oldsys = msgshdr.syssize; + oldsystems = oldsys / sizeof(syscon); + if ((oldsize != sizeof(msgs)) || (CFG.toss_systems != oldsystems)) { + MsgUpdated = 1; + Syslog('+', "\"mareas.data\" nr of systems is changed"); + } + msgshdr.hdrsize = sizeof(msgshdr); + msgshdr.recsize = sizeof(msgs); + msgshdr.syssize = sizeof(syscon) * CFG.toss_systems; + fwrite(&msgshdr, sizeof(msgshdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&msgs, 0, sizeof(msgs)); + while (fread(&msgs, oldsize, 1, fin) == 1) { + if ((oldsize != sizeof(msgs)) && !msgs.Rfccode) { + msgs.Rfccode = CHRS_DEFAULT_RFC; + msgs.Ftncode = CHRS_DEFAULT_FTN; + } + fwrite(&msgs, sizeof(msgs), 1, fout); + memset(&msgs, 0, sizeof(msgs)); + /* + * Copy the existing connections + */ + for (i = 1; i <= oldsystems; i++) { + fread(&syscon, sizeof(syscon), 1, fin); + /* + * Write only valid records + */ + if (i <= CFG.toss_systems) + fwrite(&syscon, sizeof(syscon), 1, fout); + } + if (oldsystems < CFG.toss_systems) { + /* + * The size is increased, fill with + * blank records. + */ + memset(&syscon, 0, sizeof(syscon)); + for (i = (oldsystems + 1); i <= CFG.toss_systems; i++) + fwrite(&syscon, sizeof(syscon), 1, fout); + } + } + + fclose(fin); + fclose(fout); + Syslog('+', "Opended \"mareas.data\""); + if (MsgUpdated) + Syslog('+', "Updated \"mareas.data\" data format"); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseMsgarea(int Force) +{ + char fin[81], fout[81]; + + sprintf(fin, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/mareas.temp", getenv("MBSE_ROOT")); + + if (MsgUpdated == 1) { + if (Force || (yes_no((char *)"Messages database is changed, save changes") == 1)) { + working(1, 0, 0); + if ((rename(fout, fin)) == 0) + unlink(fout); + Syslog('+', "Updated \"mareas.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); + Syslog('+', "No update of \"mareas.data\""); +} + + + +void InitMsgRec(void); +void InitMsgRec(void) +{ + memset(&msgs, 0, sizeof(msgs)); + /* + * Fill in default values + */ + msgs.DaysOld = CFG.defdays; + msgs.MaxMsgs = CFG.defmsgs; + msgs.Type = ECHOMAIL; + msgs.MsgKinds = PUBLIC; + msgs.UsrDelete = TRUE; + msgs.Rfccode = CHRS_DEFAULT_RFC; + msgs.Ftncode = CHRS_DEFAULT_FTN; + strcpy(msgs.Origin, CFG.origin); +} + + + +int AppendMsgarea(void); +int AppendMsgarea() +{ + FILE *fil; + char ffile[81]; + struct _sysconnect syscon; + int i; + + sprintf(ffile, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + InitMsgRec(); + fwrite(&msgs, sizeof(msgs), 1, fil); + memset(&syscon, 0, sizeof(syscon)); + for (i = 1; i <= CFG.toss_systems; i++) + fwrite(&syscon, sizeof(syscon), 1, fil); + fclose(fil); + MsgUpdated = 1; + return 0; + } else + return -1; +} + + + +void EditSystem(sysconnect *); +void EditSystem(sysconnect *Sys) +{ + sysconnect S; + unsigned short zone = 0; + int refresh = TRUE; + + S = (* Sys); + for (;;) { + if (refresh) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5,6, "9.2.26 EDIT CONNECTION"); + set_color(CYAN, BLACK); + mvprintw( 7,6, "1. Aka"); + mvprintw( 8,6, "2. Send to"); + mvprintw( 9,6, "3. Recv from"); + mvprintw(10,6, "4. Pause"); + mvprintw(11,6, "5. Excluded"); + mvprintw(12,6, "6. Delete"); + refresh = FALSE; + } + set_color(WHITE, BLACK); + show_str( 7,23,23, aka2str(S.aka)); + show_bool( 8,23, S.sendto); + show_bool( 9,23, S.receivefrom); + show_bool(10,23, S.pause); + show_bool(11,23, S.cutoff); + zone = S.aka.zone; + + switch(select_menu(6)) { + case 0: (* Sys) = S; + return; + case 1: S.aka = PullUplink((char *)"9.2.29"); + refresh = TRUE; + break; + case 2: E_BOOL( 8,23, S.sendto, "^Send^ mail ^to^ this node") + case 3: E_BOOL( 9,23, S.receivefrom, "^Receive^ mail ^from^ this node") + case 4: E_BOOL(10,23, S.pause, "Is this node ^paused^") + case 5: E_BOOL(11,23, S.cutoff, "Is this node ^excluded (cutoff)^ by a moderator") + case 6: if (yes_no((char *)"Delete this entry")) { + memset(&S, 0, sizeof(sysconnect)); + (* Sys) = S; + return; + } + break; + } + + /* + * Set sendto and receivefrom to on when a new + * zone is entered. + */ + if ((S.aka.zone) && (!zone)) { + S.sendto = 1; + S.receivefrom = 1; + } + } +} + + + +int EditConnections(FILE *); +int EditConnections(FILE *fil) +{ + int systems, o = 0, i, y, x; + long offset; + char pick[12]; + sysconnect System; + char status[5]; + char temp[41]; + + systems = msgshdr.syssize / sizeof(sysconnect); + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 5, "9.2.29 MESSAGE AREA CONNECTIONS"); + set_color(CYAN, BLACK); + y = 7; + x = 2; + for (i = 1; i <= 20; i++) { + if ((o+i-1) < systems) { + if (i == 11) { + y = 7; + x = 42; + } + offset = (o+i-1) * sizeof(sysconnect); + if ((fseek(fil, offset, 0)) != 0) { + working(2, 0, 0); + return FALSE; + } + fread(&System, sizeof(sysconnect), 1, fil); + memset(&status, 0, 5); + memset(&status, '-', 4); + if (System.sendto) + status[0] = 'S'; + if (System.receivefrom) + status[1] = 'R'; + if (System.pause) + status[2] = 'P'; + if (System.cutoff) + status[3] = 'C'; + + if (System.aka.zone) { + set_color(CYAN,BLACK); + sprintf(temp, "%3d. %s %d:%d/%d.%d@%s", o+i, status, System.aka.zone, System.aka.net, System.aka.node, System.aka.point, System.aka.domain); + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d.", o+i); + } + mvprintw(y, x, temp); + y++; + } + } + strcpy(pick, select_pick(systems, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return FALSE; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < systems) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if (((atoi(pick) > 0) && (atoi(pick) <= systems))) { + offset = (atoi(pick) -1) * sizeof(sysconnect); + fseek(fil, offset, 0); + fread(&System, sizeof(sysconnect), 1, fil); + EditSystem(&System); + fseek(fil, offset, 0); + fwrite(&System, sizeof(sysconnect), 1, fil); + } + } +} + + + +void SetScreen(void); +void SetScreen() +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "9.2 EDIT MESSAGE AREA"); + set_color(CYAN, BLACK); + mvprintw( 6, 2, "1. Area Name"); + mvprintw( 7, 2, "2. FTN area"); + mvprintw( 8, 2, "3. Newsgroup"); + mvprintw( 9, 2, "4. Moderator"); + mvprintw(10, 2, "5. JAM base"); + mvprintw(11, 2, "6. Origin"); + mvprintw(12, 2, "7. Fido Aka"); + mvprintw(13, 2, "8. QWK name"); + mvprintw(14, 2, "9. Group"); + mvprintw(15, 2, "10. Distrib."); + mvprintw(16, 2, "11. Area Type"); + mvprintw(17, 2, "12. Msg Kinds"); + mvprintw(18, 2, "13. FTN chars"); + mvprintw(19, 2, "14. RFC chars"); + + mvprintw(13,36, "15. Days Old"); + mvprintw(14,36, "16. Max. Msgs"); + mvprintw(15,36, "17. Netreply"); + mvprintw(16,36, "18. Active"); + mvprintw(17,36, "19. Read Sec."); + mvprintw(18,36, "20. Write Sec."); + mvprintw(19,36, "21. Sysop Sec."); + + mvprintw(12,60, "22. User Del."); + mvprintw(13,60, "23. Aliases"); + mvprintw(14,60, "24. Quotes"); + mvprintw(15,60, "25. Mandatory"); + mvprintw(16,60, "26. UnSecure"); + mvprintw(17,60, "27. OLR Default"); + mvprintw(18,60, "28. OLR Forced"); + mvprintw(19,60, "29. Connections"); +} + + + +long LoadMsgRec(int, int); +long LoadMsgRec(int Area, int work) +{ + FILE *fil; + char mfile[81]; + long offset; + sysconnect System; + int i; + + if (work) + working(1, 0, 0); + + sprintf(mfile, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + if ((tfil = tmpfile()) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + offset = msgshdr.hdrsize + (((Area -1) * (msgshdr.recsize + msgshdr.syssize))); + if (fseek(fil, offset, SEEK_SET) != 0) { + fclose(tfil); + tfil = NULL; + working(2, 0, 0); + return -1; + } + + fread(&msgs, msgshdr.recsize, 1, fil); + MsgCrc = 0xffffffff; + MsgCrc = upd_crc32((char *)&msgs, MsgCrc, msgshdr.recsize); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, fil); + fwrite(&System, sizeof(sysconnect), 1, tfil); + MsgCrc = upd_crc32((char *)&System, MsgCrc, sizeof(sysconnect)); + } + fclose(fil); + if (work) + working(0, 0, 0); + + return offset; +} + + + +int SaveMsgRec(int, int); +int SaveMsgRec(int Area, int work) +{ + int i; + FILE *fil; + long offset; + char mfile[81]; + sysconnect System; + + if (work) + working(1, 0, 0); + sprintf(mfile, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r+")) == 0) { + working(2, 0, 0); + return -1; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + offset = msgshdr.hdrsize + (((Area -1) * (msgshdr.recsize + msgshdr.syssize))); + if (fseek(fil, offset, SEEK_SET)) { + fclose(fil); + working(2, 0, 0); + return -1; + } + + fwrite(&msgs, msgshdr.recsize, 1, fil); + fseek(tfil, 0, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, tfil); + fwrite(&System, sizeof(sysconnect), 1, fil); + } + fclose(fil); + fclose(tfil); + tfil = NULL; + if (work) + working(0, 0, 0); + return 0; +} + + + +void ShowStatus(sysconnect); +void ShowStatus(sysconnect S) +{ + clr_index(); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "Aka"); + mvprintw( 8, 6, "Send to"); + mvprintw( 9, 6, "Recv from"); + mvprintw(10, 6, "Pause"); + mvprintw(11, 6, "Excluded"); + set_color(WHITE, BLACK); + show_str( 7,16,23, aka2str(S.aka)); + show_bool( 8,16, S.sendto); + show_bool( 9,16, S.receivefrom); + show_bool(10,16, S.pause); + show_bool(11,16, S.cutoff); +} + + + +void MsgGlobal(void); +void MsgGlobal(void) +{ + gr_list *mgr = NULL, *tmp; + char *p, mfile[128]; + FILE *fil; + fidoaddr a1, a2; + int menu = 0, marea, Areas, akan = 0, Found; + int Total, Done, netbrd, daysold, maxmsgs; + long offset; + securityrec rs, ws, ss; + sysconnect S, Sc; + + /* + * Build the groups select array + */ + working(1, 0, 0); + sprintf(mfile, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + + while (fread(&mgroup, mgrouphdr.recsize, 1, fil) == 1) + fill_grlist(&mgr, mgroup.Name); + + fclose(fil); + sort_grlist(&mgr); + } + working(0, 0, 0); + + /* + * Initialize some variables + */ + memset(&rs, 0, sizeof(securityrec)); + memset(&ws, 0, sizeof(securityrec)); + memset(&ss, 0, sizeof(securityrec)); + memset(&S, 0, sizeof(sysconnect)); + S.sendto = TRUE; + S.receivefrom = TRUE; + memset(&mfile, 0, sizeof(mfile)); + sprintf(mfile, "%s", CFG.origin); + daysold = CFG.defdays; + maxmsgs = CFG.defmsgs; + netbrd = 1; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "9.2 GLOBAL EDIT MESSAGE AREAS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Delete connection"); + mvprintw( 8, 6, "2. Add new connection"); + mvprintw( 9, 6, "3. Replace connection"); + mvprintw(10, 6, "4. Change connection status"); + mvprintw(11, 6, "5. Change days old"); + mvprintw(12, 6, "6. Change max. messages"); + mvprintw(13, 6, "7. Change security"); + mvprintw(14, 6, "8. Change aka to use"); + mvprintw(15, 6, "9. Change origin line"); + mvprintw(16, 6, "10. Change netmail reply"); + mvprintw(17, 6, "11. Delete message area"); + + memset(&a1, 0, sizeof(fidoaddr)); + memset(&a2, 0, sizeof(fidoaddr)); + + menu = select_menu(11); + switch (menu) { + case 0: return; + case 1: a1 = PullUplink((char *)"AKA TO DELETE"); + break; + case 2: a2 = PullUplink((char *)"AKA TO ADD"); + break; + case 3: a1 = PullUplink((char *)"AKA TO REPLACE"); + a2 = PullUplink((char *)"NEW AKA"); + break; + case 4: S.aka = PullUplink((char *)"AKA TO CHANGE STATUS"); + ShowStatus(S); + S.sendto = edit_bool(8,16,S.sendto, (char *)"^Send^ mail to this node"); + S.receivefrom = edit_bool(9,16,S.receivefrom, (char *)"^Receive^ mail from this node"); + S.pause = edit_bool(10,16,S.pause, (char *)"Is this node ^paused^"); + S.cutoff = edit_bool(11,16,S.cutoff, (char *)"Is this node ^excluded^"); + break; + case 5: mvprintw(LINES -3, 5, "Days old"); + E_INT(LINES -3, 14, daysold, (char *)"Enter new number of ^days old^") + case 6: mvprintw(LINES -3, 5, "Max. messages"); + E_INT(LINES -3, 19, maxmsgs, (char *)"Enter ^maximum messages^") + case 7: rs = edit_sec(6, 5, rs, (char *)"9.2.7 READ SECURITY"); + ws = edit_sec(7, 5, ws, (char *)"9.2.7 WRITE SECURITY"); + ss = edit_sec(8, 5, ss, (char *)"9.2.7 SYSOP SECURITY"); + break; + case 8: akan = PickAka((char *)"9.2.8", TRUE); + break; + case 9: E_STR(LINES -3, 5, 64, mfile, "Enter new ^origin^ line"); + case 10:mvprintw(LINES -3, 5, "Netmail reply board"); + E_INT(LINES -3, 25, netbrd, (char *)"The ^netmail reply^ board number") + } + + E_Group(&mgr, (char *)"SELECT MESSAGE GROUPS TO CHANGE"); + + /* + * Show settings before proceeding + */ + switch (menu) { + case 1: mvprintw(7, 6, "Delete aka %s", aka2str(a1)); + break; + case 2: mvprintw(7, 6, "Add aka %s", aka2str(a2)); + break; + case 3: p = xstrcpy(aka2str(a1)); + mvprintw(7, 6, "Replace aka %s with %s", p, aka2str(a2)); + free(p); + break; + case 4: ShowStatus(S); + mvprintw(14, 6, "Change the link status"); + break; + case 5: mvprintw(7, 6, "Change days old to %d", daysold); + break; + case 6: mvprintw(7, 6, "Change maximum messages to %d", maxmsgs); + break; + case 7: set_color(CYAN, BLACK); + mvprintw(7, 6, "Read security"); + mvprintw(8, 6, "Write security"); + mvprintw(9, 6, "Sysop security"); + set_color(WHITE, BLACK); + show_sec(7, 21, rs); + show_sec(8, 21, ws); + show_sec(9, 21, ss); + break; + case 8: if (akan != -1) + mvprintw( 7, 6, "Set %s as new aka to use", aka2str(CFG.aka[akan])); + break; + case 9: mvprintw(7, 6, "Origin: %s", mfile); + break; + case 10:mvprintw(7, 6, "New netmail reply board %d", netbrd); + break; + case 11:mvprintw(7, 6, "Delete message areas"); + break; + } + + if (yes_no((char *)"Perform changes")) { + working(1, 0, 0); + Areas = CountMsgarea(); + Total = Done = 0; + + for (marea = 1; marea <= Areas; marea++) { + offset = LoadMsgRec(marea, FALSE); + if (msgs.Active && strlen(msgs.Group)) { + for (tmp = mgr; tmp; tmp = tmp->next) { + if (tmp->tagged && (strcmp(tmp->group, msgs.Group) == 0)) { + Total++; + switch (menu) { + case 1: fseek(tfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) { + if ((Sc.aka.zone == a1.zone) && + (Sc.aka.net == a1.net) && + (Sc.aka.node == a1.node) && + (Sc.aka.point == a1.point)) { + fseek(tfil, - sizeof(sysconnect), SEEK_CUR); + memset(&Sc, 0, sizeof(sysconnect)); + fwrite(&Sc, sizeof(sysconnect), 1, tfil); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Deleted %s from %s", aka2str(a1), msgs.Tag); + } + break; + } + } + break; + case 2: fseek(tfil, 0, SEEK_SET); + Found = FALSE; + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) + if ((Sc.aka.zone == a2.zone) && + (Sc.aka.net == a2.net) && + (Sc.aka.node == a2.node) && + (Sc.aka.point == a2.point)) { + Found = TRUE; + break; + } + if (Found) + break; + fseek(tfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) { + if (Sc.aka.zone == 0) { + fseek(tfil, - sizeof(sysconnect), SEEK_CUR); + memset(&Sc, 0, sizeof(sysconnect)); + Sc.aka.zone = a2.zone; + Sc.aka.net = a2.net; + Sc.aka.node = a2.node; + Sc.aka.point = a2.point; + Sc.sendto = TRUE; + Sc.receivefrom = TRUE; + sprintf(Sc.aka.domain, "%s", a2.domain); + fwrite(&Sc, sizeof(sysconnect), 1, tfil); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Added %s to area %s", aka2str(a2), msgs.Tag); + } + break; + } + } + break; + case 3: fseek(tfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) { + if ((Sc.aka.zone == a1.zone) && + (Sc.aka.net == a1.net) && + (Sc.aka.node == a1.node) && + (Sc.aka.point == a1.point)) { + Sc.aka.zone = a2.zone; + Sc.aka.net = a2.net; + Sc.aka.node = a2.node; + Sc.aka.point = a2.point; + sprintf(Sc.aka.domain, "%s", a2.domain); + fseek(tfil, - sizeof(sysconnect), SEEK_CUR); + fwrite(&Sc, sizeof(sysconnect), 1, tfil); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + p = xstrcpy(aka2str(a1)); + Syslog('+', "Changed %s into %s in area %s", p, aka2str(a2), msgs.Tag); + free(p); + } + break; + } + } + break; + case 4: fseek(tfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) { + if ((Sc.aka.zone == S.aka.zone) && + (Sc.aka.net == S.aka.net) && + (Sc.aka.node == S.aka.node) && + (Sc.aka.point == S.aka.point)) { + Sc.sendto = S.sendto; + Sc.receivefrom = S.receivefrom; + Sc.pause = S.pause; + Sc.cutoff = S.cutoff; + fseek(tfil, - sizeof(sysconnect), SEEK_CUR); + fwrite(&Sc, sizeof(sysconnect), 1, tfil); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed status of %s in area %s", aka2str(S.aka), msgs.Tag); + } + break; + } + } + break; + case 5: if (daysold != msgs.DaysOld) { + msgs.DaysOld = daysold; + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed days old to %d in area %s", daysold, msgs.Tag); + } + } + break; + case 6: if (maxmsgs != msgs.MaxMsgs) { + msgs.MaxMsgs = maxmsgs; + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed max. messages to %d in area %s", maxmsgs, msgs.Tag); + } + } + break; + case 7: if ((msgs.RDSec.level != rs.level) || + (msgs.RDSec.flags != rs.flags) || + (msgs.RDSec.notflags != rs.notflags) || + (msgs.WRSec.level != ws.level) || + (msgs.WRSec.flags != ws.flags) || + (msgs.WRSec.notflags != ws.notflags) || + (msgs.SYSec.level != ss.level) || + (msgs.SYSec.flags != ss.flags) || + (msgs.SYSec.notflags != ss.notflags)) { + memcpy(&msgs.RDSec, &rs, sizeof(securityrec)); + memcpy(&msgs.WRSec, &ws, sizeof(securityrec)); + memcpy(&msgs.SYSec, &ss, sizeof(securityrec)); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Updated security levels in area %s", msgs.Tag); + } + } + break; + case 8: if (akan != -1) { + if ((msgs.Aka.zone != CFG.aka[akan].zone) || + (msgs.Aka.net != CFG.aka[akan].net) || + (msgs.Aka.node != CFG.aka[akan].node) || + (msgs.Aka.point != CFG.aka[akan].point)) { + msgs.Aka.zone = CFG.aka[akan].zone; + msgs.Aka.net = CFG.aka[akan].net; + msgs.Aka.node = CFG.aka[akan].node; + msgs.Aka.point = CFG.aka[akan].point; + sprintf(msgs.Aka.domain, "%s", CFG.aka[akan].domain); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Area %s now uses aka %s", msgs.Tag, aka2str(msgs.Aka)); + } + } + } + break; + case 9: if (strcmp(msgs.Origin, mfile)) { + sprintf(msgs.Origin, "%s", mfile); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed origin line in area %s", msgs.Tag); + } + } + break; + case 10:if (netbrd != msgs.NetReply) { + msgs.NetReply = netbrd; + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed netmail board to %d in area %s", netbrd, msgs.Tag); + } + } + break; + case 11:if (msgs.Active) { + msgs.Active = FALSE; + memset(&msgs.Name, 0, sizeof(msgs.Name)); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Deleted message area %s", msgs.Tag); + } + } + break; + } + } + } + } + if (tfil != NULL) + fclose(tfil); + } + + working(0, 0, 0); + mvprintw(LINES -3, 6,"Made %d changes in %d possible areas", Done, Total); + (void)readkey(LINES -3, 50, LIGHTGRAY, BLACK); + if (Done) + MsgUpdated = TRUE; + } + } + + tidy_grlist(&mgr); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditMsgRec(int); +int EditMsgRec(int Area) +{ + unsigned long crc1; + int tmp, i, changed = FALSE; + sysconnect System; + + clr_index(); + IsDoing("Edit Msg Area"); + + if (LoadMsgRec(Area, TRUE) == -1) + return -1; + + SetScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6,16,40, msgs.Name); + show_str( 7,16,50, msgs.Tag); + show_str( 8,16,64, msgs.Newsgroup); + show_str( 9,16,64, msgs.Moderator); + show_str(10,16,64, msgs.Base); + show_str(11,16,64, msgs.Origin); + show_aka(12,16, msgs.Aka); + show_str(13,16,13, msgs.QWKname); + show_str(14,16,12, msgs.Group); + show_str(15,16,16, msgs.Distribution); + show_msgtype(16,16, msgs.Type); + show_msgkinds(17,16, msgs.MsgKinds); + show_str(18,16,16, printable(getchrs(msgs.Ftncode), 0)); + show_str(19,16,16, printable(getchrs(msgs.Rfccode), 0)); + + show_int( 13,52, msgs.DaysOld); + show_int( 14,52, msgs.MaxMsgs); + show_int( 15,52, msgs.NetReply); + show_bool(16,52, msgs.Active); + show_int( 17,52, msgs.RDSec.level); + show_int( 18,52, msgs.WRSec.level); + show_int( 19,52, msgs.SYSec.level); + + show_bool(12,76, msgs.UsrDelete); + show_bool(13,76, msgs.Aliases); + show_bool(14,76, msgs.Quotes); + show_bool(15,76, msgs.Mandatory); + show_bool(16,76, msgs.UnSecure); + show_bool(17,76, msgs.OLR_Default); + show_bool(18,76, msgs.OLR_Forced); + + switch(select_menu(29)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&msgs, crc1, msgshdr.recsize); + fseek(tfil, 0, 0); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, tfil); + crc1 = upd_crc32((char *)&System, crc1, sizeof(sysconnect)); + } + if ((MsgCrc != crc1) || (changed)) { + if (yes_no((char *)"Record is changed, save") == 1) { + if (SaveMsgRec(Area, TRUE) == -1) + return -1; + MsgUpdated = 1; + Syslog('+', "Saved record %d", Area); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 6,16,40,msgs.Name, "The ^Name^ of this area") + case 2: strcpy(msgs.Tag, edit_ups(7,16,50, msgs.Tag, (char *)"The ^Area Tag^ for Echomail")); + if (!strlen(msgs.QWKname)) { + memset(&msgs.QWKname, '\0', strlen(msgs.QWKname)); + strncpy(msgs.QWKname, msgs.Tag, 13); + } + break; + case 3: E_STR( 8,16,64,msgs.Newsgroup, "The ^Newsgroup^ name of this area") + case 4: E_STR( 9,16,64,msgs.Moderator, "The ^Moderator^ if this is a moderated area") + case 5: E_JAM( 10,16,64,msgs.Base, "The path to the ^JAM Message Base^") + case 6: E_STR( 11,16,64,msgs.Origin, "The ^Origin line^ to append to Echomail messages") + case 7: tmp = PickAka((char *)"9.2.7", TRUE); + if (tmp != -1) + msgs.Aka = CFG.aka[tmp]; + SetScreen(); break; + case 8: E_UPS( 13,16,13,msgs.QWKname, "The name for ^QWK or Bluewave^ message packets") + case 9: strcpy(msgs.Group, PickMGroup((char *)"9.2.9")); + if (strlen(msgs.Group)) { + msgs.Aka = mgroup.UseAka; + msgs.Active = TRUE; + /* + * If there is an uplink defined in the group, + * and the first connected system is empty, + * copy the uplink as default connection. + */ + if (mgroup.UpLink.zone) { + fseek(tfil, 0, SEEK_SET); + fread(&System, sizeof(sysconnect), 1, tfil); + if (!System.aka.zone) { + memset(&System, 0, sizeof(sysconnect)); + System.aka = mgroup.UpLink; + System.sendto = TRUE; + System.receivefrom = TRUE; + fseek(tfil, 0, SEEK_SET); + fwrite(&System, sizeof(sysconnect), 1, tfil); + } + } + } + SetScreen(); + break; + case 10:E_STR( 15,16,16,msgs.Distribution, "The ^Distribution^ name if this is a newsgroup") + case 11:msgs.Type = edit_msgtype(16,16, msgs.Type); break; + case 12:msgs.MsgKinds = edit_msgkinds(17,16, msgs.MsgKinds); break; + + case 15:E_INT( 13,52, msgs.DaysOld, "Maximum ^days^ to keep mail in this area") + case 16:E_INT( 14,52, msgs.MaxMsgs, "The ^maximum^ amount of messages in this area") + case 17:E_INT( 15,52, msgs.NetReply, "The ^Area Number^ for netmail replies") + case 18:E_BOOL(16,52, msgs.Active, "Is this area ^Active^") + case 19:E_SEC( 17,52, msgs.RDSec, "9.2 EDIT READ SECURITY", SetScreen) + case 20:E_SEC( 18,52, msgs.WRSec, "9.2 EDIT WRITE SECURITY", SetScreen) + case 21:E_SEC( 19,52, msgs.SYSec, "9.2 EDIT SYSOP SECURITY", SetScreen) + + case 22:E_BOOL(12,76, msgs.UsrDelete, "Allow users to ^Delete^ their messages") + case 23:E_BOOL(13,76, msgs.Aliases, "Allow ^aliases^ or real names only") + case 24:E_BOOL(14,76, msgs.Quotes, "Add random ^quotes^ to new messages") + case 25:E_BOOL(15,76, msgs.Mandatory, "Is this area ^mandatory^ for nodes") + case 26:E_BOOL(16,76, msgs.UnSecure, "Toss messages ^UnSecure^, ie: no originating check") + case 27:E_BOOL(17,76, msgs.OLR_Default, "Area is ^default^ for ^offline^ users.") + case 28:E_BOOL(18,76, msgs.OLR_Forced, "Area is ^always on^ for ^offline^ users.") + case 29:if (EditConnections(tfil)) + changed = TRUE; + SetScreen(); break; + } + } +} + + + +void EditMsgarea(void) +{ + int records, i, o, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + int from, too; + sysconnect System; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountMsgarea(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenMsgarea() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 3, "9.2 MESSAGE AREA SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, fil); + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = sizeof(msgshdr) + (((o + i) - 1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(fil, offset, 0); + fread(&msgs, msgshdr.recsize, 1, fil); + if (msgs.Active) { + set_color(CYAN, BLACK); + sprintf(temp, "%3d. %-8s %-25s %-40s", o + i, getmsgtype(msgs.Type), msgs.Tag, msgs.Name); + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d.", o+i); + } + mvprintw(y, 2, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_area(records, 10)); + + if (strncmp(pick, "-", 1) == 0) { + CloseMsgarea(FALSE); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendMsgarea() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "G", 1) == 0) { + MsgGlobal(); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o = o + 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o = o - 10; + + if (strncmp(pick, "M", 1) == 0) { + from = too = 0; + mvprintw(LINES -3, 5, "From"); + from = edit_int(LINES -3, 10, from, (char *)"Wich ^area^ you want to move"); + mvprintw(LINES -3,15, "To"); + too = edit_int(LINES -3, 18, too, (char *)"Too which ^area^ to move"); + if ((LoadMsgRec(from, TRUE) == -1) || (!msgs.Active)) { + errmsg((char *)"The originating area is invalid"); + fclose(tfil); + } else { + fclose(tfil); + if ((LoadMsgRec(too, TRUE) == -1) || (msgs.Active)) { + errmsg((char *)"The destination area is invalid"); + fclose(tfil); + } else { + fclose(tfil); + LoadMsgRec(from, TRUE); + SaveMsgRec(too, TRUE); + LoadMsgRec(from, TRUE); + InitMsgRec(); + fseek(tfil, 0, SEEK_SET); + memset(&System, 0, sizeof(sysconnect)); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fwrite(&System, sizeof(sysconnect), 1, tfil); + } + SaveMsgRec(from, TRUE); + MsgUpdated = 1; + } + } + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + EditMsgRec(atoi(pick)); + o = ((atoi(pick) - 1) / 10) * 10; + } + } +} + + + +char *PickMsgarea(char *shdr) +{ + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + static char Buf[81]; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return '\0'; + } + + records = CountMsgarea(); + if (records == -1) { + working(2, 0, 0); + return '\0'; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. MESSAGE AREA SELECT", shdr); + mvprintw(5, 3, temp); + set_color(CYAN, BLACK); + + if (records) { + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(msgshdr) + (((o + i) - 1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(fil, offset, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, fil); + if (msgs.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-31s", o + i, msgs.Name); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return '\0'; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o += 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o -= 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + offset = msgshdr.hdrsize + ((atoi(pick) - 1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(fil, offset, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, fil); + fclose(fil); + if (msgs.Active) { + memset(&Buf, 0, sizeof(Buf)); + sprintf(Buf, "%s", msgs.Base); + return Buf; + } + } + } + } +} + + + +int GroupInMarea(char *Group) +{ + int Area = 0, RetVal = 0, systems; + FILE *no; + char temp[128]; + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return 0; + + fread(&msgshdr, sizeof(msgshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, no); + systems = msgshdr.syssize / sizeof(sysconnect); + + while (fread(&msgs, msgshdr.recsize, 1, no) == 1) { + Area++; + + if (msgs.Active && !strcmp(msgs.Group, Group) && strlen(msgs.Group)) { + RetVal++; + Syslog('-', "Group %s in msg area %d: %s", Group, Area, msgs.Tag); + } + + fseek(no, msgshdr.syssize, SEEK_CUR); + } + + fclose(no); + return RetVal; +} + + + +int NodeInMarea(fidoaddr A) +{ + int i, Area = 0, RetVal = 0, systems; + FILE *no; + char temp[128]; + sysconnect S; + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return 0; + + fread(&msgshdr, sizeof(msgshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, no); + systems = msgshdr.syssize / sizeof(sysconnect); + + while (fread(&msgs, msgshdr.recsize, 1, no) == 1) { + Area++; + for (i = 0; i < systems; i++) { + fread(&S, sizeof(sysconnect), 1, no); + if (S.aka.zone && (S.aka.zone == A.zone) && (S.aka.net == A.net) && + (S.aka.node == A.node) && (S.aka.point == A.point) && msgs.Active) { + RetVal++; + Syslog('-', "Node %s connected to msg area %d: %s", aka2str(A), Area, msgs.Tag); + } + } + } + + fclose(no); + return RetVal; +} + + + +void gold_areas(FILE *fp) +{ + char *temp; + FILE *no; + int i = 0; + + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return; + + fread(&msgshdr, sizeof(msgshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, no); + + fprintf(fp, "; Message Areas\n;\n"); + fprintf(fp, "AREASCAN *\n"); + fprintf(fp, "AREATYPEORDER Net Email Echo News Local\n"); + + while (fread(&msgs, msgshdr.recsize, 1, no) == 1) { + + i++; + if (msgs.Active) { + fprintf(fp, "AREADEF "); + if (strlen(msgs.Tag)) + fprintf(fp, "%s", msgs.Tag); + else + fprintf(fp, "AREA%d", i); + fprintf(fp, " \"%s\" ", msgs.Name); + switch (msgs.Type) { + case LOCALMAIL : fprintf(fp, "0 Local"); break; + case NETMAIL : fprintf(fp, "N Net"); break; + case ECHOMAIL : fprintf(fp, "C Echo"); break; + case NEWS : fprintf(fp, "I News"); break; + } + fprintf(fp, " JAM %s . ", msgs.Base); + if (msgs.Type == NETMAIL) + fprintf(fp, "(Loc Pvt)"); + else + fprintf(fp, "(Loc)"); + fprintf(fp, " \"%s\"\n", msgs.Origin); + } + fseek(no, msgshdr.syssize, SEEK_CUR); + } + + fclose(no); + free(temp); + fprintf(fp, "\n"); +} + + + +int mail_area_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81], status[5]; + FILE *no; + int i = 0, j, systems, First = TRUE; + sysconnect System; + int LMiy; + struct tm *t; + time_t Now; + + Now = time(NULL); + t = localtime(&Now); + + Diw = t->tm_wday; + Miy = t->tm_mon; + if (Miy == 0) + LMiy = 11; + else + LMiy = Miy - 1; + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + fread(&msgshdr, sizeof(msgshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, no); + systems = msgshdr.syssize / sizeof(sysconnect); + + while (fread(&msgs, msgshdr.recsize, 1, no) == 1) { + + i++; + if (msgs.Active) { + page = newpage(fp, page); + + if (First) { + addtoc(fp, toc, 9, 2, page, (char *)"Mail areas"); + First = FALSE; + fprintf(fp, "\n"); + } else + fprintf(fp, "\n\n"); + + fprintf(fp, " Area number %d\n", i); + fprintf(fp, " Area name %s\n", msgs.Name); + fprintf(fp, " Area tag %s\n", msgs.Tag); + fprintf(fp, " Newsgroup name %s\n", msgs.Newsgroup); + fprintf(fp, " Distribution %s\n", msgs.Distribution); + fprintf(fp, " Moderator %s\n", msgs.Moderator); + fprintf(fp, " JAM message base %s\n", msgs.Base); + fprintf(fp, " Offline name %s\n", msgs.QWKname); + fprintf(fp, " Area type %s\n", getmsgtype(msgs.Type)); + fprintf(fp, " Messages type %s\n", getmsgkinds(msgs.MsgKinds)); + fprintf(fp, " FTN charset %s\n", printable(getchrs(msgs.Ftncode), 0)); + fprintf(fp, " RFC charset %s\n", printable(getchrs(msgs.Rfccode), 0)); + fprintf(fp, " Days old msgs. %d\n", msgs.DaysOld); + fprintf(fp, " Maximum msgs. %d\n", msgs.MaxMsgs); + fprintf(fp, " Users delete %s\n", getboolean(msgs.UsrDelete)); + fprintf(fp, " Read security %s\n", get_secstr(msgs.RDSec)); + fprintf(fp, " Write security %s\n", get_secstr(msgs.WRSec)); + fprintf(fp, " Sysop security %s\n", get_secstr(msgs.SYSec)); + fprintf(fp, " Minimum age %d\n", msgs.Age); + fprintf(fp, " Password %s\n", msgs.Password); + fprintf(fp, " Group %s\n", msgs.Group); + fprintf(fp, " Fido address %s\n", aka2str(msgs.Aka)); + fprintf(fp, " Netmail board %d\n", msgs.NetReply); + fprintf(fp, " Origin line %s\n", msgs.Origin); + fprintf(fp, " Allow aliases %s\n", getboolean(msgs.Aliases)); + fprintf(fp, " OLR mandatory %s\n", getboolean(msgs.OLR_Forced)); + fprintf(fp, " OLR default on %s\n", getboolean(msgs.OLR_Default)); + fprintf(fp, " Append quotes %s\n", getboolean(msgs.Quotes)); + fprintf(fp, " Nodes mandatory %s\n", getboolean(msgs.Mandatory)); + fprintf(fp, " UnSecure toss %s\n", getboolean(msgs.UnSecure)); + fprintf(fp, " Last msg rcvd. %s", ctime(&msgs.LastRcvd)); + fprintf(fp, " Last msg posted %s", ctime(&msgs.LastPosted)); + + for (j = 0; j < systems; j++) { + fread(&System, sizeof(sysconnect), 1, no); + if (System.aka.zone) { + memset(&status, 0, 5); + memset(&status, '-', 4); + if (System.sendto) + status[0] = 'S'; + if (System.receivefrom) + status[1] = 'R'; + if (System.pause) + status[2] = 'P'; + if (System.cutoff) + status[3] = 'C'; + + fprintf(fp, " Link %2d %s %s\n", j+1, status, aka2str(System.aka)); + } + } + fprintf(fp, "\n"); + fprintf(fp, " Total This Month Last Month\n"); + fprintf(fp, " ---------- ---------- ----------\n"); + fprintf(fp, " Msgs received %-10ld %-10ld %-10ld\n", msgs.Received.total, msgs.Received.month[Miy], msgs.Received.month[LMiy]); + fprintf(fp, " Msgs posted %-10ld %-10ld %-10ld\n", msgs.Posted.total, msgs.Posted.month[Miy], msgs.Posted.month[LMiy]); + + } else + fseek(no, msgshdr.syssize, SEEK_CUR); + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_marea.h b/mbsetup/m_marea.h new file mode 100644 index 00000000..8b22974b --- /dev/null +++ b/mbsetup/m_marea.h @@ -0,0 +1,17 @@ +#ifndef _MAREA_H +#define _MAREA_H + + +int OpenMsgarea(void); +void CloseMsgarea(int); +int GroupInMarea(char *); +int NodeInMarea(fidoaddr); +int CountMsgarea(void); +void EditMsgarea(void); +void gold_areas(FILE *); +int mail_area_doc(FILE *, FILE *, int); +char *PickMsgarea(char *); + + +#endif + diff --git a/mbsetup/m_menu.c b/mbsetup/m_menu.c new file mode 100644 index 00000000..db12d4d8 --- /dev/null +++ b/mbsetup/m_menu.c @@ -0,0 +1,597 @@ +/***************************************************************************** + * + * File ..................: mbsetup/m_menu.c + * Purpose ...............: Edit BBS menus + * Last modification date : 27-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "mutil.h" +#include "screen.h" +#include "ledit.h" +#include "m_lang.h" +#include "m_menu.h" + + + +char *select_menurec(int max) +{ + static char *menu=(char *)"-"; + char help[81]; + int pick; + + if (max > 10) + sprintf(help, "Rec. (1..%d), ^\"-\"^ Back, ^A^ppend, ^D^elete, ^M^ove, ^P^revious, ^N^ext", max); + else if (max > 1) + sprintf(help, "Rec. (1..%d), ^\"-\"^ Back, ^A^ppend, ^D^elete, ^M^ove", max); + else if (max == 1) + sprintf(help, "Rec. (1..%d), ^\"-\"^ Back, ^A^ppend, ^D^elete", max); + else + sprintf(help, "Select ^\"-\"^ for previous level, ^A^ppend a record"); + + showhelp(help); + + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES -3, 6); + clrtoeol(); + + if (strncmp(menu, "A", 1) == 0) + break; + if (strncmp(menu, "-", 1) == 0) + break; + if (strncmp(menu, "D", 1) == 0) + break; + if ((max > 1) && (strncmp(menu, "M", 1) == 0)) + break; + + if (max > 10) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + break; + + working(2, 0, 0); + working(0, 0, 0); + } + return menu; +} + + + +void Show_A_Menu(void); +void Show_A_Menu(void) +{ + char *p; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "8.3. EDIT MENU ITEM"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Sel. key"); + mvprintw( 8, 2, "2. Type nr."); + mvprintw( 9, 2, "3. Opt. data"); + mvprintw(10, 2, "4. Display"); + mvprintw(11, 2, "5. Security"); + mvprintw(12, 2, "6. Min. age"); + mvprintw(13, 2, "7. Max. lvl"); + mvprintw(14, 2, "8. Password"); + mvprintw(15, 2, "9. Credit"); + mvprintw(16, 2, "10. Colors"); + mvprintw(12,42, "11. Autoexec"); + mvprintw(13,42, "12. Menu open"); + if (menus.MenuType == 7) { + mvprintw(14,42, "13. No door.sys"); + mvprintw(15,42, "14. Y2K style"); + mvprintw(16,42, "15. Use Comport"); + } + + set_color(WHITE, BLACK); + show_str( 7,16, 1, menus.MenuKey); + show_int( 8,16, menus.MenuType); show_str( 8, 26,29, menus.TypeDesc); + show_str( 9,16,64, menus.OptionalData); + show_str(10,16,64, menus.Display); + show_sec(11,16, menus.MenuSecurity); + show_int(12,16, menus.Age); + show_int(13,16, menus.MaxSecurity); + if (strlen(menus.Password)) + show_str(14,16,14, (char *)"**************"); + else + show_str(14,16,14, (char *)""); + show_int(15,16, menus.Credit); + S_COL(16,16, "Display color", menus.ForeGnd, menus.BackGnd) + set_color(WHITE, BLACK); + show_bool(12,58, menus.AutoExec); + if ((menus.OpenFrom == 0) && (menus.OpenTo == 0)) + show_str(13,58, 6, (char *)"Always"); + else { + p = calloc(40, sizeof(char)); + sprintf(p, "%02d:%02d - %02d:%02d", menus.OpenFrom / 60, menus.OpenFrom % 60, + menus.OpenTo / 60, menus.OpenTo % 60); + show_str(13, 58, 13, p); + free(p); + } + if (menus.MenuType == 7) { + show_bool(14,58, menus.NoDoorsys); + show_bool(15,58, menus.Y2Kdoorsys); + show_bool(16,58, menus.Comport); + } +} + + + +int GetSubmenu(int, int); +int GetSubmenu(int Base, int Max) +{ + int i, x, y; + char temp[81]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "8.3 EDIT MENU - SELECT MENUTYPE"); + set_color(CYAN, BLACK); + y = 6; + x = 2; + + for (i = 1; i <= Max; i++) { + sprintf(temp, "%2d. %s", i, getmenutype(i - 1 + Base)); + mvprintw(y, x, temp); + y++; + if ((i % 13) == 0) { + y = 6; + x = 42; + } + } + i = select_menu(Max); + + if (i) + return (i + Base - 1); + else + return 0; +} + + + +int GetMenuType(void); +int GetMenuType(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.3 EDIT MENU - SELECT MENUTYPE"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Global system menus"); + mvprintw( 8, 6, "2. File areas menus"); + mvprintw( 9, 6, "3. Message areas menus"); + mvprintw(10, 6, "4. User setting menus"); + mvprintw(11, 6, "5. Oneliner menus"); + mvprintw(12, 6, "6. BBS List menus"); + + switch (select_menu(6)) { + case 1: return GetSubmenu(1, 25); + case 2: return GetSubmenu(101, 19); + case 3: return GetSubmenu(201, 20); + case 4: return GetSubmenu(301, 16); + case 5: return GetSubmenu(401, 5); + case 6: return GetSubmenu(501, 6); + default: return 0; + } +} + + + +void Edit_A_Menu(void); +void Edit_A_Menu(void) +{ + Show_A_Menu(); + + for (;;) { + switch(select_menu(15)) { + case 0: + return; + break; + + case 1: E_UPS( 7,16, 1, menus.MenuKey, "The ^key^ to select this menu item") + case 2: menus.MenuType = GetMenuType(); + memset(&menus.TypeDesc, 0, sizeof(menus.TypeDesc)); + if (menus.MenuType) + strcpy(menus.TypeDesc, getmenutype(menus.MenuType)); + Show_A_Menu(); + break; + case 3: E_STR( 9,16,64, menus.OptionalData, "The ^optional data^ for this menu item") + case 4: E_STR(10,16,64, menus.Display, "The text to ^display^ for this menu") + case 5: E_SEC(11,16, menus.MenuSecurity, "7.3.5 MENU ACCESS SECURITY", Show_A_Menu) + case 6: E_INT(12,16, menus.Age, "The minimum ^Age^ to select this menu, 0 is don't care") + case 7: E_INT(13,16, menus.MaxSecurity, "The maximum ^Security level^ to access this menu") + case 8: E_STR(14,16,14, menus.Password, "The ^password^ to access this menu item") + case 9: E_INT(15,16, menus.Credit, "The ^credit cost^ for this menu item") + case 10:edit_color(&menus.ForeGnd, &menus.BackGnd, (char *)"Display color"); + Show_A_Menu(); + break; + case 11:E_BOOL(12,58, menus.AutoExec, "Is this an ^Autoexecute^ menu item") + case 13:if (menus.MenuType == 7) { + E_BOOL(14,58, menus.NoDoorsys, "Suppress writing ^door.sys^ dropfile") + } else + break; + case 14:if (menus.MenuType == 7) { + E_BOOL(15,58, menus.Y2Kdoorsys, "Create ^door.sys^ with 4 digit yearnumbers") + } else + break; + case 15:if (menus.MenuType == 7) { + E_BOOL(16,58, menus.Comport, "Write real ^COM port^ in door.sys for Vmodem patch") + } else + break; + } + } +} + + + +void EditMenu(char *); +void EditMenu(char *Name) +{ + char mtemp[81], temp[161]; + FILE *fil, *tmp; + int records = 0, i, o, y; + char pick[12]; + long offset; + unsigned long crc, crc1; + int MenuUpdated = FALSE, from, too; + struct menufile tmenus; + + clr_index(); + IsDoing("Edit Menu"); + working(1, 0, 0); + + sprintf(mtemp, "%s/%s.tmp", lang.MenuPath, Name); + tmp = fopen(mtemp, "w+"); + + sprintf(temp, "%s/%s.mnu", lang.MenuPath, Name); + if ((fil = fopen(temp, "r")) != NULL) { + while (fread(&menus, sizeof(menus), 1, fil) == 1) { + fwrite(&menus, sizeof(menus), 1, tmp); + records++; + } + fclose(fil); + } + + o = 0; + for (;;) { + clr_index(); + working(1, 0, 0); + sprintf(temp, "8.3 EDIT MENU \"%s\" (%s)", Name, lang.Name); + mvprintw( 5, 6, tu(temp)); + set_color(CYAN, BLACK); + fseek(tmp, 0, SEEK_SET); + + if (records) { + y = 7; + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = ((o + i) - 1) * sizeof(menus); + fseek(tmp, offset, SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + if ((menus.MenuKey[0]) || menus.AutoExec) { + set_color(CYAN, BLACK); + mvprintw(y, 5, "%3d. ", o + i); + if (menus.AutoExec) { + set_color(LIGHTRED, BLACK); + mvprintw(y, 10, "a"); + set_color(CYAN, BLACK); + } else + mvprintw(y, 10, "%1s", menus.MenuKey); + mvprintw(y, 12, "%-29s %5d %s", menus.TypeDesc, + menus.MenuSecurity.level, menus.OptionalData); + } else { + set_color(LIGHTBLUE, BLACK); + mvprintw(y, 5, "%3d.", o + i); + } + y++; + } + } + } + + working(0, 0, 0); + strcpy(pick, select_menurec(records)); + + if (strncmp(pick, "-", 1) == 0) { + if (MenuUpdated) { + if (yes_no((char *)"Menu is changed, save changes") == 1) { + working(1, 0, 0); + sprintf(temp, "%s/%s.mnu", lang.MenuPath, Name); + if ((fil = fopen(temp, "w+")) == NULL) { + working(2, 0, 0); + } else { + fseek(tmp, 0, SEEK_SET); + while (fread(&menus, sizeof(menus), 1, tmp) == 1) { + if (menus.MenuKey[0] || menus.AutoExec) + fwrite(&menus, sizeof(menus), 1, fil); + } + fclose(fil); + } + working(0, 0, 0); + } + } + fclose(tmp); + unlink(mtemp); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + memset(&menus, 0, sizeof(menus)); + fseek(tmp, 0, SEEK_END); + fwrite(&menus, sizeof(menus), 1, tmp); + records++; + working(0, 0, 0); + } + + if (strncmp(pick, "D", 1) == 0) { + mvprintw(LINES -3, 6, "Enter menu number (1..%d) to delete >", records); + y = 0; + y = edit_int(LINES -3, 44, y, (char *)"Enter record number"); + if ((y > 0) && (y <= records) && yes_no((char *)"Remove record")) { + offset = (y - 1) * sizeof(menus); + fseek(tmp, offset, SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + menus.MenuKey[0] = '\0'; + menus.AutoExec = FALSE; + fseek(tmp, offset, SEEK_SET); + fwrite(&menus, sizeof(menus), 1, tmp); + MenuUpdated = TRUE; + } + } + + if (strncmp(pick, "M", 1) == 0) { + from = too = 0; + mvprintw(LINES -3, 6, "Enter menu number (1..%d) to move >", records); + from = edit_int(LINES -3, 42, from, (char *)"Enter record number"); + locate(LINES -3, 6); + clrtoeol(); + mvprintw(LINES -3, 6, "Enter new position (1..%d) >", records); + too = edit_int(LINES -3, 36, too, (char *)"Enter destination record number, other will move away"); + if ((from == too) || (from == 0) || (too == 0) || (from > records) || (too > records)) { + errmsg("That makes no sense"); + } else if (yes_no((char *)"Proceed move")) { + fseek(tmp, (from -1) * sizeof(menus), SEEK_SET); + fread(&tmenus, sizeof(menus), 1, tmp); + if (from > too) { + for (i = from; i > too; i--) { + fseek(tmp, (i -2) * sizeof(menus), SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + fseek(tmp, (i -1) * sizeof(menus), SEEK_SET); + fwrite(&menus, sizeof(menus), 1, tmp); + } + } else { + for (i = from; i < too; i++) { + fseek(tmp, i * sizeof(menus), SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + fseek(tmp, (i -1) * sizeof(menus), SEEK_SET); + fwrite(&menus, sizeof(menus), 1, tmp); + } + } + fseek(tmp, (too -1) * sizeof(menus), SEEK_SET); + fwrite(&tmenus, sizeof(menus), 1, tmp); + MenuUpdated = TRUE; + } + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o += 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o -= 10; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = (atoi(pick) - 1) * sizeof(menus); + fseek(tmp, offset, SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + crc = 0xffffffff; + crc = upd_crc32((char *)&menus, crc, sizeof(menus)); + Edit_A_Menu(); + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&menus, crc1, sizeof(menus)); + if (crc1 != crc) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + fseek(tmp, offset, SEEK_SET); + fwrite(&menus, sizeof(menus), 1, tmp); + MenuUpdated = TRUE; + working(0, 0, 0); + } + } + } + } +} + + + +void EditMenus(void) +{ + int Lang, mcount, err, i, x, y; + DIR *dp; + FILE *fil; + struct dirent *de; + char menuname[50][11]; + char temp[81], pick[12], *p; + + Syslog('+', "Start menu edit"); + memset(&menuname, 0, sizeof(menuname)); + Lang = PickLanguage((char *)"8.3"); + if (Lang == '\0') + return; + + for (;;) { + clr_index(); + mcount = 0; + if ((dp = opendir(lang.MenuPath)) != NULL) { + working(1, 0, 0); + + while ((de = readdir(dp))) { + if (de->d_name[0] != '.') { + strcpy(menuname[mcount], strtok(de->d_name, ".")); + mcount++; + } + } + closedir(dp); + working(0, 0, 0); + } + + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.3 MENU EDIT: %s", lang.Name); + set_color(CYAN, BLACK); + + if (mcount) { + x = 6; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= mcount; i++) { + sprintf(temp, "%2d. %s", i, menuname[i-1]); + mvprintw(y, x, temp); + y++; + if ((i % 10) == 0) { + x+=15; + y = 7; + } + } + } + strcpy(pick, select_record(mcount, 50)); + + if (strncmp(pick, "-", 1) == 0) { + Syslog('+', "Finished menu edit"); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + set_color(WHITE, BLACK); + mvprintw(LINES -3, 6, (char *)"New menu name >"); + memset(&temp, 0, sizeof(temp)); + strcpy(temp, edit_str(LINES -3, 22, 10, temp, (char *)"Enter a new ^menu^ name without extension")); + if (strlen(temp)) { + p = xstrcpy(lang.MenuPath); + p = xstrcat(p, (char *)"/"); + p = xstrcat(p, temp); + p = xstrcat(p, (char *)".mnu"); + if ((err = file_exist(p, F_OK))) { + if ((fil = fopen(p, "a")) == NULL) { + errmsg("Can't create menu %s", temp); + } else { + fclose(fil); + Syslog('+', "Created menufile %s", p); + } + } else { + errmsg("Menu %s already exists", temp); + } + free(p); + } + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= mcount)) + EditMenu(menuname[atoi(pick) -1]); + } +} + + + +int bbs_menu_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no, *mn; + DIR *dp; + struct dirent *de; + int j; + + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 8, 3, page, (char *)"BBS Menus"); + + fread(&langhdr, sizeof(langhdr), 1, no); + j =0; + + while ((fread(&lang, langhdr.recsize, 1, no)) == 1) { + if ((dp = opendir(lang.MenuPath)) != NULL) { + while ((de = readdir(dp))) { + if (de->d_name[0] != '.') { + j = 0; + sprintf(temp, "%s/%s", lang.MenuPath, de->d_name); + fprintf(fp, " MENU %s (%s)\n\n", de->d_name, lang.Name); + if ((mn = fopen(temp, "r")) != NULL) { + while (fread(&menus, sizeof(menus), 1, mn) == 1) { + if (menus.MenuKey[0]) + fprintf(fp, " Menu select %s\n", menus.MenuKey); + if (menus.AutoExec) + fprintf(fp, " Menu select Autoexec\n"); + fprintf(fp, " Type %d %s\n", menus.MenuType, menus.TypeDesc); + fprintf(fp, " Opt. data %s\n", menus.OptionalData); + fprintf(fp, " Display %s\n", menus.Display); + fprintf(fp, " Security %s\n", get_secstr(menus.MenuSecurity)); + fprintf(fp, " Minimum age %d\n", menus.Age); + fprintf(fp, " Maximum level %d\n", menus.MaxSecurity); + fprintf(fp, " Password %s\n", menus.Password); + fprintf(fp, " Credits %ld\n", menus.Credit); + if (menus.MenuType == 7) { + fprintf(fp, " No door.sys %s\n", getboolean(menus.NoDoorsys)); + fprintf(fp, " Y2K door.sys %s\n", getboolean(menus.Y2Kdoorsys)); + fprintf(fp, " Use COM port %s\n", getboolean(menus.Comport)); + } + fprintf(fp, "\n\n"); + j++; + if (j == 5) { + j = 0; + page = newpage(fp, page); + } + } + fclose(mn); + } + if (j) + page = newpage(fp, page); + } + } + closedir(dp); + } + } + + fclose(no); + return page; +} + + + diff --git a/mbsetup/m_menu.h b/mbsetup/m_menu.h new file mode 100644 index 00000000..55fc2e8c --- /dev/null +++ b/mbsetup/m_menu.h @@ -0,0 +1,9 @@ +#ifndef _M_MENU_H +#define _M_MENU_H + +char *select_menurec(int); +void EditMenus(void); +int bbs_menu_doc(FILE *, FILE*, int); + +#endif + diff --git a/mbsetup/m_mgroup.c b/mbsetup/m_mgroup.c new file mode 100644 index 00000000..43dfd7ca --- /dev/null +++ b/mbsetup/m_mgroup.c @@ -0,0 +1,570 @@ +/***************************************************************************** + * + * File ..................: setup/m_mgroups.c + * Purpose ...............: Setup MGroups. + * Last modification date : 12-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_node.h" +#include "m_marea.h" +#include "m_mgroup.h" + + + +int MGrpUpdated = 0; + + +/* + * Count nr of mgroup records in the database. + * Creates the database if it doesn't exist. + */ +int CountMGroup(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + mgrouphdr.hdrsize = sizeof(mgrouphdr); + mgrouphdr.recsize = sizeof(mgroup); + fwrite(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&mgrouphdr, mgrouphdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - mgrouphdr.hdrsize) / mgrouphdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenMGroup(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + MGrpUpdated = 0; + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&mgrouphdr, mgrouphdr.hdrsize, 1, fin); + if (mgrouphdr.hdrsize != sizeof(mgrouphdr)) { + mgrouphdr.hdrsize = sizeof(mgrouphdr); + mgrouphdr.lastupd = time(NULL); + MGrpUpdated = 1; + } + + /* + * In case we are automaitc upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = mgrouphdr.recsize; + if (oldsize != sizeof(mgroup)) + MGrpUpdated = 1; + mgrouphdr.hdrsize = sizeof(mgrouphdr); + mgrouphdr.recsize = sizeof(mgroup); + fwrite(&mgrouphdr, sizeof(mgrouphdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&mgroup, 0, sizeof(mgroup)); + while (fread(&mgroup, oldsize, 1, fin) == 1) { + fwrite(&mgroup, sizeof(mgroup), 1, fout); + memset(&mgroup, 0, sizeof(mgroup)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseMGroup(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *mgr = NULL, *tmp; + + sprintf(fin, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + + if (MGrpUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&mgrouphdr, mgrouphdr.hdrsize, 1, fi); + fwrite(&mgrouphdr, mgrouphdr.hdrsize, 1, fo); + + while (fread(&mgroup, mgrouphdr.recsize, 1, fi) == 1) + if (!mgroup.Deleted) + fill_stlist(&mgr, mgroup.Name, ftell(fi) - mgrouphdr.recsize); + sort_stlist(&mgr); + + for (tmp = mgr; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&mgroup, mgrouphdr.recsize, 1, fi); + fwrite(&mgroup, mgrouphdr.recsize, 1, fo); + } + + tidy_stlist(&mgr); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"mgroups.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendMGroup(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&mgroup, 0, sizeof(mgroup)); + time(&mgroup.StartDate); + fwrite(&mgroup, sizeof(mgroup), 1, fil); + fclose(fil); + MGrpUpdated = 1; + return 0; + } else + return -1; +} + + + +void MgScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "9.1 EDIT MESSAGE GROUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Name"); + mvprintw( 8, 6, "2. Comment"); + mvprintw( 9, 6, "3. Active"); + mvprintw(10, 6, "4. Use Aka"); + mvprintw(11, 6, "5. Uplink"); + mvprintw(12, 6, "6. Areas"); + mvprintw(13, 6, "7. Deleted"); +} + + + +/* + * Check if field can be edited without screwing up the database. + */ +int CheckMgroup(void); +int CheckMgroup(void) +{ + int ncnt, mcnt; + + working(1, 0, 0); + ncnt = GroupInNode(mgroup.Name, TRUE); + mcnt = GroupInMarea(mgroup.Name); + working(0, 0, 0); + if (ncnt || mcnt) { + errmsg((char *)"Error, %d node(s) and/or %d message area(s) connected", ncnt, mcnt); + return TRUE; + } + return FALSE; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditMGrpRec(int Area) +{ + FILE *fil; + static char mfile[PATH_MAX]; + static long offset; + static int j, tmp; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit MessageGroup"); + + sprintf(mfile, "%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(mgrouphdr) + ((Area -1) * sizeof(mgroup)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&mgroup, sizeof(mgroup), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&mgroup, crc, sizeof(mgroup)); + working(0, 0, 0); + MgScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,18,12, mgroup.Name); + show_str( 8,18,55, mgroup.Comment); + show_bool( 9,18, mgroup.Active); + show_aka( 10,18, mgroup.UseAka); + show_aka( 11,18, mgroup.UpLink); + show_str( 12,18,12, mgroup.AreaFile); + show_bool(13,18, mgroup.Deleted); + + j = select_menu(7); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&mgroup, crc1, sizeof(mgroup)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + WriteError("$Can't reopen %s", mfile); + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&mgroup, sizeof(mgroup), 1, fil); + fclose(fil); + MGrpUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: if (CheckMgroup()) + break; + E_UPS( 7,18,12,mgroup.Name,"The ^name^ for this message group") + case 2: E_STR( 8,18,55,mgroup.Comment,"The ^desription^ for this message group") + case 3: if (CheckMgroup()) + break; + E_BOOL(9,18, mgroup.Active, "Is this message group ^active^") + case 4: tmp = PickAka((char *)"9.1.4", TRUE); + if (tmp != -1) + memcpy(&mgroup.UseAka, &CFG.aka[tmp], sizeof(fidoaddr)); + MgScreen(); + break; + case 5: mgroup.UpLink = PullUplink((char *)"9.1.5"); + MgScreen(); + break; + case 6: E_STR(12,18,12,mgroup.AreaFile,"The name of the ^Areas File^ from the uplink") + case 7: if (CheckMgroup()) + break; + E_BOOL(13,18, mgroup.Deleted, "Is this group ^Deleted^") + } + } + + return 0; +} + + + +void EditMGroup(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountMGroup(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenMGroup() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "9.1 MESSAGE GROUPS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11 ) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(mgrouphdr) + (((o + i) - 1) * mgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&mgroup, mgrouphdr.recsize, 1, fil); + if (mgroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, mgroup.Name, mgroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseMGroup(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendMGroup() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditMGrpRec(atoi(pick)); + } +} + + + +char *PickMGroup(char *shdr) +{ + static char MGrp[21] = ""; + int records, i, o = 0, y, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return MGrp; + } + + records = CountMGroup(); + if (records == -1) { + working(2, 0, 0); + return MGrp; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. MESSAGE GROUP SELECT", shdr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(mgrouphdr) + (((o + i) - 1) * mgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&mgroup, mgrouphdr.recsize, 1, fil); + if (mgroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, mgroup.Name, mgroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return MGrp; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + fil = fopen(temp, "r"); + offset = sizeof(mgrouphdr) + ((atoi(pick) - 1) * mgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&mgroup, mgrouphdr.recsize, 1, fil); + fclose(fil); + strcpy(MGrp, mgroup.Name); + return MGrp; + } + } +} + + + +int mail_group_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + addtoc(fp, toc, 9, 1, page, (char *)"Mail processing groups"); + j = 0; + fprintf(fp, "\n\n"); + + fread(&mgrouphdr, sizeof(mgrouphdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&mgrouphdr, mgrouphdr.hdrsize, 1, no); + + while ((fread(&mgroup, mgrouphdr.recsize, 1, no)) == 1) { + if (j == 3) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Name %s\n", mgroup.Name); + fprintf(fp, " Comment %s\n", mgroup.Comment); + fprintf(fp, " Active %s\n", getboolean(mgroup.Active)); + fprintf(fp, " Use Aka %s\n", aka2str(mgroup.UseAka)); + fprintf(fp, " Uplink %s\n", aka2str(mgroup.UpLink)); + fprintf(fp, " Areas file %s\n", mgroup.AreaFile); + fprintf(fp, " Start date %s", ctime(&mgroup.StartDate)); + fprintf(fp, " Last date %s\n", ctime(&mgroup.LastDate)); + +// fprintf(fp, " Total This month Last month\n"); +// fprintf(fp, " ---------- ---------- ----------\n"); +// fprintf(fp, " Messages %-10ld %-10ld %-10ld\n", mgroup.Total.files, mgroup.ThisMonth.files, mgroup.LastMonth.files); +// fprintf(fp, " Kilobytes %-10ld %-10ld %-10ld\n", mgroup.Total.kbytes, mgroup.ThisMonth.kbytes, mgroup.LastMonth.kbytes); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_mgroup.h b/mbsetup/m_mgroup.h new file mode 100644 index 00000000..6999af0b --- /dev/null +++ b/mbsetup/m_mgroup.h @@ -0,0 +1,12 @@ +#ifndef _MGROUP_H +#define _MGROUP_H + + +int CountMGroup(void); +void EditMGroup(void); +char *PickMGroup(char *); +int mail_group_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_modem.c b/mbsetup/m_modem.c new file mode 100644 index 00000000..e572dd6f --- /dev/null +++ b/mbsetup/m_modem.c @@ -0,0 +1,716 @@ +/***************************************************************************** + * + * File ..................: setup/m_modem.c + * Purpose ...............: Setup Modem structure. + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_modem.h" + + + +int ModemUpdated = 0; + + +/* + * Count nr of modem records in the database. + * Creates the database if it doesn't exist. + */ +int CountModem(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/modem.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + modemhdr.hdrsize = sizeof(modemhdr); + modemhdr.recsize = sizeof(modem); + fwrite(&modemhdr, sizeof(modemhdr), 1, fil); + + /* + * Create some default modem types + */ + memset(&modem, 0, sizeof(modem)); + sprintf(modem.modem, "Dynalink 1428EXTRA"); + sprintf(modem.init[0], "AT Z\\r"); + sprintf(modem.init[1], "AT &F &C1 &D2 X4 W2 B0 M0 \\\\V1 \\\\G0 &K3 S37=0\\r"); + sprintf(modem.ok, "OK"); + sprintf(modem.dial, "ATDT\\T\\r"); + sprintf(modem.connect[0], "CONNECT 33600"); + sprintf(modem.connect[1], "CONNECT 31200"); + sprintf(modem.connect[2], "CONNECT 28800"); + sprintf(modem.connect[3], "CONNECT 26400"); + sprintf(modem.connect[4], "CONNECT 24000"); + sprintf(modem.connect[5], "CONNECT 21600"); + sprintf(modem.connect[6], "CONNECT 19200"); + sprintf(modem.connect[7], "CONNECT 16800"); + sprintf(modem.connect[8], "CONNECT 14400"); + sprintf(modem.connect[9], "CONNECT 12000"); + sprintf(modem.connect[10], "CONNECT 9600"); + sprintf(modem.connect[11], "CONNECT 7200"); + sprintf(modem.connect[12], "CONNECT 4800"); + sprintf(modem.connect[13], "CONNECT 2400"); + sprintf(modem.connect[14], "CONNECT 1200"); + sprintf(modem.connect[15], "CONNECT 300"); + sprintf(modem.reset, "AT&F&C1&D2X4W2B0M0&K3\\r"); + sprintf(modem.error[0], "BUSY"); + sprintf(modem.error[1], "NO CARRIER"); + sprintf(modem.error[2], "NO DIALTONE"); + sprintf(modem.error[3], "NO ANSWER"); + sprintf(modem.error[4], "RING\\r"); + sprintf(modem.error[5], "ERROR"); + sprintf(modem.error[6], "CONNECT VOICE"); + sprintf(modem.speed, "28800"); + modem.available = TRUE; + modem.costoffset = 6; + fwrite(&modem, sizeof(modem), 1, fil); + + sprintf(modem.modem, "ISDN Dynalink"); + sprintf(modem.init[0], "ATZ\\r"); + sprintf(modem.init[1], "AT&E3306018793\\r"); + sprintf(modem.init[2], "AT&B512\\r"); + sprintf(modem.hangup, "ATH0\\r"); + sprintf(modem.speed, "64000"); + modem.costoffset = 1; + fwrite(&modem, sizeof(modem), 1, fil); + + sprintf(modem.modem, "Standard Hayes V34"); + sprintf(modem.init[0], "ATZ\\r"); + memset(&modem.init[1], 0, sizeof(modem.init[1])); + memset(&modem.init[2], 0, sizeof(modem.init[2])); + memset(&modem.hangup, 0, sizeof(modem.hangup)); + sprintf(modem.speed, "33600"); + modem.costoffset = 6; + fwrite(&modem, sizeof(modem), 1, fil); + + memset(&modem, 0, sizeof(modem)); + sprintf(modem.modem, "ISDN Linux"); + sprintf(modem.init[0], "AT Z\\r"); + sprintf(modem.ok, "OK"); + sprintf(modem.dial, "ATDT\\T\\r"); + sprintf(modem.info, "ATI2\\r"); + sprintf(modem.hangup, "\\d\\p\\p\\p+++\\d\\p\\p\\pATH0\\r"); + sprintf(modem.connect[0], "CONNECT 64000"); + sprintf(modem.connect[1], "CONNECT"); + sprintf(modem.error[0], "BUSY"); + sprintf(modem.error[1], "NO CARRIER"); + sprintf(modem.error[2], "NO DIALTONE"); + sprintf(modem.error[3], "NO ANSWER"); + sprintf(modem.error[4], "RING\\r"); + sprintf(modem.error[5], "ERROR"); + sprintf(modem.speed, "64000"); + modem.available = TRUE; + modem.costoffset = 1; + fwrite(&modem, sizeof(modem), 1, fil); + + fclose(fil); + return 4; + } else + return -1; + } + + fread(&modemhdr, sizeof(modemhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - modemhdr.hdrsize) / modemhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenModem(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/modem.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/modem.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&modemhdr, sizeof(modemhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = modemhdr.recsize; + if (oldsize != sizeof(modem)) + ModemUpdated = 1; + else + ModemUpdated = 0; + modemhdr.hdrsize = sizeof(modemhdr); + modemhdr.recsize = sizeof(modem); + fwrite(&modemhdr, sizeof(modemhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&modem, 0, sizeof(modem)); + while (fread(&modem, oldsize, 1, fin) == 1) { + fwrite(&modem, sizeof(modem), 1, fout); + memset(&modem, 0, sizeof(modem)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseModem(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *mdm = NULL, *tmp; + + sprintf(fin, "%s/etc/modem.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/modem.temp", getenv("MBSE_ROOT")); + + if (ModemUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&modemhdr, modemhdr.hdrsize, 1, fi); + fwrite(&modemhdr, modemhdr.hdrsize, 1, fo); + + while (fread(&modem, modemhdr.recsize, 1, fi) == 1) + if (!modem.deleted) + fill_stlist(&mdm, modem.modem, ftell(fi) - modemhdr.recsize); + sort_stlist(&mdm); + + for (tmp = mdm; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&modem, modemhdr.recsize, 1, fi); + fwrite(&modem, modemhdr.recsize, 1, fo); + } + + tidy_stlist(&mdm); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"modem.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendModem(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/modem.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&modem, 0, sizeof(modem)); + sprintf(modem.init[0], "ATZ\\r"); + sprintf(modem.ok, "OK"); + sprintf(modem.dial, "ATDT\\T\\r"); + sprintf(modem.connect[0], "CONNECT 33600"); + sprintf(modem.connect[1], "CONNECT 31200"); + sprintf(modem.connect[2], "CONNECT 28800"); + sprintf(modem.connect[3], "CONNECT 26400"); + sprintf(modem.connect[4], "CONNECT 24000"); + sprintf(modem.connect[5], "CONNECT 21600"); + sprintf(modem.connect[6], "CONNECT 19200"); + sprintf(modem.connect[7], "CONNECT 16800"); + sprintf(modem.connect[8], "CONNECT 14400"); + sprintf(modem.connect[9], "CONNECT 12000"); + sprintf(modem.connect[10], "CONNECT 9600"); + sprintf(modem.connect[11], "CONNECT 7200"); + sprintf(modem.connect[12], "CONNECT 4800"); + sprintf(modem.connect[13], "CONNECT 2400"); + sprintf(modem.connect[14], "CONNECT 1200"); + sprintf(modem.connect[15], "CONNECT 300"); + sprintf(modem.error[0], "BUSY"); + sprintf(modem.error[1], "NO CARRIER"); + sprintf(modem.error[2], "NO DIALTONE"); + sprintf(modem.error[3], "NO ANSWER"); + sprintf(modem.error[4], "RING\\r"); + sprintf(modem.error[5], "ERROR"); + sprintf(modem.speed, "28800"); + sprintf(modem.reset, "AT\\r"); + modem.available = TRUE; + fwrite(&modem, sizeof(modem), 1, fil); + fclose(fil); + ModemUpdated = 1; + return 0; + } else + return -1; +} + + + +void Modem_Screen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "5. EDIT MODEM TYPE"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Type"); + mvprintw( 8, 2, "2. Init 1"); + mvprintw( 9, 2, "3. Init 2"); + mvprintw(10, 2, "4. Init 3"); + mvprintw(11, 2, "5. Reset"); + mvprintw(12, 2, "6. Hangup"); + mvprintw(13, 2, "7. Dial"); + mvprintw(14, 2, "8. Info"); + mvprintw(15, 2, "9. Ok"); + mvprintw(16, 2, "10. Offset"); + mvprintw(17, 2, "11. Speed"); + + mvprintw(15,30, "12. Available"); + mvprintw(16,30, "13. Deleted"); + mvprintw(17,30, "14. Stripdash"); + + mvprintw(15,58, "15. Connect strings"); + mvprintw(16,58, "16. Error strings"); +} + + + +void EditConnect(void) +{ + int i, j; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "5.15 EDIT MODEM CONNECT STRINGS"); + set_color(CYAN, BLACK); + + for (i = 0; i < 10; i++) { + mvprintw( 7+i, 2, (char *)"%2d.", i+1); + mvprintw( 7+i,42, (char *)"%2d.", i+11); + } + + for (;;) { + set_color(WHITE, BLACK); + for (i = 0; i < 10; i++) { + show_str( 7+i, 8, 30, modem.connect[i]); + show_str( 7+i,48, 30, modem.connect[i+10]); + } + + j = select_menu(20); + if (j == 0) + return; + if (j < 11) + strcpy(modem.connect[j-1], edit_str(6+j, 8,30, modem.connect[j-1], (char *)"^Connect^ string")); + else + strcpy(modem.connect[j-1], edit_str(j-4,48,30, modem.connect[j-1], (char *)"^Connect^ string")); + } +} + + + +void EditError(void) +{ + int i, j; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "5.16 EDIT MODEM ERROR STRINGS"); + set_color(CYAN, BLACK); + + for (i = 0; i < 10; i++) { + mvprintw( 7+i, 2, (char *)"%2d.", i+1); + } + + for (;;) { + set_color(WHITE, BLACK); + for (i = 0; i < 10; i++) { + show_str( 7+i, 8, 20, modem.error[i]); + } + + j = select_menu(10); + if (j == 0) + return; + strcpy(modem.error[j-1], edit_str(6+j, 8,20, modem.error[j-1], (char *)"^Error^ string")); + } +} + + + +int EditModemRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Modem"); + + sprintf(mfile, "%s/etc/modem.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(modemhdr) + ((Area -1) * sizeof(modem)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&modem, sizeof(modem), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&modem, crc, sizeof(modem)); + working(0, 0, 0); + Modem_Screen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,14,30, modem.modem); + show_str( 8,14,60, modem.init[0]); + show_str( 9,14,60, modem.init[1]); + show_str(10,14,60, modem.init[2]); + show_str(11,14,60, modem.reset); + show_str(12,14,40, modem.hangup); + show_str(13,14,40, modem.dial); + show_str(14,14,40, modem.info); + show_str(15,14,10, modem.ok); + show_int(16,14, modem.costoffset); + show_str(17,14,15, modem.speed); + + show_bool(15,44, modem.available); + show_bool(16,44, modem.deleted); + show_bool(17,44, modem.stripdash); + + j = select_menu(16); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&modem, crc1, sizeof(modem)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&modem, sizeof(modem), 1, fil); + fclose(fil); + ModemUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,14,30, modem.modem, "The ^Type^ or brand of this modem") + case 2: E_STR( 8,14,60, modem.init[0], "The ^first init^ string for this modem") + case 3: E_STR( 9,14,60, modem.init[1], "The ^second init^ string for this modem") + case 4: E_STR(10,14,60, modem.init[2], "The ^third init^ string for this modem") + case 5: E_STR(11,14,60, modem.reset, "The ^reset^ string for this modem") + case 6: E_STR(12,14,40, modem.hangup, "The ^hangup^ string for this modem (Leave empty for ^DTR-drop^ hangup)") + case 7: E_STR(13,14,40, modem.dial, "The ^dial^ command for this modem, ^\\T^ is translated phonenumber") + case 8: E_STR(14,14,40, modem.info, "The command to get connection ^info^ from this modem after call") + case 9: E_STR(15,14,10, modem.ok, "The ^OK^ string to get from the modem") + case 10:E_INT(16,14, modem.costoffset, "The ^offset^ time in seconds between answer and connect string") + case 11:E_STR(17,14,15, modem.speed, "The ^EMSI speed^ message for this modem") + case 12:E_BOOL(15,44, modem.available, "If this modem is ^available^") + case 13:E_BOOL(16,44, modem.deleted, "If this modem is to be ^deleted^ from the setup") + case 14:E_BOOL(17,44, modem.stripdash, "Stript ^dashes (-)^ from dial command strings if this modem needs it") + case 15: + EditConnect(); + Modem_Screen(); + break; + case 16: + EditError(); + Modem_Screen(); + break; + } + } + + return 0; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +void EditModem(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountModem(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenModem() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "5. MODEM TYPES SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/modem.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&modemhdr, sizeof(modemhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(modemhdr) + ((i - 1) * modemhdr.recsize); + fseek(fil, offset, 0); + fread(&modem, modemhdr.recsize, 1, fil); + if (i == 11) { + x = 42; + y = 7; + } + if (modem.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-30s", i, modem.modem); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + /* Show records here */ + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseModem(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendModem() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditModemRec(atoi(pick)); + } +} + + + +char *PickModem(char *shdr) +{ + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + static char buf[31]; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return '\0'; + } + + records = CountModem(); + if (records == -1) { + working(2, 0, 0); + return '\0'; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. MODEM SELECT", shdr); + mvprintw(5,3,temp); + set_color(CYAN, BLACK); + if (records) { + sprintf(temp, "%s/etc/modem.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&modemhdr, sizeof(modemhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(modemhdr) + (((o + i) - 1) * modemhdr.recsize); + fseek(fil, offset, SEEK_SET); + fread(&modem, modemhdr.recsize, 1, fil); + if (modem.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-31s", o + i, modem.modem); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return '\0'; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o += 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o -= 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/modem.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + offset = modemhdr.hdrsize + ((atoi(pick) - 1) * modemhdr.recsize); + fseek(fil, offset, SEEK_SET); + fread(&modem, modemhdr.recsize, 1, fil); + fclose(fil); + if (modem.available) { + sprintf(buf, "%s", modem.modem); + return buf; + } + } + } + } +} + + + +int modem_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *mdm; + int i, j; + + sprintf(temp, "%s/etc/modem.data", getenv("MBSE_ROOT")); + if ((mdm = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 5, 0, page, (char *)"Modem types information"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&modemhdr, sizeof(modemhdr), 1, mdm); + + while ((fread(&modem, modemhdr.recsize, 1, mdm)) == 1) { + if (j == 1) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Modem type %s\n", modem.modem); + for (i = 0; i < 3; i++) + fprintf(fp, " Init string %s\n", modem.init[i]); + fprintf(fp, " OK string %s\n", modem.ok); + fprintf(fp, " Hangup %s\n", modem.hangup); + fprintf(fp, " Info command %s\n", modem.info); + fprintf(fp, " Dial command %s\n", modem.dial); + for (i = 0; i < 20; i++) + fprintf(fp, " Connect %s\n", modem.connect[i]); + fprintf(fp, " Reset cmd %s\n", modem.reset); + for (i = 0; i < 10; i++) + fprintf(fp, " Error string %s\n", modem.error[i]); + fprintf(fp, " Cost offset %d\n", modem.costoffset); + fprintf(fp, " EMSI speed %s\n", modem.speed); + fprintf(fp, " Strip dashes %s\n", getboolean(modem.stripdash)); + fprintf(fp, " Available %s\n", getboolean(modem.available)); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(mdm); + return page; +} + + diff --git a/mbsetup/m_modem.h b/mbsetup/m_modem.h new file mode 100644 index 00000000..e24ad3ab --- /dev/null +++ b/mbsetup/m_modem.h @@ -0,0 +1,11 @@ +#ifndef _MODEM_H +#define _MODEM_H + + +int CountModem(void); +void EditModem(void); +char *PickModem(char *); +int modem_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_new.c b/mbsetup/m_new.c new file mode 100644 index 00000000..557f35d2 --- /dev/null +++ b/mbsetup/m_new.c @@ -0,0 +1,556 @@ +/***************************************************************************** + * + * File ..................: m_fnewfiles.c + * Purpose ...............: Newfiles Setup + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "grlist.h" +#include "m_new.h" +#include "m_lang.h" +#include "m_marea.h" +#include "m_ngroup.h" + + +int NewUpdated = 0; + + +/* + * Count nr of newfiles records in the database. + * Creates the database if it doesn't exist. + */ +int CountNewfiles(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + newfileshdr.hdrsize = sizeof(newfileshdr); + newfileshdr.recsize = sizeof(newfiles); + newfileshdr.grpsize = CFG.new_groups * 13; + fwrite(&newfileshdr, sizeof(newfileshdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&newfileshdr, sizeof(newfileshdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - newfileshdr.hdrsize) / (newfileshdr.recsize + newfileshdr.grpsize); + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenNewfiles(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + int i, old_groups; + long oldgroup; + char group[13]; + + sprintf(fnin, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&newfileshdr, sizeof(newfileshdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = newfileshdr.recsize; + oldgroup = newfileshdr.grpsize; + old_groups = oldgroup / 13; + if ((oldsize != sizeof(newfiles)) || (CFG.new_groups != old_groups)) + NewUpdated = 1; + else + NewUpdated = 0; + newfileshdr.hdrsize = sizeof(newfileshdr); + newfileshdr.recsize = sizeof(newfiles); + newfileshdr.grpsize = CFG.new_groups * 13; + fwrite(&newfileshdr, sizeof(newfileshdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&newfiles, 0, sizeof(newfiles)); + while (fread(&newfiles, oldsize, 1, fin) == 1) { + fwrite(&newfiles, sizeof(newfiles), 1, fout); + memset(&newfiles, 0, sizeof(newfiles)); + /* + * Copy the existing groups + */ + for (i = 1; i <= old_groups; i++) { + fread(&group, 13, 1, fin); + if (i <= CFG.new_groups) + fwrite(&group, 13, 1, fout); + } + if (old_groups < CFG.new_groups) { + /* + * The size increased, fill with + * blank records. + */ + memset(&group, 0, 13); + for (i = (old_groups + 1); i <= CFG.new_groups; i++) + fwrite(&group, 13, 1, fout); + } + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseNewfiles(void) +{ + char fin[81], fout[81], group[13]; + FILE *fi, *fo; + st_list *new = NULL, *tmp; + int i; + + sprintf(fin, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + + if (NewUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&newfileshdr, newfileshdr.hdrsize, 1, fi); + fwrite(&newfileshdr, newfileshdr.hdrsize, 1, fo); + + while (fread(&newfiles, newfileshdr.recsize, 1, fi) == 1) { + if (!newfiles.Deleted) + fill_stlist(&new, newfiles.Comment, ftell(fi) - newfileshdr.recsize); + fseek(fi, newfileshdr.grpsize, SEEK_CUR); + } + sort_stlist(&new); + + for (tmp = new; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&newfiles, newfileshdr.recsize, 1, fi); + fwrite(&newfiles, newfileshdr.recsize, 1, fo); + for (i = 0; i < (newfileshdr.grpsize / sizeof(group)); i++) { + fread(&group, sizeof(group), 1, fi); + fwrite(&group, sizeof(group), 1, fo); + } + } + + fclose(fi); + fclose(fo); + tidy_stlist(&new); + unlink(fout); + Syslog('+', "Updated \"newfiles.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendNewfiles(void) +{ + FILE *fil; + char ffile[81], group[13]; + int i; + + sprintf(ffile, "%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&newfiles, 0, sizeof(newfiles)); + /* + * Fill in default values + */ + sprintf(newfiles.From, "%s", CFG.sysop_name); + fwrite(&newfiles, sizeof(newfiles), 1, fil); + memset(&group, 0, 13); + for (i = 1; i <= CFG.new_groups; i++) + fwrite(&group, 13, 1, fil); + fclose(fil); + NewUpdated = 1; + return 0; + } else + return -1; +} + + + +void NewScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "12. EDIT NEW FILES REPORTS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Comment"); + mvprintw( 8, 2, "2. Msg area"); + mvprintw( 9, 2, "3. Origin line"); + mvprintw(10, 2, "4. From name"); + mvprintw(11, 2, "5. To name"); + mvprintw(12, 2, "6. Subject"); + mvprintw(13, 2, "7. Language"); + mvprintw(14, 2, "8. Template"); + mvprintw(15, 2, "9. Aka to use"); + mvprintw(16, 2, "10. Active"); + mvprintw(17, 2, "11. Deleted"); + mvprintw(16,42, "12. High ASCII"); + mvprintw(17,42, "13. New groups"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditNewRec(int Area) +{ + FILE *fil; + char mfile[81], temp1[2]; + long offset; + unsigned long crc, crc1; + gr_list *fgr = NULL, *tmp; + char group[13]; + int groups, i, j, GrpChanged = FALSE; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Newfiles"); + + sprintf(mfile, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) != NULL) { + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + + while (fread(&ngroup, ngrouphdr.recsize, 1, fil) == 1) + fill_grlist(&fgr, ngroup.Name); + + fclose(fil); + sort_grlist(&fgr); + } + + sprintf(mfile, "%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + tidy_grlist(&fgr); + return -1; + } + + fread(&newfileshdr, sizeof(newfileshdr), 1, fil); + offset = newfileshdr.hdrsize + ((Area -1) * (newfileshdr.recsize + newfileshdr.grpsize)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + tidy_grlist(&fgr); + return -1; + } + + fread(&newfiles, newfileshdr.recsize, 1, fil); + groups = newfileshdr.grpsize / 13; + + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, fil); + if (strlen(group)) { + Syslog('+', "New group %s", group); + for (tmp = fgr; tmp; tmp = tmp->next) + if (!strcmp(tmp->group, group)) + tmp->tagged = TRUE; + } + } + + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&newfiles, crc, newfileshdr.recsize); + working(0, 0, 0); + + for (;;) { + NewScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,55, newfiles.Comment); + show_str( 8,18,50, newfiles.Area); + show_str( 9,18,50, newfiles.Origin); + show_str( 10,18,35, newfiles.From); + show_str( 11,18,35, newfiles.Too); + show_str( 12,18,60, newfiles.Subject); + sprintf(temp1, "%c", newfiles.Language); + show_str( 13,18,2, temp1); + show_str( 14,18,14, newfiles.Template); + show_str( 15,18,35, aka2str(newfiles.UseAka)); + show_bool(16,18, newfiles.Active); + show_bool(17,18, newfiles.Deleted); + show_bool(16,58, newfiles.HiAscii); + i = 0; + for (tmp = fgr; tmp; tmp = tmp->next) + if (tmp->tagged) + i++; + show_int( 17,58, i); + + switch(select_menu(13)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&newfiles, crc1, newfileshdr.recsize); + if ((crc != crc1) || GrpChanged) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&newfiles, newfileshdr.recsize, 1, fil); + + groups = newfileshdr.grpsize / 13; + i = 0; + for (tmp = fgr; tmp; tmp = tmp->next) + if (tmp->tagged) { + i++; + memset(&group, 0, 13); + sprintf(group, "%s", tmp->group); + fwrite(&group, 13, 1, fil); + } + Syslog('+', "Written %d out of %d entries", i, groups); + + memset(&group, 0, 13); + for (j = i; j < groups; j++) + fwrite(&group, 13, 1, fil); + + fclose(fil); + NewUpdated = 1; + working(0, 0, 0); + } + } + tidy_grlist(&fgr); + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,55, newfiles.Comment, "The ^comment^ for this area") + case 2: strcpy(newfiles.Area, PickMsgarea((char *)"12.2")); + break; + case 3: E_STR( 9,18,50, newfiles.Origin, "The ^origin line^ to append, leave blank for random lines") + case 4: E_STR( 10,18,35, newfiles.From, "The ^From^ name to appear above the messages") + case 5: E_STR( 11,18,35, newfiles.Too, "The ^To^ name to appear above the messages") + case 6: E_STR( 12,18,60, newfiles.Subject, "The ^Subject^ of the messages") + case 7: newfiles.Language = PickLanguage((char *)"12.7"); + break; + case 8: E_STR( 14,18,14, newfiles.Template, "The ^template^ file to use for the report") + case 9: i = PickAka((char *)"12.9", TRUE); + if (i != -1) + newfiles.UseAka = CFG.aka[i]; + break; + case 10:E_BOOL(16,18, newfiles.Active, "If this report is ^active^") + case 11:E_BOOL(17,18, newfiles.Deleted, "Is this record ^deleted^") + case 12:E_BOOL(16,58, newfiles.HiAscii, "Allow ^High ASCII^ in this report") + case 13:if (E_Group(&fgr, (char *)"12.12 NEWFILE GROUPS")) + GrpChanged = TRUE; + break; + } + } +} + + + +void EditNewfiles(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountNewfiles(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenNewfiles() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "12. NEWFILES REPORTS"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&newfileshdr, sizeof(newfileshdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(newfileshdr) + (((o + i) - 1) * (newfileshdr.recsize + newfileshdr.grpsize)); + fseek(fil, offset, 0); + fread(&newfiles, newfileshdr.recsize, 1, fil); + if (newfiles.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, newfiles.Comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseNewfiles(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendNewfiles() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditNewRec(atoi(pick)); + } +} + + + +int new_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81], group[13]; + FILE *no; + int groups, i, j; + + sprintf(temp, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 12, 0, page, (char *)"Newfiles reports"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&newfileshdr, sizeof(newfileshdr), 1, no); + + while ((fread(&newfiles, newfileshdr.recsize, 1, no)) == 1) { + + if (j == 3) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Area comment %s\n", newfiles.Comment); + fprintf(fp, " Message area %s\n", newfiles.Area); + fprintf(fp, " Origin line %s\n", newfiles.Origin); + fprintf(fp, " From name %s\n", newfiles.From); + fprintf(fp, " To name %s\n", newfiles.Too); + fprintf(fp, " Subject %s\n", newfiles.Subject); + fprintf(fp, " Language %c\n", newfiles.Language); + fprintf(fp, " Aka to use %s\n", aka2str(newfiles.UseAka)); + fprintf(fp, " Active %s\n", getboolean(newfiles.Active)); + fprintf(fp, " Allow High ASCII %s\n", getboolean(newfiles.HiAscii)); + fprintf(fp, "\n File groups:\n "); + groups = newfileshdr.grpsize / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group)) { + fprintf(fp, "%-12s ", group); + if (((i+1) %5) == 0) + fprintf(fp, "\n "); + } + } + if ((i+1) % 5) + fprintf(fp, "\n"); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_new.h b/mbsetup/m_new.h new file mode 100644 index 00000000..d80ed79b --- /dev/null +++ b/mbsetup/m_new.h @@ -0,0 +1,10 @@ +#ifndef _NEW_H +#define _NEW_H + + +int CountNewfiles(void); +void EditNewfiles(void); +int new_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_ngroup.c b/mbsetup/m_ngroup.c new file mode 100644 index 00000000..665d2d8c --- /dev/null +++ b/mbsetup/m_ngroup.c @@ -0,0 +1,513 @@ +/***************************************************************************** + * + * File ..................: setup/m_ngroups.c + * Purpose ...............: Setup NGroups. + * Last modification date : 28-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_ngroup.h" + + + +int NGrpUpdated = 0; + + +/* + * Count nr of ngroup records in the database. + * Creates the database if it doesn't exist. + */ +int CountNGroup(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + ngrouphdr.hdrsize = sizeof(ngrouphdr); + ngrouphdr.recsize = sizeof(ngroup); + fwrite(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&ngrouphdr, ngrouphdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - ngrouphdr.hdrsize) / ngrouphdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenNGroup(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + NGrpUpdated = 0; + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&ngrouphdr, ngrouphdr.hdrsize, 1, fin); + if (ngrouphdr.hdrsize != sizeof(ngrouphdr)) { + ngrouphdr.hdrsize = sizeof(ngrouphdr); + NGrpUpdated = 1; + } + + /* + * In case we are automaitc upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = ngrouphdr.recsize; + if (oldsize != sizeof(ngroup)) + NGrpUpdated = 1; + ngrouphdr.hdrsize = sizeof(ngrouphdr); + ngrouphdr.recsize = sizeof(ngroup); + fwrite(&ngrouphdr, sizeof(ngrouphdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&ngroup, 0, sizeof(ngroup)); + while (fread(&ngroup, oldsize, 1, fin) == 1) { + fwrite(&ngroup, sizeof(ngroup), 1, fout); + memset(&ngroup, 0, sizeof(ngroup)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseNGroup(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *mgr = NULL, *tmp; + + sprintf(fin, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + + if (NGrpUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&ngrouphdr, ngrouphdr.hdrsize, 1, fi); + fwrite(&ngrouphdr, ngrouphdr.hdrsize, 1, fo); + + while (fread(&ngroup, ngrouphdr.recsize, 1, fi) == 1) + if (!ngroup.Deleted) + fill_stlist(&mgr, ngroup.Name, ftell(fi) - ngrouphdr.recsize); + sort_stlist(&mgr); + + for (tmp = mgr; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&ngroup, ngrouphdr.recsize, 1, fi); + fwrite(&ngroup, ngrouphdr.recsize, 1, fo); + } + + tidy_stlist(&mgr); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"ngroups.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendNGroup(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&ngroup, 0, sizeof(ngroup)); + fwrite(&ngroup, sizeof(ngroup), 1, fil); + fclose(fil); + NGrpUpdated = 1; + return 0; + } else + return -1; +} + + + +void NgScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "9.1 EDIT NEWFILES GROUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Name"); + mvprintw( 8, 6, "2. Comment"); + mvprintw( 9, 6, "3. Active"); + mvprintw(10, 6, "4. Deleted"); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditNGrpRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit NewfileGroup"); + + sprintf(mfile, "%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(ngrouphdr) + ((Area -1) * sizeof(ngroup)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&ngroup, sizeof(ngroup), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&ngroup, crc, sizeof(ngroup)); + working(0, 0, 0); + NgScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,18,12, ngroup.Name); + show_str( 8,18,55, ngroup.Comment); + show_bool( 9,18, ngroup.Active); + show_bool(10,18, ngroup.Deleted); + + j = select_menu(4); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&ngroup, crc1, sizeof(ngroup)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&ngroup, sizeof(ngroup), 1, fil); + fclose(fil); + NGrpUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_UPS( 7,18,12,ngroup.Name,"The ^name^ for this message group") + case 2: E_STR( 8,18,55,ngroup.Comment,"The ^desription^ for this message group") + case 3: E_BOOL(9,18, ngroup.Active, "Is this message group ^active^") + case 4: E_BOOL(10,18, ngroup.Deleted, "Is this group ^Deleted^") + } + } + + return 0; +} + + + +void EditNGroup(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountNGroup(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenNGroup() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "11. NEWFILES GROUPS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11 ) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(ngrouphdr) + (((o + i) - 1) * ngrouphdr.recsize); + fseek(fil, offset, 0); + fread(&ngroup, ngrouphdr.recsize, 1, fil); + if (ngroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, ngroup.Name, ngroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseNGroup(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendNGroup() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditNGrpRec(atoi(pick)); + } +} + + + +char *PickNGroup(char *shdr) +{ + static char MGrp[21] = ""; + int records, i, o = 0, y, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return MGrp; + } + + records = CountNGroup(); + if (records == -1) { + working(2, 0, 0); + return MGrp; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. NEWFILES GROUP SELECT", shdr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(ngrouphdr) + (((o + i) - 1) * ngrouphdr.recsize); + fseek(fil, offset, 0); + fread(&ngroup, ngrouphdr.recsize, 1, fil); + if (ngroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, ngroup.Name, ngroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return MGrp; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + fil = fopen(temp, "r"); + offset = sizeof(ngrouphdr) + ((atoi(pick) - 1) * ngrouphdr.recsize); + fseek(fil, offset, 0); + fread(&ngroup, ngrouphdr.recsize, 1, fil); + fclose(fil); + strcpy(MGrp, ngroup.Name); + return MGrp; + } + } +} + + + +int newf_group_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + addtoc(fp, toc, 11, 0, page, (char *)"Newfiles announce groups"); + j = 0; + fprintf(fp, "\n\n"); + + fread(&ngrouphdr, sizeof(ngrouphdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&ngrouphdr, ngrouphdr.hdrsize, 1, no); + + while ((fread(&ngroup, ngrouphdr.recsize, 1, no)) == 1) { + if (j == 7) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Name %s\n", ngroup.Name); + fprintf(fp, " Comment %s\n", ngroup.Comment); + fprintf(fp, " Active %s\n", getboolean(ngroup.Active)); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_ngroup.h b/mbsetup/m_ngroup.h new file mode 100644 index 00000000..272fef91 --- /dev/null +++ b/mbsetup/m_ngroup.h @@ -0,0 +1,12 @@ +#ifndef _NGROUP_H +#define _NGROUP_H + + +int CountNGroup(void); +void EditNGroup(void); +char *PickNGroup(char *); +int newf_group_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_node.c b/mbsetup/m_node.c new file mode 100644 index 00000000..ece9aabf --- /dev/null +++ b/mbsetup/m_node.c @@ -0,0 +1,1209 @@ +/***************************************************************************** + * + * File ..................: m_node.c + * Purpose ...............: Nodes Setup Program + * Last modification date : 30-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "grlist.h" +#include "stlist.h" +#include "m_global.h" +#include "m_lang.h" +#include "m_ticarea.h" +#include "m_marea.h" +#include "m_node.h" + + +int NodeUpdated = 0; + + +/* + * Count nr of nodes records in the database. + * Creates the database if it doesn't exist. + */ +int CountNoderec(void); +int CountNoderec(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + nodeshdr.hdrsize = sizeof(nodeshdr); + nodeshdr.recsize = sizeof(nodes); + nodeshdr.filegrp = CFG.tic_groups * 13; + nodeshdr.mailgrp = CFG.toss_groups * 13; + fwrite(&nodeshdr, sizeof(nodeshdr), 1, fil); + fclose(fil); + Syslog('+', "Created nodes.data"); + return 0; + } else + return -1; + } + + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&nodeshdr, nodeshdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - nodeshdr.hdrsize) / (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp); + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenNoderec(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + char group[13]; + long oldsize; + int i, old_fgroups, old_mgroups; + long oldfilegrp, oldmailgrp; + + sprintf(fnin, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/nodes.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + Syslog('+', "Opened nodes.data"); + NodeUpdated = 0; + fread(&nodeshdr, sizeof(nodeshdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&nodeshdr, nodeshdr.hdrsize, 1, fin); + if (nodeshdr.hdrsize != sizeof(nodeshdr)) { + nodeshdr.hdrsize = sizeof(nodeshdr); + nodeshdr.lastupd = time(NULL); + NodeUpdated = 1; + } + + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = nodeshdr.recsize; + oldfilegrp = nodeshdr.filegrp; + oldmailgrp = nodeshdr.mailgrp; + old_fgroups = oldfilegrp / 13; + old_mgroups = oldmailgrp / 13; + if ((oldsize != sizeof(nodes) || + (CFG.tic_groups != old_fgroups) || + (CFG.toss_groups != old_mgroups))) { + NodeUpdated = 1; + Syslog('+', "nodes.data nr of groups is changed"); + } + nodeshdr.hdrsize = sizeof(nodeshdr); + nodeshdr.recsize = sizeof(nodes); + nodeshdr.filegrp = CFG.tic_groups * 13; + nodeshdr.mailgrp = CFG.toss_groups * 13; + fwrite(&nodeshdr, sizeof(nodeshdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&nodes, 0, sizeof(nodes)); + while (fread(&nodes, oldsize, 1, fin) == 1) { + fwrite(&nodes, sizeof(nodes), 1, fout); + memset(&nodes, 0, sizeof(nodes)); + /* + * Copy the existing file groups + */ + for (i = 1; i <= old_fgroups; i++) { + fread(&group, 13, 1, fin); + if (i <= CFG.tic_groups) + fwrite(&group, 13, 1, fout); + } + if (old_fgroups < CFG.tic_groups) { + /* + * The size increased, fill with + * blank records + */ + memset(&group, 0, 13); + for (i = (old_fgroups + 1); i <= CFG.tic_groups; i++) + fwrite(&group, 13, 1, fout); + } + /* + * Copy the existing mail groups + */ + for (i = 1; i <= old_mgroups; i++) { + fread(&group, 13, 1, fin); + if (i <= CFG.toss_groups) + fwrite(&group, 13, 1, fout); + } + if (old_mgroups < CFG.toss_groups) { + memset(&group, 0, 13); + for (i = (old_mgroups + 1); i <= CFG.toss_groups; i++) + fwrite(&group, 13, 1, fout); + } + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseNoderec(int Force) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + int i; + char group[13]; + st_list *nod = NULL, *tmp; + + sprintf(fin, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/nodes.temp", getenv("MBSE_ROOT")); + + if (NodeUpdated == 1) { + if (Force || (yes_no((char *)"Nodes database is changed, save changes") == 1)) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&nodeshdr, nodeshdr.hdrsize, 1, fi); + fwrite(&nodeshdr, nodeshdr.hdrsize, 1, fo); + + while (fread(&nodes, nodeshdr.recsize, 1, fi) == 1) { + if (!nodes.Deleted) + fill_stlist(&nod, nodes.Sysop, ftell(fi) - nodeshdr.recsize); + fseek(fi, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + } + sort_stlist(&nod); + + for (tmp = nod; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&nodes, nodeshdr.recsize, 1, fi); + fwrite(&nodes, nodeshdr.recsize, 1, fo); + for (i = 0; i < ((nodeshdr.filegrp + nodeshdr.mailgrp) / sizeof(group)); i++) { + fread(&group, sizeof(group), 1, fi); + fwrite(&group, sizeof(group), 1, fo); + } + } + + tidy_stlist(&nod); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"nodes.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendNoderec(void); +int AppendNoderec(void) +{ + FILE *fil; + char ffile[81]; + char group[13]; + int i; + + sprintf(ffile, "%s/etc/nodes.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&nodes, 0, sizeof(nodes)); + /* + * Fill in the defaults + */ + nodes.Tic = TRUE; + nodes.Notify = FALSE; + nodes.AdvTic = FALSE; + nodes.Hold = TRUE; + nodes.ARCmailCompat = TRUE; + nodes.ARCmailAlpha = TRUE; + nodes.StartDate = time(NULL); + fwrite(&nodes, sizeof(nodes), 1, fil); + memset(&group, 0, 13); + for (i = 1; i <= CFG.tic_groups; i++) + fwrite(&group, 13, 1, fil); + for (i = 1; i <= CFG.toss_groups; i++) + fwrite(&group, 13, 1, fil); + fclose(fil); + NodeUpdated = 1; + return 0; + } else + return -1; +} + + + +int GroupInNode(char *Group, int Mail) +{ + char temp[128], group[13]; + FILE *no; + int i, groups, Area = 0, RetVal = 0; + + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return FALSE; + + fread(&nodeshdr, sizeof(nodeshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&nodeshdr, nodeshdr.hdrsize, 1, no); + + while ((fread(&nodes, nodeshdr.recsize, 1, no)) == 1) { + Area++; + groups = nodeshdr.filegrp / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group) && !Mail) { + if (!strcmp(group, Group)) { + RetVal++; + Syslog('-', "File group %s in %d: %s", Group, Area, aka2str(nodes.Aka[0])); + } + } + } + groups = nodeshdr.mailgrp / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group) && Mail) { + if (!strcmp(group, Group)) { + RetVal++; + Syslog('-', "Mail group %s found in %d: %s", Group, Area, aka2str(nodes.Aka[0])); + } + } + } + } + + fclose(no); + return RetVal; +} + + + +int CheckAka(fidoaddr); +int CheckAka(fidoaddr A) +{ + int mcnt, tcnt; + + working(1, 0, 0); + mcnt = NodeInMarea(A); + tcnt = NodeInTic(A); + working(0, 0, 0); + if (mcnt || tcnt) { + errmsg((char *)"Error aka connected to %d message and/or %d tic areas", mcnt, tcnt); + return TRUE; + } + return FALSE; +} + + + +void E_Mail(void); +void E_Mail(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "7.14 EDIT NODE - MAIL PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Session pwd"); + mvprintw( 8, 6, "2. Check PKT pwd"); + mvprintw( 9, 6, "3. UplMgr program"); + mvprintw(10, 6, "4. UplMgr passwd"); + mvprintw(11, 6, "5. Mail forward"); + mvprintw(12, 6, "6. ARCmail comp."); + mvprintw(13, 6, "7. ARCmail a..z"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,25,15, (char *)"***************"); + show_bool(8,25, nodes.MailPwdCheck); + show_str( 9,25, 8, nodes.UplAmgrPgm); + show_str(10,25,15, (char *)"***************"); + show_bool(11,25, nodes.MailFwd); + show_bool(12,25, nodes.ARCmailCompat); + show_bool(13,25, nodes.ARCmailAlpha); + + switch(select_menu(7)) { + case 0: return; + case 1: E_STR( 7,25,15,nodes.Epasswd, "The ^Session/Mail password^ for this node") + case 2: E_BOOL( 8,25, nodes.MailPwdCheck, "Check the ^mail PKT^ password") + case 3: E_STR( 9,25, 8,nodes.UplAmgrPgm, "Name of the uplink ^areamanager program^") + case 4: E_STR( 10,25,15,nodes.UplAmgrPass, "Uplink ^areamanager password^ for this node") + case 5: E_BOOL(11,25, nodes.MailFwd, "^Forward^ echomail for this node") + case 6: E_BOOL(12,25, nodes.ARCmailCompat, "Use ^ARCmail 0.60^ file naming convention for out of zone mail") + case 7: E_BOOL(13,25, nodes.ARCmailAlpha, "Allow ^0..9 and a..z^ filename extensions for ARCmail archives") + } + } +} + + + +void E_Files(void); +void E_Files(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "7.16 EDIT NODE - FILES PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Files password"); + mvprintw( 8, 6, "2. Mgr password"); + mvprintw( 9, 6, "3. UplMgr program"); + mvprintw(10, 6, "4. UplMgr passwd"); + mvprintw(11, 6, "5. UplMgr Add +"); + mvprintw(12, 6, "6. Incl. message"); + mvprintw(13, 6, "7. Send TIC file"); + mvprintw(14, 6, "8. Advanced TIC"); + mvprintw(15, 6, "9. File forward"); + mvprintw(16, 6, "10. Billing"); + mvprintw( 7,46, "11. Bill direct"); + mvprintw( 8,46, "12. Credit"); + mvprintw( 9,46, "13. Debet"); + mvprintw(10,46, "14. Add %"); + mvprintw(11,46, "15. Warn level"); + mvprintw(12,46, "16. Stop level"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,25,15, (char *)"***************"); + show_str( 8,25,15, (char *)"***************"); + show_str( 9,25, 8, nodes.UplFmgrPgm); + show_str(10,25,15, (char *)"***************"); + show_bool(11,25, nodes.AddPlus); + show_bool(12,25, nodes.Message); + show_bool(13,25, nodes.Tic); + show_bool(14,25, nodes.AdvTic); + show_bool(15,25, nodes.FileFwd); + show_bool(16,25, nodes.Billing); + show_bool( 7,65, nodes.BillDirect); + show_int( 8,65, nodes.Credit); + show_int( 9,65, nodes.Debet); + show_int(10,65, nodes.AddPerc); + show_int(11,65, nodes.WarnLevel); + show_int(12,65, nodes.StopLevel); + + switch(select_menu(16)) { + case 0: return; + case 1: E_STR( 7,25,15,nodes.Fpasswd, "The ^TIC^ files ^password^ for this node") + case 2: E_STR( 8,25,15,nodes.Apasswd, "The filemanager ^password^ for this node") + case 3: E_STR( 9,25,8, nodes.UplFmgrPgm, "The name of the uplink ^filemanager^ program") + case 4: E_STR( 10,25,15,nodes.UplFmgrPass,"The uplink filemanager ^password^") + case 5: E_BOOL(11,25, nodes.AddPlus, "Add ^+^ in uplink manager requests for new areas") + case 6: E_BOOL(12,25, nodes.Message, "Send ^messages^ with files send to this node") + case 7: E_BOOL(13,25, nodes.Tic, "Send ^TIC^ files to this node") + case 8: E_BOOL(14,25, nodes.AdvTic, "Send ^advanced^ TIC files to this node") + case 9: E_BOOL(15,25, nodes.FileFwd, "^Forward TIC^ files for this node") + case 10:E_BOOL(16,25, nodes.Billing, "Send ^bills^ to this node") + case 11:E_BOOL( 7,65, nodes.BillDirect, "Send bills ^direct^ after file processing") + case 12:E_INT( 8,65, nodes.Credit, "The ^credit^ this node has for costsharing") + case 13:E_INT( 9,65, nodes.Debet, "The ^debet^ in cents we have credit from this node") + case 14:E_INT( 10,65, nodes.AddPerc, "The + or - ^promille^ factor for this node") + case 15:E_INT( 11,65, nodes.WarnLevel, "Credit level in cents to ^Warn^ node for low credit") + case 16:E_INT( 12,65, nodes.StopLevel, "Credit level in cents to ^Stop^ sending files") + } + } +} + + + +void S_Stat(void); +void S_Stat(void) +{ + time_t Now; + struct tm *t; + int LMiy; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 7, "7.18 NODE STATISTICS"); + set_color(CYAN, BLACK); + mvprintw( 8,18, " This week Last week This month Last month Total"); + mvprintw( 9,18, "---------- ---------- ---------- ---------- ----------"); + mvprintw(10,6, "Files sent"); + mvprintw(11,6, "Kbytes sent"); + mvprintw(12,6, "Files rcvd"); + mvprintw(13,6, "Kbytes rcvd"); + mvprintw(14,6, "Mail sent"); + mvprintw(15,6, "Mail rcvd"); + set_color(WHITE, BLACK); + + Now = time(NULL); + t = localtime(&Now); + + Diw = t->tm_wday; + Miy = t->tm_mon; + if (Miy == 0) + LMiy = 11; + else + LMiy = Miy - 1; + + mvprintw(10,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.FilesSent.tweek, nodes.FilesSent.lweek, nodes.FilesSent.month[Miy], nodes.FilesSent.month[LMiy], nodes.FilesSent.total); + mvprintw(11,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.F_KbSent.tweek, nodes.F_KbSent.lweek, nodes.F_KbSent.month[Miy], nodes.F_KbSent.month[LMiy], nodes.F_KbSent.total); + mvprintw(12,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.FilesRcvd.tweek, nodes.FilesRcvd.lweek, nodes.FilesRcvd.month[Miy], nodes.FilesRcvd.month[LMiy], nodes.FilesRcvd.total); + mvprintw(13,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.F_KbRcvd.tweek, nodes.F_KbRcvd.lweek, nodes.F_KbRcvd.month[Miy], nodes.F_KbRcvd.month[LMiy], nodes.F_KbRcvd.total); + mvprintw(14,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.MailSent.tweek, nodes.MailSent.lweek, nodes.MailSent.month[Miy], nodes.MailSent.month[LMiy], nodes.MailSent.total); + mvprintw(15,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.MailRcvd.tweek, nodes.MailRcvd.lweek, nodes.MailRcvd.month[Miy], nodes.MailRcvd.month[LMiy], nodes.MailRcvd.total); + set_color(CYAN, BLACK); + center_addstr(LINES - 4, (char *)"Press any key"); + readkey(LINES - 4, COLS / 2 + 8, LIGHTGRAY, BLACK); +} + + + +fidoaddr e_a(fidoaddr, int); +fidoaddr e_a(fidoaddr n, int x) +{ + FILE *fil; + char temp[81]; + int i; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, (char *)"7.%d EDIT AKA", x); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Zone"); + mvprintw( 8, 6, "2. Net"); + mvprintw( 9, 6, "3. Node"); + mvprintw(10, 6, "4. Point"); + mvprintw(11, 6, " Domain"); + set_color(WHITE, BLACK); + show_int( 7,17, n.zone); + show_int( 8,17, n.net); + show_int( 9,17, n.node); + show_int(10,17, n.point); + show_str(11,17,12, n.domain); + + switch(select_menu(4)) { + case 0: return n; + case 1: n.zone = edit_int(7, 17, n.zone, (char *)"The ^zone^ number 1..4095"); + sprintf(temp, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + + while (fread(&fidonet, fidonethdr.recsize, 1, fil) == 1) { + if (fidonet.available) { + for (i = 0; i < 6; i++) { + if (fidonet.zone[i] == n.zone) { + memset(&n.domain, 0, sizeof(n.domain)); + strcpy(n.domain, fidonet.domain); + } + } + } + } + fclose(fil); + } + break; + case 2: E_INT( 8,17,n.net, "The ^net^ number 1..65535") + case 3: E_INT( 9,17,n.node, "The ^node^ number 1..65535") + case 4: E_INT(10,17,n.point,"The ^point^ number 0..65535") + } + } +} + + + +void N_Akas(void) +{ + int i, j, m, x, y; + fidoaddr a[20]; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "7.2 EDIT NODES AKA'S"); + set_color(CYAN, BLACK); + y = 7; x = 6; + for (i = 0; i < 20; i++) { + if (i == 10) { + y = 7; x = 46; + } + mvprintw( y, x, (char *)"%d.", i + 1); + if (nodes.Aka[i].zone) + mvprintw(y, x + 5, (char *)"%s", aka2str(nodes.Aka[i])); + y++; + } + + m = select_menu(20); + switch(m) { + case 0: + /* + * Pack the aka's + */ + for (i = 0; i < 20; i++) { + a[i] = nodes.Aka[i]; + memset(&nodes.Aka[i], 0, sizeof(fidoaddr)); + } + j = 0; + for (i = 0; i < 20; i++) { + if (a[i].zone) { + nodes.Aka[j] = a[i]; + j++; + } + } + return; + + default: + if (! CheckAka(nodes.Aka[m - 1])) + nodes.Aka[m - 1] = e_a(nodes.Aka[m - 1], 2); + break; + } + + } +} + + + +void NScreen(void); +void NScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "7. EDIT NODE"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Sysop name"); + mvprintw( 8, 2, "2. Fido aka's"); + mvprintw( 9, 2, "3. Dial command"); + mvprintw(10, 2, "4. Phone number 1"); + mvprintw(11, 2, "5. Phone number 2"); + mvprintw(12, 2, "6. Route via"); + mvprintw(13, 2, "7. Netmail direct"); + mvprintw(14, 2, "8. Netmail crash"); + mvprintw(15, 2, "9. Netmail hold"); + mvprintw(16, 2, "10. Pack netmail"); + mvprintw(17, 2, "11. Send notify"); + mvprintw(18, 2, "12. Language"); + mvprintw(19, 2, "13. Deleted"); + + mvprintw(14,31, "14. Mail setup"); + mvprintw(15,31, "15. Mail groups"); + mvprintw(16,31, "16. File setup"); + mvprintw(17,31, "17. File groups"); + mvprintw(18,31, "18. Statistics"); + mvprintw(19,31, "19. No EMSI"); + + mvprintw(10,51, "20. No YooHoo/2U2"); + mvprintw(11,51, "21. No Filerequest"); + mvprintw(12,51, "22. Don't call"); + mvprintw(13,51, "23. No Hold mail"); + mvprintw(14,51, "24. Pickup primary"); + mvprintw(15,51, "25. No Zmodem"); + mvprintw(16,51, "26. No Zedzap"); + mvprintw(17,51, "27. No Hydra"); + mvprintw(18,51, "28. No TCP/IP"); + mvprintw(19,51, "29. Force FNC"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditNodeRec(int); +int EditNodeRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + unsigned long crc, crc1; + gr_list *fgr = NULL, *egr = NULL, *tmp; + char group[13]; + int count, groups, i, j, GrpChanged = FALSE; + char *temp, temp1[32]; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Fido Node"); + + sprintf(mfile, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + + while (fread(&mgroup, mgrouphdr.recsize, 1, fil) == 1) + fill_grlist(&egr, mgroup.Name); + + fclose(fil); + sort_grlist(&egr); + } + + sprintf(mfile, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + + while (fread(&fgroup, fgrouphdr.recsize, 1, fil) == 1) + fill_grlist(&fgr, fgroup.Name); + + fclose(fil); + sort_grlist(&fgr); + } + + sprintf(mfile, "%s/etc/nodes.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + tidy_grlist(&egr); + tidy_grlist(&fgr); + return -1; + } + + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + offset = nodeshdr.hdrsize + ((Area -1) * (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + tidy_grlist(&egr); + tidy_grlist(&fgr); + return -1; + } + + fread(&nodes, nodeshdr.recsize, 1, fil); + groups = nodeshdr.filegrp / 13; + + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, fil); + if (strlen(group)) { + for (tmp = fgr; tmp; tmp = tmp->next) + if (!strcmp(tmp->group, group)) + tmp->tagged = TRUE; + } + } + + groups = nodeshdr.mailgrp / 13; + + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, fil); + if (strlen(group)) { + for (tmp = egr; tmp; tmp = tmp->next) + if (!strcmp(tmp->group, group)) + tmp->tagged = TRUE; + } + } + + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&nodes, crc, nodeshdr.recsize); + working(0, 0, 0); + NScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,21,35, nodes.Sysop); + temp = xstrcpy((char *)""); + for (i = 0; i < 7; i++) { + if (nodes.Aka[i].zone) { + if (nodes.Aka[i].point) + sprintf(temp1, "%d:%d/%d.%d ", nodes.Aka[i].zone, nodes.Aka[i].net, nodes.Aka[i].node, nodes.Aka[i].point); + else + sprintf(temp1, "%d:%d/%d ", nodes.Aka[i].zone, nodes.Aka[i].net, nodes.Aka[i].node); + temp = xstrcat(temp, temp1); + } + } + show_str( 8,21,58, temp); + free(temp); + show_str( 9,21,40, nodes.dial); + show_str(10,21,20, nodes.phone[0]); + show_str(11,21,20, nodes.phone[1]); + if (nodes.RouteVia.zone) + show_aka(12,21,nodes.RouteVia); + show_bool(13,21, nodes.Direct); + show_bool(14,21, nodes.Crash); + show_bool(15,21, nodes.Hold); + show_bool(16,21, nodes.PackNetmail); + show_bool(17,21, nodes.Notify); + sprintf(temp1, "%c", nodes.Language); + show_str(18,21,1, temp1); + show_bool(19,21, nodes.Deleted); + show_bool(19,47, nodes.NoEMSI); + show_bool(10,70, nodes.NoWaZOO); + show_bool(11,70, nodes.NoFreqs); + show_bool(12,70, nodes.NoCall); + show_bool(13,70, nodes.NoHold); + show_bool(14,70, nodes.NoPUA); + show_bool(15,70, nodes.NoZmodem); + show_bool(16,70, nodes.NoZedzap); + show_bool(17,70, nodes.NoHydra); + show_bool(18,70, nodes.NoTCP); + show_bool(19,70, nodes.FNC); + + switch(select_menu(29)) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&nodes, crc1, nodeshdr.recsize); + if ((crc != crc1) || GrpChanged) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + Syslog('+', "Updated node record %s", nodes.Sysop); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&nodes, nodeshdr.recsize, 1, fil); + + groups = nodeshdr.filegrp / 13; + i = 0; + for (tmp = fgr; tmp; tmp = tmp->next) + if (tmp->tagged) { + i++; + memset(&group, 0, 13); + sprintf(group, "%s", tmp->group); + fwrite(&group, 13, 1, fil); + } + + memset(&group, 0, sizeof(group)); + for (j = i; j < groups; j++) + fwrite(&group, 13, 1, fil); + + groups = nodeshdr.mailgrp / 13; + i = 0; + for (tmp = egr; tmp; tmp = tmp->next) + if (tmp->tagged) { + i++; + memset(&group, 0, 13); + sprintf(group, "%s", tmp->group); + fwrite(&group, 13, 1, fil); + } + + memset(&group, 0, sizeof(group)); + for (j = i; j < groups; j++) + fwrite(&group, 13, 1, fil); + + fclose(fil); + NodeUpdated = 1; + working(0, 0, 0); + } + } + tidy_grlist(&egr); + tidy_grlist(&fgr); + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR(7,21,35, nodes.Sysop, "The name of the ^sysop^ for this node") + case 2: N_Akas(); NScreen(); break; + case 3: E_STR( 9,21,40, nodes.dial, "If needed, give a special modem ^dial command^ for this node") + case 4: E_STR(10,21,20, nodes.phone[0], "Enter ^phone number^ to override the nodelist") + case 5: E_STR(11,21,20, nodes.phone[1], "Enter ^phone number^ to override the nodelist") + case 6: nodes.RouteVia = e_a(nodes.RouteVia, 6); NScreen(); break; + case 7: E_BOOL(13,21, nodes.Direct, "Set the ^direct^ flag on netmail") + case 8: nodes.Crash = edit_bool(14,21, nodes.Crash, (char *)"Set the ^crash^ flags for this node"); + if (nodes.Crash) + nodes.Hold = FALSE; + break; + case 9: nodes.Hold = edit_bool(15,21, nodes.Hold, (char *)"Set the ^hold^ flag for this node"); + if (nodes.Hold) + nodes.Crash = FALSE; + break; + case 10:E_BOOL(16,21, nodes.PackNetmail, "^Pack netmail^ for this node") + case 11:E_BOOL(17,21, nodes.Notify, "Send ^notify^ messages to this node") + case 12:nodes.Language = PickLanguage((char *)"7.12"); NScreen(); break; + case 13:count = 0; + working(1, 0, 0); + for (i = 0; i < 20; i++) + if (nodes.Aka[i].zone) + count += NodeInMarea(nodes.Aka[i]); + if (count) { + working(0, 0, 0); + errmsg((char *)"Node is connected to %d message areas", count); + break; + } + count = 0; + for (i = 0; i < 20; i++) + if (nodes.Aka[i].zone) + count += NodeInTic(nodes.Aka[i]); + working(0, 0, 0); + if (count) { + errmsg((char *)"Node is connected to %d tic areas", count); + break; + } + E_BOOL(19,21, nodes.Deleted, "Is this node ^Deleted^") + case 14:E_Mail(); NScreen(); break; + case 15:if (E_Group(&egr, (char *)"7.15 MAIL GROUPS")) + GrpChanged = TRUE; + NScreen(); break; + case 16:E_Files(); + NScreen(); break; + case 17:if (E_Group(&fgr, (char *)"7.17 FILE GROUPS")) + GrpChanged = TRUE; + NScreen(); break; + case 18:S_Stat(); NScreen(); break; + case 19:E_BOOL(19,47, nodes.NoEMSI, "Disable ^EMSI handshake^ with this node") + case 20:E_BOOL(10,70, nodes.NoWaZOO, "Disable ^YooHoo/2U2 handshake^ (FTSC-0006) with this node") + case 21:E_BOOL(11,70, nodes.NoFreqs, "Disallow ^file requests^ from this node") + case 22:E_BOOL(12,70, nodes.NoCall, "Don't ^call^ this node") + case 23:E_BOOL(13,70, nodes.NoHold, "Don't ^hold hold-mail^ when we call (no = only pickup)") + case 24:E_BOOL(14,70, nodes.NoPUA, "Only pickup mail from the ^primary^ address") + case 25:E_BOOL(15,70, nodes.NoZmodem, "Disable ^Zmodem^ protocol with this node") + case 26:E_BOOL(16,70, nodes.NoZedzap, "Disable ^Zedzap^ protocol with this node") + case 27:E_BOOL(17,70, nodes.NoHydra, "Disable ^Hydra^ protocol with this node") + case 28:E_BOOL(18,70, nodes.NoTCP, "Disable ^TCP/IP^ protocol whith this node") + case 29:E_BOOL(19,70, nodes.FNC, "Force ^FileName Conversion^ during binkp sessions"); + } + } +} + + + +void EditNodes(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountNoderec(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenNoderec() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "7. NODES SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/nodes.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(nodeshdr) + (((o + i) - 1) * (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)); + fseek(fil, offset, 0); + fread(&nodes, nodeshdr.recsize, 1, fil); + if (strlen(nodes.Sysop)) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s (%s)", o + i, nodes.Sysop, strtok(aka2str(nodes.Aka[0]), "@")); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseNoderec(FALSE); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendNoderec() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditNodeRec(atoi(pick)); + } +} + + + +fidoaddr PullUplink(char *Hdr) +{ + static fidoaddr uplink; + int records, m, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + memset(&uplink, 0, sizeof(uplink)); + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return uplink; + } + + records = CountNoderec(); + if (records == -1) { + working(2, 0, 0); + return uplink; + } + + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "%s. UPLINK SELECT", Hdr); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(nodeshdr) + (((o + i) - 1) * (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)); + fseek(fil, offset, 0); + fread(&nodes, nodeshdr.recsize, 1, fil); + if (strlen(nodes.Sysop)) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s (%s)", o + i, nodes.Sysop, strtok(aka2str(nodes.Aka[0]), "@")); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return uplink; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + fseek(fil, ((atoi(pick) -1) * (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)) + nodeshdr.hdrsize, SEEK_SET); + if (fread(&nodes, nodeshdr.recsize, 1, fil) != 1) { + fclose(fil); + return uplink; + } + fclose(fil); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "%s. SELECT NODE AKA", Hdr); + set_color(CYAN, BLACK); + y = 7; x = 6; + for (i = 0; i < 20; i++) { + if (i == 10) { + y = 7; x = 46; + } + mvprintw( y, x, (char *)"%d.", i + 1); + if (nodes.Aka[i].zone) + mvprintw(y, x + 5, (char *)"%s", aka2str(nodes.Aka[i])); + y++; + } + + m = select_menu(20); + switch(m) { + case 0: + return uplink; + + default: + uplink = nodes.Aka[m - 1]; + return uplink; + } + + } + } + return uplink; + } + } +} + + + +int node_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int groups, i, First = TRUE; + char group[13]; + + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + fread(&nodeshdr, sizeof(nodeshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&nodeshdr, nodeshdr.hdrsize, 1, no); + + while ((fread(&nodes, nodeshdr.recsize, 1, no)) == 1) { + + page = newpage(fp, page); + + if (First) { + addtoc(fp, toc, 7, 0, page, (char *)"Fidonet nodes"); + First = FALSE; + fprintf(fp, "\n"); + } else + fprintf(fp, "\n\n"); + + fprintf(fp, " Sysop %s\n", nodes.Sysop); + fprintf(fp, " First date %s", ctime(&nodes.StartDate)); + fprintf(fp, " Last date %s\n", ctime(&nodes.LastDate)); + for (i = 0; i < 20; i++) + if (nodes.Aka[i].zone) + fprintf(fp, " Aka %2d %s\n", i+1, aka2str(nodes.Aka[i])); + if (nodes.RouteVia.zone) + fprintf(fp, " Route via %s\n", aka2str(nodes.RouteVia)); + + fprintf(fp, " Language %c\n", nodes.Language); + fprintf(fp, " Files passwd %s\n", nodes.Fpasswd); + fprintf(fp, " Session pwd %s\n", nodes.Epasswd); + fprintf(fp, " Areamgr pwd %s\n\n", nodes.Apasswd); + + fprintf(fp, " Uplink mgrs Program Password\n"); + fprintf(fp, " ------------ --------- ---------------\n"); + fprintf(fp, " Files %s %s\n", padleft(nodes.UplFmgrPgm, 9, ' '), nodes.UplFmgrPass); + fprintf(fp, " Mail %s %s\n\n", padleft(nodes.UplAmgrPgm, 9, ' '), nodes.UplAmgrPass); + + fprintf(fp, " Mail direct %s", getboolean(nodes.Direct)); + fprintf(fp, " Mail crash %s", getboolean(nodes.Crash)); + fprintf(fp, " Mail hold %s\n", getboolean(nodes.Hold)); + fprintf(fp, " Send message %s", getboolean(nodes.Message)); + fprintf(fp, " Send .TIC %s", getboolean(nodes.Tic)); + fprintf(fp, " Send notify %s\n", getboolean(nodes.Notify)); + fprintf(fp, " File forward %s", getboolean(nodes.FileFwd)); + fprintf(fp, " Mail forward %s", getboolean(nodes.MailFwd)); + fprintf(fp, " Advanced TIC %s\n", getboolean(nodes.AdvTic)); + fprintf(fp, " Billing %s", getboolean(nodes.Billing)); + fprintf(fp, " Bill direct %s", getboolean(nodes.BillDirect)); + fprintf(fp, " Uplink add + %s\n", getboolean(nodes.AddPlus)); + fprintf(fp, " Check mailpwd %s", getboolean(nodes.MailPwdCheck)); + fprintf(fp, " No EMSI %s", getboolean(nodes.NoEMSI)); + fprintf(fp, " No YooHoo/2U2 %s\n", getboolean(nodes.NoWaZOO)); + fprintf(fp, " No Requests %s", getboolean(nodes.NoFreqs)); + fprintf(fp, " Don't call %s", getboolean(nodes.NoCall)); + fprintf(fp, " No hold mail %s\n", getboolean(nodes.NoHold)); + fprintf(fp, " No Pickup all %s", getboolean(nodes.NoPUA)); + fprintf(fp, " No Zmodem %s", getboolean(nodes.NoZmodem)); + fprintf(fp, " No Zedzap %s\n", getboolean(nodes.NoZedzap)); + fprintf(fp, " No Hydra %s", getboolean(nodes.NoHydra)); + fprintf(fp, " No TCP/IP %s", getboolean(nodes.NoTCP)); + fprintf(fp, " Force FNC %s\n", getboolean(nodes.FNC)); + fprintf(fp, " Pack Netmail %s", getboolean(nodes.PackNetmail)); + fprintf(fp, " ARCmail comp. %s", getboolean(nodes.ARCmailCompat)); + fprintf(fp, " ACRmail a..z %s\n\n", getboolean(nodes.ARCmailAlpha)); + + fprintf(fp, " Statistics Send KBytes Received KBytes\n"); + fprintf(fp, " ------------ -------- -------- -------- --------\n"); + fprintf(fp, " Total files %-8lu %-8lu %-8lu %-8lu\n", nodes.FilesSent.total, nodes.F_KbSent.total, nodes.FilesRcvd.total, nodes.F_KbSent.total); + fprintf(fp, " Total mail %-8lu %-8lu\n", nodes.MailSent.total, nodes.MailRcvd.total); + + fprintf(fp, " Credit units %-8ld Warnlevel %ld\n", nodes.Credit, nodes.WarnLevel); + fprintf(fp, " Debet units %-8ld Stoplevel %ld\n", nodes.Debet, nodes.StopLevel); + fprintf(fp, " Add promille %ld\n", nodes.AddPerc); + fprintf(fp, "\n File groups:\n "); + groups = nodeshdr.filegrp / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group)) { + fprintf(fp, "%-12s ", group); + if (((i+1) % 5) == 0) + fprintf(fp, "\n "); + } + } + if ((i+1) % 5) + fprintf(fp, "\n"); + fprintf(fp, "\n Mail groups:\n "); + groups = nodeshdr.mailgrp / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group)) { + fprintf(fp, "%-12s ", group); + if (((i+1) % 5) == 0) + fprintf(fp, "\n "); + } + } + fprintf(fp, "\n"); + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_node.h b/mbsetup/m_node.h new file mode 100644 index 00000000..3bca6007 --- /dev/null +++ b/mbsetup/m_node.h @@ -0,0 +1,12 @@ +#ifndef _NODE_H +#define _NODE_H + +int OpenNoderec(void); +void CloseNoderec(int); +int GroupInNode(char *, int); +void EditNodes(void); +int node_doc(FILE *, FILE *, int); +fidoaddr PullUplink(char *); + +#endif + diff --git a/mbsetup/m_ol.c b/mbsetup/m_ol.c new file mode 100644 index 00000000..3537f68b --- /dev/null +++ b/mbsetup/m_ol.c @@ -0,0 +1,534 @@ +/***************************************************************************** + * + * File ..................: setup/m_ol.c + * Purpose ...............: Setup Oneliners. + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_ol.h" + + + +int OnelUpdated = 0; + + +/* + * Count nr of oneline records in the database. + * Creates the database if it doesn't exist. + */ +int CountOneline(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + olhdr.hdrsize = sizeof(olhdr); + olhdr.recsize = sizeof(ol); + fwrite(&olhdr, sizeof(olhdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + count = 0; + fread(&olhdr, sizeof(olhdr), 1, fil); + + while (fread(&ol, olhdr.recsize, 1, fil) == 1) { + count++; + } + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenOneline(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/oneline.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&olhdr, sizeof(olhdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = olhdr.recsize; + if (oldsize != sizeof(ol)) + OnelUpdated = 1; + else + OnelUpdated = 0; + olhdr.hdrsize = sizeof(olhdr); + olhdr.recsize = sizeof(ol); + fwrite(&olhdr, sizeof(olhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&ol, 0, sizeof(ol)); + while (fread(&ol, oldsize, 1, fin) == 1) { + fwrite(&ol, sizeof(ol), 1, fout); + memset(&ol, 0, sizeof(ol)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseOneline(void) +{ + char fin[81], fout[81]; + + sprintf(fin, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/oneline.temp", getenv("MBSE_ROOT")); + + if (OnelUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + if ((rename(fout, fin)) == 0) + unlink(fout); + Syslog('+', "Updated \"oneline.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendOneline(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/oneline.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&ol, 0, sizeof(ol)); + fwrite(&ol, sizeof(ol), 1, fil); + fclose(fil); + OnelUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditOnelRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Oneline"); + + sprintf(mfile, "%s/etc/oneline.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(olhdr) + ((Area -1) * sizeof(ol)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&ol, sizeof(ol), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&ol, crc, sizeof(ol)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 2, "8.8.1 EDIT ONELINER"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Text"); + mvprintw( 8, 2, "2. User"); + mvprintw( 9, 2, "3. Date"); + mvprintw(10, 2, "4. Avail"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,12,68, ol.Oneline); + show_str( 8,12,35, ol.UserName); + show_str( 9,12,10, ol.DateOfEntry); + show_bool(10,12, ol.Available); + + j = select_menu(4); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&ol, crc1, sizeof(ol)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&ol, sizeof(ol), 1, fil); + fclose(fil); + OnelUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,12,68,ol.Oneline, "The ^Oneline^ text to show") + case 2: E_STR( 8,12,30,ol.UserName, "The ^Username^ of the owner of this oneline") + case 3: E_STR( 9,12,10,ol.DateOfEntry,"The ^Date^ this oneliner is added, format: ^DD-MM-YYYY^") + case 4: E_BOOL(10,12, ol.Available, "Is this oneline ^available^") + } + } + + return 0; +} + + + +void EditOneline(void) +{ + int records, i, x, y, o; + char pick[12]; + FILE *fil; + char temp[121]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountOneline(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenOneline() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "8.8.1 ONELINERS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/oneline.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&olhdr, sizeof(olhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(olhdr) + (((o + i) - 1) * olhdr.recsize); + fseek(fil, offset, 0); + fread(&ol, olhdr.recsize, 1, fil); + if (ol.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, ol.Oneline); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records,20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseOneline(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendOneline() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditOnelRec(atoi(pick)); + } +} + + + +void PurgeOneline(void) +{ + FILE *pOneline, *fp; + int recno = 0; + int iCount = 0; + char sFileName[81]; + char temp[81]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "7.8.2 ONELINERS PURGE"); + set_color(CYAN, BLACK); + working(1, 0, 0); + + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + IsDoing("Purge Oneliners"); + + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if ((pOneline = fopen(sFileName, "r")) == NULL) { + return; + } + + fread(&olhdr, sizeof(olhdr), 1, pOneline); + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + recno++; + if (!ol.Available) + iCount++; + } + working(0, 0, 0); + + sprintf(temp, "%d records, %d records to purge", recno, iCount); + mvprintw(7, 6, temp); + if (iCount == 0) { + mvprintw(9, 6, "Press any key"); + readkey(9, 20, LIGHTGRAY, BLACK); + return; + } + + if (yes_no((char *)"Purge deleted records") == TRUE) { + working(1, 0, 0); + fseek(pOneline, olhdr.hdrsize, 0); + fp = fopen("tmp.1", "a"); + fwrite(&olhdr, sizeof(olhdr), 1, fp); + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + if (ol.Available) + fwrite(&ol, olhdr.recsize, 1, fp); + } + fclose(fp); + fclose(pOneline); + if ((rename("tmp.1", sFileName)) != 0) + working(2, 0, 0); + unlink("tmp.1"); + working(0, 0, 0); + } +} + + + +void ImportOneline(void) +{ + FILE *Imp, *pOneline; + char temp[81]; + int recno = 0; + struct tm *l_date; + char buf[12]; + time_t Time; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 6, "8.8.3 IMPORT ONELINERS"); + set_color(CYAN, BLACK); + memset(&temp, 0, sizeof(temp)); + strcpy(temp, edit_str(21, 6,64, temp, (char *)"The ^full path and filename^ of the file to import")); + if (strlen(temp) == 0) + return; + + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + if ((Imp = fopen(temp, "r")) == NULL) { + working(2, 0, 0); + working(0, 0, 0); + mvprintw(21, 6, temp); + readkey(22, 6, LIGHTGRAY, BLACK); + return; + } + + sprintf(temp, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + + /* + * Check if database exists, if not create a new one + */ + if ((pOneline = fopen(temp, "r" )) == NULL) { + if ((pOneline = fopen(temp, "w")) != NULL) { + olhdr.hdrsize = sizeof(olhdr); + olhdr.recsize = sizeof(ol); + fwrite(&olhdr, sizeof(olhdr), 1, pOneline); + fclose(pOneline); + } + } else + fclose(pOneline); + + /* + * Open database for appending + */ + if ((pOneline = fopen(temp, "a+")) == NULL) { + working(2, 0, 0); + working(0, 0, 0); + fclose(Imp); + mvprintw(21, 6, temp); + readkey(22, 6, LIGHTGRAY, BLACK); + return; + } + + time(&Time); + l_date = localtime(&Time); + sprintf(buf, "%02d-%02d-%04d", l_date->tm_mday, l_date->tm_mon+1, l_date->tm_year+1900); + + while ((fgets(temp, 80, Imp)) != NULL) { + Striplf(temp); + if ((strlen(temp) > 0) && (strlen(temp) < 78)) { + memset(&ol, 0, sizeof(ol)); + strcpy(ol.Oneline, temp); + strcpy(ol.UserName, CFG.sysop_name); + strcpy(ol.DateOfEntry, buf); + ol.Available = TRUE; + fwrite(&ol, sizeof(ol), 1, pOneline); + recno++; + } + } + + fclose(Imp); + fclose(pOneline); + working(0, 0, 0); + + sprintf(temp, "Imported %d records", recno); + mvprintw(21, 6, temp); + readkey(21, 27, LIGHTGRAY, BLACK); +} + + + +void ol_menu(void) +{ + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.8 ONELINER SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Oneliners"); + mvprintw( 8, 6, "2. Purge Oneliners"); + mvprintw( 9, 6, "3. Import Oneliners"); + + switch(select_menu(3)) { + case 0: + return; + + case 1: + EditOneline(); + break; + + case 2: + PurgeOneline(); + break; + + case 3: + ImportOneline(); + break; + + } + } +} + + diff --git a/mbsetup/m_ol.h b/mbsetup/m_ol.h new file mode 100644 index 00000000..84a2419a --- /dev/null +++ b/mbsetup/m_ol.h @@ -0,0 +1,12 @@ +/* m_ol.h */ + +#ifndef _OL_H +#define _OL_H + + +int CountOneline(void); +void EditOneline(void); +void ol_menu(void); + +#endif + diff --git a/mbsetup/m_protocol.c b/mbsetup/m_protocol.c new file mode 100644 index 00000000..698802b5 --- /dev/null +++ b/mbsetup/m_protocol.c @@ -0,0 +1,538 @@ +/***************************************************************************** + * + * File ..................: mbsetup/m_protocol.c + * Purpose ...............: Setup Protocols. + * Last modification date : 22-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_protocol.h" + + + +int ProtUpdated = 0; + + +/* + * Count nr of PROT records in the database. + * Creates the database if it doesn't exist. + */ +int CountProtocol(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + PROThdr.hdrsize = sizeof(PROThdr); + PROThdr.recsize = sizeof(PROT); + fwrite(&PROThdr, sizeof(PROThdr), 1, fil); + + memset(&PROT, 0, sizeof(PROT)); + sprintf(PROT.ProtKey, "1"); + sprintf(PROT.ProtName, "Ymodem"); + sprintf(PROT.ProtUp, "/usr/bin/rb -v"); + sprintf(PROT.ProtDn, "/usr/bin/sb -v -u"); + sprintf(PROT.Advice, "Press Ctrl-X to abort"); + PROT.Available = TRUE; + PROT.Batch = TRUE; + PROT.Efficiency = 92; + fwrite(&PROT, sizeof(PROT), 1, fil); + + memset(&PROT, 0, sizeof(PROT)); + sprintf(PROT.ProtKey, "L"); + sprintf(PROT.ProtName, "Local disk"); + sprintf(PROT.ProtUp, "%s/bin/rf", getenv("MBSE_ROOT")); + sprintf(PROT.ProtDn, "%s/bin/sf", getenv("MBSE_ROOT")); + sprintf(PROT.Advice, "It goes before you know"); + PROT.Efficiency = 100; + PROT.Batch = TRUE; + fwrite(&PROT, sizeof(PROT), 1, fil); + + memset(&PROT, 0, sizeof(PROT)); + sprintf(PROT.ProtKey, "Y"); + sprintf(PROT.ProtName, "Ymodem 1K"); + sprintf(PROT.ProtUp, "/usr/bin/rb -k -v"); + sprintf(PROT.ProtDn, "/usr/bin/sb -k -v -u"); + sprintf(PROT.Advice, "Press Ctrl-X to abort"); + PROT.Available = TRUE; + PROT.Batch = TRUE; + PROT.Efficiency = 95; + fwrite(&PROT, sizeof(PROT), 1, fil); + + memset(&PROT, 0, sizeof(PROT)); + sprintf(PROT.ProtKey, "Z"); + sprintf(PROT.ProtName, "Zmodem"); + sprintf(PROT.ProtUp, "/usr/bin/rz -p -v"); + sprintf(PROT.ProtDn, "/usr/bin/sz -b -q -r -u"); + sprintf(PROT.Advice, "Press Ctrl-X to abort"); + PROT.Available = TRUE; + PROT.Batch = TRUE; + PROT.Efficiency = 98; + fwrite(&PROT, sizeof(PROT), 1, fil); + + fclose(fil); + return 4; + } else + return -1; + } + + fread(&PROThdr, sizeof(PROThdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - PROThdr.hdrsize) / PROThdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenProtocol(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/protocol.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&PROThdr, sizeof(PROThdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = PROThdr.recsize; + if (oldsize != sizeof(PROT)) + ProtUpdated = 1; + else + ProtUpdated = 0; + PROThdr.hdrsize = sizeof(PROThdr); + PROThdr.recsize = sizeof(PROT); + fwrite(&PROThdr, sizeof(PROThdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&PROT, 0, sizeof(PROT)); + while (fread(&PROT, oldsize, 1, fin) == 1) { + fwrite(&PROT, sizeof(PROT), 1, fout); + memset(&PROT, 0, sizeof(PROT)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseProtocol(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *pro = NULL, *tmp; + + sprintf(fin, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/protocol.temp", getenv("MBSE_ROOT")); + + if (ProtUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&PROThdr, PROThdr.hdrsize, 1, fi); + fwrite(&PROThdr, PROThdr.hdrsize, 1, fo); + + while (fread(&PROT, PROThdr.recsize, 1, fi) == 1) + if (!PROT.Deleted) + fill_stlist(&pro, PROT.ProtKey, ftell(fi) - PROThdr.recsize); + sort_stlist(&pro); + + for (tmp = pro; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&PROT, PROThdr.recsize, 1, fi); + fwrite(&PROT, PROThdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + unlink(fout); + tidy_stlist(&pro); + Syslog('+', "Updated \"protocol.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendProtocol(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/protocol.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&PROT, 0, sizeof(PROT)); + fwrite(&PROT, sizeof(PROT), 1, fil); + fclose(fil); + ProtUpdated = 1; + return 0; + } else + return -1; +} + + + +void s_protrec(void); +void s_protrec(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.5 EDIT PROTOCOL"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Select Key"); + mvprintw( 8, 6, "2. Name"); + mvprintw( 9, 6, "3. Upload"); + mvprintw(10, 6, "4. Download"); + mvprintw(11, 6, "5. Available"); + mvprintw(12, 6, "6. Batching"); + mvprintw(13, 6, "7. Bi direct"); + mvprintw(14, 6, "8. Advice"); + mvprintw(15, 6, "9. Efficiency"); + mvprintw(16, 6, "10. Deleted"); + mvprintw(17, 6, "11. Sec. level"); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditProtRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Protocol"); + + sprintf(mfile, "%s/etc/protocol.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(PROThdr) + ((Area -1) * sizeof(PROT)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&PROT, sizeof(PROT), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&PROT, crc, sizeof(PROT)); + working(0, 0, 0); + + s_protrec(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,21, 1, PROT.ProtKey); + show_str( 8,21,20, PROT.ProtName); + show_str( 9,21,50, PROT.ProtUp); + show_str( 10,21,50, PROT.ProtDn); + show_bool(11,21, PROT.Available); + show_bool(12,21, PROT.Batch); + show_bool(13,21, PROT.Bidir); + show_str( 14,21,30, PROT.Advice); + show_int( 15,21, PROT.Efficiency); + show_bool(16,21, PROT.Deleted); + show_sec( 17,21, PROT.Level); + + j = select_menu(11); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&PROT, crc1, sizeof(PROT)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&PROT, sizeof(PROT), 1, fil); + fclose(fil); + ProtUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_UPS( 7,21,1, PROT.ProtKey, "The ^Key^ to select this protocol") + case 2: E_STR( 8,21,20,PROT.ProtName, "The ^name^ of this protocol") + case 3: E_STR( 9,21,50,PROT.ProtUp, "The ^Upload^ path, binary and parameters") + case 4: E_STR( 10,21,50,PROT.ProtDn, "The ^Download^ path, binary and parameters") + case 5: E_BOOL(11,21, PROT.Available, "Is this protocol ^available^") + case 6: E_BOOL(12,21, PROT.Batch, "Is this a ^batching^ transfer protocol") + case 7: E_BOOL(13,21, PROT.Bidir, "Is this protocol ^bidirectional^") + case 8: E_STR( 14,21,30,PROT.Advice, "A small ^advice^ to the user, eg \"Press Ctrl-X to abort\"") + case 9: E_INT( 15,21, PROT.Efficiency,"The ^efficiency^ in % of this protocol") + case 10:E_BOOL(16,21, PROT.Deleted, "Is this protocol ^Deleted^") + case 11:E_SEC( 17,21, PROT.Level, "8.5.11 PROTOCOL SECURITY LEVEL", s_protrec) + } + } + + return 0; +} + + + +void EditProtocol(void) +{ + int records, i, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountProtocol(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenProtocol() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.5 PROTOCOL SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/protocol.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&PROThdr, sizeof(PROThdr), 1, fil); + x = 4; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(PROThdr) + ((i - 1) * PROThdr.recsize); + fseek(fil, offset, 0); + fread(&PROT, PROThdr.recsize, 1, fil); + if (i == 11) + x = 44; + if (PROT.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %-30s", i, PROT.ProtKey, PROT.ProtName); + temp[37] = '\0'; + mvprintw(i + 6, x, temp); + } + fclose(fil); + } + /* Show records here */ + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseProtocol(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendProtocol() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditProtRec(atoi(pick)); + } +} + + + +char *PickProtocol(int nr) +{ + static char Prot[21] = ""; + int records, i, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return Prot; + } + + records = CountProtocol(); + if (records == -1) { + working(2, 0, 0); + return Prot; + } + + working(0, 0, 0); + + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%d. PROTOCOL SELECT", nr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&PROThdr, sizeof(PROThdr), 1, fil); + x = 2; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(PROThdr) + ((i - 1) * PROThdr.recsize); + fseek(fil, offset, 0); + fread(&PROT, PROThdr.recsize, 1, fil); + if (i == 11) + x = 42; + if (PROT.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %-30s", i, PROT.ProtKey, PROT.ProtName); + temp[37] = '\0'; + mvprintw(i + 6, x, temp); + } + strcpy(pick, select_pick(records, 20)); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = sizeof(PROThdr) + ((atoi(pick) - 1) * PROThdr.recsize); + fseek(fil, offset, 0); + fread(&PROT, PROThdr.recsize, 1, fil); + strcpy(Prot, PROT.ProtName); + } + fclose(fil); + } + } + return Prot; +} + + + +int bbs_prot_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 8, 5, page, (char *)"BBS Transfer protocols"); + j = 0; + fprintf(fp, "\n\n"); + fread(&PROThdr, sizeof(PROThdr), 1, no); + + while ((fread(&PROT, PROThdr.recsize, 1, no)) == 1) { + + if (j == 4) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Selection key %s\n", PROT.ProtKey); + fprintf(fp, " Protocol name %s\n", PROT.ProtName); + fprintf(fp, " Upload command %s\n", PROT.ProtUp); + fprintf(fp, " Download command %s\n", PROT.ProtDn); + fprintf(fp, " Available %s\n", getboolean(PROT.Available)); + fprintf(fp, " Batch protocol %s\n", getboolean(PROT.Batch)); + fprintf(fp, " Bidirectional %s\n", getboolean(PROT.Bidir)); + fprintf(fp, " User advice %s\n", PROT.Advice); + fprintf(fp, " Efficiency %d%%\n", PROT.Efficiency); + fprintf(fp, " Security level %s\n", get_secstr(PROT.Level)); + fprintf(fp, "\n\n"); + + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_protocol.h b/mbsetup/m_protocol.h new file mode 100644 index 00000000..c4f0e668 --- /dev/null +++ b/mbsetup/m_protocol.h @@ -0,0 +1,12 @@ +#ifndef _PROTOCOL_H +#define _PROTOCOL_H + + +int CountProtocol(void); +void EditProtocol(void); +char *PickProtocol(int); +int bbs_prot_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_service.c b/mbsetup/m_service.c new file mode 100644 index 00000000..4f3acbbe --- /dev/null +++ b/mbsetup/m_service.c @@ -0,0 +1,435 @@ +/***************************************************************************** + * + * File ..................: m_service.c + * Purpose ...............: Service Setup + * Last modification date : 30-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_service.h" + + +int ServiceUpdated; + + +/* + * Count nr of servrec records in the database. + * Creates the database if it doesn't exist. + */ +int CountService(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/service.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + servhdr.hdrsize = sizeof(servhdr); + servhdr.recsize = sizeof(servrec); + servhdr.lastupd = time(NULL); + fwrite(&servhdr, sizeof(servhdr), 1, fil); + memset(&servrec, 0, sizeof(servrec)); + sprintf(servrec.Service, "UUCP"); + servrec.Action = EMAIL; + servrec.Active = TRUE; + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "areamgr"); + servrec.Action = AREAMGR; + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "gecho"); + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "fmail"); + fwrite(&servrec, sizeof(servrec), 1, fil); + servrec.Action = FILEMGR; + sprintf(servrec.Service, "allfix"); + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "mbtic"); + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "raid"); + fwrite(&servrec, sizeof(servrec), 1, fil); + fclose(fil); + return 6; + } else + return -1; + } + + fread(&servhdr, sizeof(servhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - servhdr.hdrsize) / servhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenService(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/service.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/service.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&servhdr, sizeof(servhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = servhdr.recsize; + if (oldsize != sizeof(servrec)) + ServiceUpdated = 1; + else + ServiceUpdated = 0; + servhdr.hdrsize = sizeof(servhdr); + servhdr.recsize = sizeof(servrec); + fwrite(&servhdr, sizeof(servhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&servrec, 0, sizeof(servrec)); + while (fread(&servrec, oldsize, 1, fin) == 1) { + fwrite(&servrec, sizeof(servrec), 1, fout); + memset(&servrec, 0, sizeof(servrec)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseService(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *hat = NULL, *tmp; + + sprintf(fin, "%s/etc/service.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/service.temp", getenv("MBSE_ROOT")); + + if (ServiceUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&servhdr, servhdr.hdrsize, 1, fi); + fwrite(&servhdr, servhdr.hdrsize, 1, fo); + + while (fread(&servrec, servhdr.recsize, 1, fi) == 1) + if (!servrec.Deleted) + fill_stlist(&hat, servrec.Service, ftell(fi) - servhdr.recsize); + sort_stlist(&hat); + + for (tmp = hat; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&servrec, servhdr.recsize, 1, fi); + fwrite(&servrec, servhdr.recsize, 1, fo); + } + + tidy_stlist(&hat); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"servrec.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendService(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/service.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&servrec, 0, sizeof(servrec)); + /* + * Fill in default values + */ + fwrite(&servrec, sizeof(servrec), 1, fil); + fclose(fil); + ServiceUpdated = 1; + return 0; + } else + return -1; +} + + + +void ServiceScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "16. EDIT SERVICES"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Name"); + mvprintw( 8, 2, "2. Type"); + mvprintw( 9, 2, "3. Active"); + mvprintw(10, 2, "4. Deleted"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditServiceRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Service"); + + sprintf(mfile, "%s/etc/service.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&servhdr, sizeof(servhdr), 1, fil); + offset = servhdr.hdrsize + ((Area -1) * servhdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&servrec, servhdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&servrec, crc, servhdr.recsize); + working(0, 0, 0); + + for (;;) { + ServiceScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,15, servrec.Service); + show_service(8, 18, servrec.Action); + show_bool( 9,18, servrec.Active); + show_bool(10,18, servrec.Deleted); + + switch(select_menu(4)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&servrec, crc1, servhdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&servrec, servhdr.recsize, 1, fil); + fclose(fil); + ServiceUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,15, servrec.Service,"Enter the ^name^ of this ^service^.") + case 2: servrec.Action = edit_service(8,18,servrec.Action); + break; + case 3: E_BOOL( 9,18, servrec.Active, "If this service is ^active^") + case 4: E_BOOL(10,18, servrec.Deleted, "If this record is ^Deleted^") + } + } +} + + + +void EditService(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountService(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenService() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "16. SERVICE MANAGER"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/service.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&servhdr, sizeof(servhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(servhdr) + (((o + i) - 1) * servhdr.recsize); + fseek(fil, offset, 0); + fread(&servrec, servhdr.recsize, 1, fil); + if (servrec.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-15s %s", o+i, servrec.Service, getservice(servrec.Action)); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseService(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendService() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditServiceRec(atoi(pick)); + } +} + + + +int service_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/service.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 14, 0, page, (char *)"Service manager"); + j = 0; + + fprintf(fp, "\n"); + fprintf(fp, " Service Action Active\n"); + fprintf(fp, " --------------- -------- ------\n"); + fread(&servhdr, sizeof(servhdr), 1, no); + + while ((fread(&servrec, servhdr.recsize, 1, no)) == 1) { + + if (j == 50) { + page = newpage(fp, page); + fprintf(fp, "\n"); + fprintf(fp, " Service Action Active\n"); + fprintf(fp, " --------------- -------- ------\n"); + j = 0; + } + + fprintf(fp, " %-15s %-8s %s\n", servrec.Service, getservice(servrec.Action), getboolean(servrec.Active)); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_service.h b/mbsetup/m_service.h new file mode 100644 index 00000000..619303bf --- /dev/null +++ b/mbsetup/m_service.h @@ -0,0 +1,10 @@ +#ifndef _SERVICE_H +#define _SERVICE_H + + +int CountService(void); +void EditService(void); +int service_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_task.c b/mbsetup/m_task.c new file mode 100644 index 00000000..e7be5b7c --- /dev/null +++ b/mbsetup/m_task.c @@ -0,0 +1,243 @@ +/***************************************************************************** + * + * File ..................: setup/m_task.c + * Purpose ...............: Setup TaskManager. + * Last modification date : 06-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_task.h" + + + +struct taskrec TCFG; +unsigned long crc1, crc2; + + + +/* + * Open database for editing. + */ +int OpenTask(void); +int OpenTask(void) +{ + FILE *fin; + char fnin[PATH_MAX]; + + sprintf(fnin, "%s/etc/task.data", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + fread(&TCFG, sizeof(TCFG), 1, fin); + fclose(fin); + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&TCFG, crc1, sizeof(TCFG)); + return 0; + } + return -1; +} + + + +void CloseTask(void); +void CloseTask(void) +{ + char fin[PATH_MAX]; + FILE *fp; + + crc2 = 0xffffffff; + crc2 = upd_crc32((char *)&TCFG, crc2, sizeof(TCFG)); + + if (crc1 != crc2) { + if (yes_no((char *)"Configuration is changed, save changes") == 1) { + working(1, 0, 0); + sprintf(fin, "%s/etc/task.data", getenv("MBSE_ROOT")); + if ((fp = fopen(fin, "w+")) != NULL) { + fwrite(&TCFG, sizeof(TCFG), 1, fp); + fclose(fp); + Syslog('+', "Updated \"task.data\""); + } + } + } + working(1, 0, 0); +} + + + +/* + * Edit task record. + */ +int EditTask(void); +int EditTask() +{ + int j; + char temp[20]; + + clr_index(); + IsDoing("Edit Taskmanager"); + + set_color(WHITE, BLACK); + mvprintw( 4, 1, "18. EDIT TASK MANAGER"); + set_color(CYAN, BLACK); + mvprintw( 6, 1, " 1. Mailout"); + mvprintw( 7, 1, " 2. Mailin"); + mvprintw( 8, 1, " 3. Newnews"); + mvprintw( 9, 1, " 4. Index 1"); + mvprintw(10, 1, " 5. Index 2"); + mvprintw(11, 1, " 6. Index 3"); + mvprintw(12, 1, " 7. Msglink"); + mvprintw(13, 1, " 8. Reqindex"); + mvprintw(14, 1, " 9. ISP conn"); + mvprintw(15, 1, "10. ISP disc"); + mvprintw(16, 1, "11. Ping #1"); + mvprintw(17, 1, "12. Ping #2"); + mvprintw(18, 1, "13. ISP blks"); + mvprintw(19, 1, "14. Max Load"); + + mvprintw(18,29, "15. ZMH start"); + mvprintw(19,29, "16. ZMH end"); + + mvprintw(16,55, "17. Debug"); + mvprintw(17,55, "18. Max POTS"); + mvprintw(18,55, "19. Max ISDN"); + mvprintw(19,55, "20. Max TCP"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6, 15,65, TCFG.cmd_mailout); + show_str( 7, 15,65, TCFG.cmd_mailin); + show_str( 8, 15,65, TCFG.cmd_newnews); + show_str( 9, 15,65, TCFG.cmd_mbindex1); + show_str(10, 15,65, TCFG.cmd_mbindex2); + show_str(11, 15,65, TCFG.cmd_mbindex3); + show_str(12, 15,65, TCFG.cmd_msglink); + show_str(13, 15,65, TCFG.cmd_reqindex); + show_str(14, 15,65, TCFG.isp_connect); + show_str(15, 15,65, TCFG.isp_hangup); + show_str(16, 15,40, TCFG.isp_ping1); + show_str(17, 15,40, TCFG.isp_ping2); + show_bool(18,15, TCFG.ipblocks); + sprintf(temp, "%0.2f", TCFG.maxload); + show_str(19, 15,5, temp); + + show_str( 18,44, 5, TCFG.zmh_start); + show_str( 19,44, 5, TCFG.zmh_end); + + show_bool(16,69, TCFG.debug); + show_int( 17,69, TCFG.max_pots); + show_int( 18,69, TCFG.max_isdn); + show_int( 19,69, TCFG.max_tcp); + + j = select_menu(20); + switch(j) { + case 0: return 0; + case 1: E_STR( 6,15,65,TCFG.cmd_mailout, "The command to execute on semafore ^mailout^") + case 2: E_STR( 7,15,65,TCFG.cmd_mailin, "The command to execute on semafore ^mailin^") + case 3: E_STR( 8,15,65,TCFG.cmd_newnews, "The command to execute on semafore ^newnews^") + case 4: E_STR( 9,15,65,TCFG.cmd_mbindex1, "The compiler 1 command to execute on semafore ^mbindex^") + case 5: E_STR( 10,15,65,TCFG.cmd_mbindex2, "The compiler 2 command to execute on semafore ^mbindex^") + case 6: E_STR( 11,15,65,TCFG.cmd_mbindex3, "The compiler 3 command to execute on semafore ^mbindex^") + case 7: E_STR( 12,15,65,TCFG.cmd_msglink, "The command to execute on semafore ^msglink^") + case 8: E_STR( 13,15,65,TCFG.cmd_reqindex, "The command to execute on semafore ^reqindex^") + case 9: E_STR( 14,15,65,TCFG.isp_connect, "The command to ^connect^ the Internet Connection") + case 10:E_STR( 15,15,65,TCFG.isp_hangup, "The command to ^hangup^ the Internet Connection") + case 11:E_STR( 16,15,40,TCFG.isp_ping1, "The ^IP address^ of host 1 to check the Internet Connection") + case 12:E_STR( 17,15,40,TCFG.isp_ping2, "The ^IP address^ of host 2 to check the Internet Connection") + case 13:E_BOOL(18,15, TCFG.ipblocks, "The ^internet^ connection ^blocks^ dial connections") + case 14:strcpy(temp, edit_str(19,15,5,temp, (char *)"^Maximum system load^ at which processing stops (1.00 .. 3.00)")); + sscanf(temp, "%f", &TCFG.maxload); + break; + case 15:E_STR( 18,44,5, TCFG.zmh_start, "^Start^ of Zone Mail Hour in UTC") + case 16:E_STR( 19,44,5, TCFG.zmh_end, "^End& of Zone Mail Hour in UTC") + case 17:E_BOOL(16,69, TCFG.debug, "Enable ^debug^ logging") + case 18:E_INT( 17,69, TCFG.max_pots, "Maximum simultanous ^POTS^ (analogue) connections") + case 19:E_INT( 18,69, TCFG.max_isdn, "Maximum simultanous ^ISDN^ connections") + case 20:E_INT( 19,69, TCFG.max_tcp, "Maximum simultanous ^TCP/IP^ connections") + } + } + + return 0; +} + + + +void task_menu(void) +{ + OpenTask(); + EditTask(); + CloseTask(); +} + + +int task_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + + sprintf(temp, "%s/etc/task.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + fread(&TCFG, sizeof(TCFG), 1, no); + fclose(no); + + page = newpage(fp, page); + addtoc(fp, toc, 16, 0, page, (char *)"Task manager"); + + fprintf(fp, "\n"); + fprintf(fp, " Command on mailout %s\n", TCFG.cmd_mailout); + fprintf(fp, " Command on mailin %s\n", TCFG.cmd_mailin); + fprintf(fp, " Command on newnews %s\n", TCFG.cmd_newnews); + fprintf(fp, " Command on mbindex 1 %s\n", TCFG.cmd_mbindex1); + fprintf(fp, " Command on mbindex 2 %s\n", TCFG.cmd_mbindex2); + fprintf(fp, " Command on mbindex 3 %s\n", TCFG.cmd_mbindex3); + fprintf(fp, " Command on msglink %s\n", TCFG.cmd_msglink); + fprintf(fp, " Command on reqindex %s\n\n", TCFG.cmd_reqindex); + + fprintf(fp, " Zone Mail Hour start %s\n", TCFG.zmh_start); + fprintf(fp, " Zone Mail Hour end %s\n\n", TCFG.zmh_end); + + fprintf(fp, " ISP connect command %s\n", TCFG.isp_connect); + fprintf(fp, " ISP hangup command %s\n", TCFG.isp_hangup); + fprintf(fp, " ISP ping host 1 %s\n", TCFG.isp_ping1); + fprintf(fp, " ISP ping host 2 %s\n", TCFG.isp_ping2); + fprintf(fp, " Internet blocks dial %s\n\n", getboolean(TCFG.ipblocks)); + + fprintf(fp, " Enable denug logging %s\n", getboolean(TCFG.debug)); + fprintf(fp, " Maximum system load %0.2f\n", TCFG.maxload); + fprintf(fp, " Max POTS connections %d\n", TCFG.max_pots); + fprintf(fp, " Max ISDN connections %d\n", TCFG.max_isdn); + fprintf(fp, " Max TCP/IP connections %d\n", TCFG.max_tcp); + + return page; +} + + diff --git a/mbsetup/m_task.h b/mbsetup/m_task.h new file mode 100644 index 00000000..7e64f419 --- /dev/null +++ b/mbsetup/m_task.h @@ -0,0 +1,10 @@ +#ifndef _TASK_H +#define _TASK_H + + +void task_menu(void); +int task_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_tic.c b/mbsetup/m_tic.c new file mode 100644 index 00000000..13b4346b --- /dev/null +++ b/mbsetup/m_tic.c @@ -0,0 +1,98 @@ +/***************************************************************************** + * + * File ..................: m_tic.c + * Purpose ...............: TIC Setup Program + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_fgroup.h" +#include "m_ticarea.h" +#include "m_magic.h" +#include "m_hatch.h" +#include "m_tic.h" + + +void tic_menu(void) +{ + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10. FILEECHO SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Fileecho Groups"); + mvprintw( 8, 6, "2. Edit Fileecho Areas"); + mvprintw( 9, 6, "3. Edit Hatch Manager"); + mvprintw(10, 6, "4. Edit Magic files"); + + switch(select_menu(4)) { + case 0: + return; + + case 1: + EditFGroup(); + break; + + case 2: + EditTicarea(); + break; + + case 3: + EditHatch(); + break; + + case 4: + EditMagics(); + break; + } + } +} + + + +int tic_doc(FILE *fp, FILE *toc, int page) +{ + int next; + + page = newpage(fp, page); + addtoc(fp, toc, 10, 0, page, (char *)"Files processing"); + + next = tic_group_doc(fp, toc, page); + next = tic_areas_doc(fp, toc, next); + next = tic_hatch_doc(fp, toc, next); + next = tic_magic_doc(fp, toc, next); + + return next; +} + + diff --git a/mbsetup/m_tic.h b/mbsetup/m_tic.h new file mode 100644 index 00000000..896a6fb6 --- /dev/null +++ b/mbsetup/m_tic.h @@ -0,0 +1,4 @@ + +void tic_menu(void); +int tic_doc(FILE *, FILE *, int); + diff --git a/mbsetup/m_ticarea.c b/mbsetup/m_ticarea.c new file mode 100644 index 00000000..3fe88ee5 --- /dev/null +++ b/mbsetup/m_ticarea.c @@ -0,0 +1,1256 @@ +/***************************************************************************** + * + * File ..................: m_ticareas.c + * Purpose ...............: TIC Areas Setup Program + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "grlist.h" +#include "m_global.h" +#include "m_node.h" +#include "m_fgroup.h" +#include "m_farea.h" +#include "m_archive.h" +#include "m_ticarea.h" + + +int TicUpdated = 0; +unsigned long TicCrc; +FILE *ttfil = NULL; + + + +/* + * Count nr of tic records in the database. + * Creates the database if it doesn't exist. + */ +int CountTicarea(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + Syslog('+', "Created tic.data"); + tichdr.hdrsize = sizeof(tichdr); + tichdr.recsize = sizeof(tic); + tichdr.syssize = CFG.tic_systems * sizeof(sysconnect); + tichdr.lastupd = time(NULL); + fwrite(&tichdr, sizeof(tichdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&tichdr, sizeof(tichdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - tichdr.hdrsize) / (tichdr.recsize + tichdr.syssize); + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenTicarea(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize, oldsys; + struct _sysconnect syscon; + int i, oldsystems; + + sprintf(fnin, "%s/etc/tic.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + Syslog('+', "Opened \"tic.data\""); + TicUpdated = 0; + fread(&tichdr, sizeof(tichdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, fin); + if (tichdr.hdrsize != sizeof(tichdr)) { + tichdr.hdrsize = sizeof(tichdr); + tichdr.lastupd = time(NULL); + TicUpdated = 1; + } + + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = tichdr.recsize; + oldsys = tichdr.syssize; + oldsystems = oldsys / sizeof(syscon); + if ((oldsize != sizeof(tic)) || (CFG.tic_systems != oldsystems)) { + TicUpdated = 1; + Syslog('+', "\"tic.data\" nr of systems is changed"); + } + tichdr.hdrsize = sizeof(tichdr); + tichdr.recsize = sizeof(tic); + tichdr.syssize = sizeof(syscon) * CFG.tic_systems; + fwrite(&tichdr, sizeof(tichdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&tic, 0, sizeof(tic)); + while (fread(&tic, oldsize, 1, fin) == 1) { + fwrite(&tic, sizeof(tic), 1, fout); + memset(&tic, 0, sizeof(tic)); + /* + * Copy the existing connections + */ + for (i = 1; i <= oldsystems; i++) { + fread(&syscon, sizeof(syscon), 1, fin); + /* + * Write only valid records + */ + if (i <= CFG.tic_systems) + fwrite(&syscon, sizeof(syscon), 1, fout); + } + if (oldsystems < CFG.tic_systems) { + /* + * The size is increased, fill with + * blank records. + */ + memset(&syscon, 0, sizeof(syscon)); + for (i = (oldsystems + 1); i <= CFG.tic_systems; i++) + fwrite(&syscon, sizeof(syscon), 1, fout); + } + } + + fclose(fin); + fclose(fout); + Syslog('+', "Opened \"tic.data\""); + if (TicUpdated) + Syslog('+', "Updated \"tic.data\" data format"); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseTicarea(int Force) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *tir = NULL, *tmp; + int i; + struct _sysconnect syscon; + + sprintf(fin, "%s/etc/tic.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/tic.temp", getenv("MBSE_ROOT")); + + if (TicUpdated == 1) { + if (Force || (yes_no((char *)"Tic areas database is changed, save changes")) == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&tichdr, tichdr.hdrsize, 1, fi); + fwrite(&tichdr, tichdr.hdrsize, 1, fo); + + while (fread(&tic, tichdr.recsize, 1, fi) == 1) { + if (!tic.Deleted) + fill_stlist(&tir, tic.Name, ftell(fi) - tichdr.recsize); + fseek(fi, tichdr.syssize, SEEK_CUR); + } + sort_stlist(&tir); + + for (tmp = tir; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&tic, tichdr.recsize, 1, fi); + fwrite(&tic, tichdr.recsize, 1, fo); + for (i = 0; i < (tichdr.syssize / sizeof(syscon)); i++) { + fread(&syscon, sizeof(syscon), 1, fi); + fwrite(&syscon, sizeof(syscon), 1, fo); + } + } + + tidy_stlist(&tir); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"tic.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); + Syslog('+', "No update of \"tic.data\""); +} + + + +int AppendTicarea(void); +int AppendTicarea(void) +{ + FILE *fil; + char ffile[81]; + struct _sysconnect syscon; + int i; + + sprintf(ffile, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&tic, 0, sizeof(tic)); + /* + * Fill in default values + */ + tic.DupCheck = TRUE; + tic.Secure = TRUE; + tic.VirScan = TRUE; + tic.Announce = TRUE; + tic.UpdMagic = TRUE; + tic.FileId = TRUE; + tic.Active = TRUE; + tic.AreaStart = time(NULL); + fwrite(&tic, sizeof(tic), 1, fil); + memset(&syscon, 0, sizeof(syscon)); + for (i = 1; i <= CFG.tic_systems; i++) + fwrite(&syscon, sizeof(syscon), 1, fil); + fclose(fil); + TicUpdated = 1; + return 0; + } else + return -1; +} + + + +void EditTicSystem(sysconnect *); +void EditTicSystem(sysconnect *Sys) +{ + sysconnect S; + unsigned short zone = 0; + int refresh = TRUE; + + S = (* Sys); + for (;;) { + if (refresh) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5,6, "10.2.25 EDIT CONNECTION"); + set_color(CYAN, BLACK); + mvprintw( 7,6, "1. Aka"); + mvprintw( 8,6, "2. Send to"); + mvprintw( 9,6, "3. Recv from"); + mvprintw(10,6, "4. Pause"); + mvprintw(11,6, "5. Delete"); + refresh = FALSE; + } + + set_color(WHITE, BLACK); + show_str( 7,24,23, aka2str(S.aka)); + show_bool( 8,24, S.sendto); + show_bool( 9,24, S.receivefrom); + show_bool(10,24, S.pause); + zone = S.aka.zone; + + switch(select_menu(5)) { + case 0: (* Sys) = S; + return; + case 1: S.aka = PullUplink((char *)"10.2.25"); + refresh = TRUE; + break; + case 2: E_BOOL( 8,24, S.sendto, "^Send^ files ^to^ this node") + case 3: E_BOOL( 9,24, S.receivefrom, "^Receive^ files ^from^ this node") + case 4: E_BOOL(10,24, S.pause, "Is this node ^paused^") + case 5: if (yes_no((char *)"Delete this entry")) { + memset(&S, 0, sizeof(sysconnect)); + (* Sys) = S; + return; + } + break; + } + + /* + * Set sendto to on when a new + * zone is entered. + */ + if ((S.aka.zone) && (!zone)) { + S.sendto = 1; + } + } +} + + + +int EditTicConnections(FILE *); +int EditTicConnections(FILE *fil) +{ + int systems, o = 0, i, y, x; + long offset; + char pick[12]; + sysconnect System; + char status[4]; + char temp[41]; + + systems = tichdr.syssize / sizeof(sysconnect); + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 5, "10.2.25 TIC AREA CONNECTIONS"); + set_color(CYAN, BLACK); + y = 7; + x = 2; + for (i = 1; i <= 20; i++) { + if ((o+i-1) < systems) { + if (i == 11) { + y = 7; + x = 42; + } + offset = (o+i-1) * sizeof(sysconnect); + if ((fseek(fil, offset, 0)) != 0) { + working(2, 0, 0); + return FALSE; + } + fread(&System, sizeof(sysconnect), 1, fil); + memset(&status, 0, 4); + memset(&status, '-', 3); + if (System.sendto) + status[0] = 'S'; + if (System.receivefrom) + status[1] = 'R'; + if (System.pause) + status[2] = 'P'; + if (System.aka.zone) { + set_color(CYAN,BLACK); + sprintf(temp, "%3d. %s %s", o+i, status, aka2str(System.aka)); + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d.", o+i); + } + mvprintw(y, x, temp); + y++; + } + } + strcpy(pick, select_pick(systems, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return FALSE; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < systems) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if (((atoi(pick) > 0) && (atoi(pick) <= systems))) { + offset = (atoi(pick) -1) * sizeof(sysconnect); + fseek(fil, offset, 0); + fread(&System, sizeof(sysconnect), 1, fil); + EditTicSystem(&System); + fseek(fil, offset, 0); + fwrite(&System, sizeof(sysconnect), 1, fil); + } + } +} + + + +void SetTicScreen(void); +void SetTicScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "10.2 EDIT TIC AREA"); + set_color(CYAN, BLACK); + mvprintw( 6, 2, "1. Comment"); + mvprintw( 7, 2, "2. Area tag"); + mvprintw( 8, 2, "3. BBS area"); + mvprintw( 9, 2, "4. Message"); + mvprintw(10, 2, "5. Group"); + mvprintw(11, 2, "6. Keep #"); + mvprintw(12, 2, "7. Fido aka"); + mvprintw(13, 2, "8. Convert"); + mvprintw(14, 2, "9. Banner"); + mvprintw(15, 2, "10. Replace"); + + mvprintw( 7,37, "11. Dupecheck"); + mvprintw( 8,37, "12. Secure"); + mvprintw( 9,37, "13. No touch"); + mvprintw(10,37, "14. Virus sc."); + mvprintw(11,37, "15. Announce"); + mvprintw(12,37, "16. Upd magic"); + mvprintw(13,37, "17. File_id"); + mvprintw(14,37, "18. Conv.all"); + mvprintw(15,37, "19. Send org."); + + mvprintw( 7,59, "20. Mandatory"); + mvprintw( 8,59, "21. Notified"); + mvprintw( 9,59, "22. Upl discon"); + mvprintw(10,59, "23. Deleted"); + mvprintw(11,59, "24. Active"); + mvprintw(12,59, "25. Systems"); +} + + + +long LoadTicRec(int, int); +long LoadTicRec(int Area, int work) +{ + FILE *fil; + char mfile[81]; + long offset; + sysconnect System; + int i; + + if (work) + working(1, 0, 0); + + sprintf(mfile, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + if ((ttfil = tmpfile()) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&tichdr, sizeof(tichdr), 1, fil); + offset = tichdr.hdrsize + (((Area -1) * (tichdr.recsize + tichdr.syssize))); + if (fseek(fil, offset, 0) != 0) { + fclose(ttfil); + working(2, 0, 0); + return -1; + } + + fread(&tic, tichdr.recsize, 1, fil); + TicCrc = 0xffffffff; + TicCrc = upd_crc32((char *)&tic, TicCrc, tichdr.recsize); + for (i = 0; i <= (tichdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, fil); + fwrite(&System, sizeof(sysconnect), 1, ttfil); + TicCrc = upd_crc32((char *)&System, TicCrc, sizeof(sysconnect)); + } + fclose(fil); + if (work) + working(0, 0, 0); + return offset; +} + + + +int SaveTicRec(int, int); +int SaveTicRec(int Area, int work) +{ + int i; + FILE *fil; + long offset; + char mfile[81]; + sysconnect System; + + if (work) + working(1, 0, 0); + sprintf(mfile, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r+")) == 0) { + working(2, 0, 0); + return -1; + } + + fread(&tichdr, sizeof(tichdr), 1, fil); + offset = tichdr.hdrsize + (((Area -1) * (tichdr.recsize + tichdr.syssize))); + if (fseek(fil, offset, SEEK_SET)) { + fclose(fil); + working(2, 0, 0); + return -1; + } + + fwrite(&tic, tichdr.recsize, 1, fil); + fseek(ttfil, 0, SEEK_SET); + for (i = 0; i < (tichdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, ttfil); + fwrite(&System, sizeof(sysconnect), 1, fil); + } + fclose(fil); + fclose(ttfil); + ttfil = NULL; + if (work) + working(0, 0, 0); + return 0; +} + + + +void ShowTicStatus(sysconnect); +void ShowTicStatus(sysconnect S) +{ + clr_index(); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "Aka"); + mvprintw( 8, 6, "Send to"); + mvprintw( 9, 6, "Recv from"); + mvprintw(10, 6, "Pause"); + set_color(WHITE, BLACK); + show_str( 7,16,23, aka2str(S.aka)); + show_bool( 8,16, S.sendto); + show_bool( 9,16, S.receivefrom); + show_bool(10,16, S.pause); +} + + + +void TicGlobal(void); +void TicGlobal(void) +{ + gr_list *mgr = NULL, *tmp; + char *p, tfile[128]; + FILE *fil; + fidoaddr a1, a2; + int menu = 0, areanr, Areas, akan = 0, Found; + int Total, Done; + long offset; + sysconnect S, Sc; + + /* + * Build the groups select array + */ + working(1, 0, 0); + sprintf(tfile, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(tfile, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + + while (fread(&fgroup, fgrouphdr.recsize, 1, fil) == 1) + fill_grlist(&mgr, fgroup.Name); + + fclose(fil); + sort_grlist(&mgr); + } + working(0, 0, 0); + + /* + * Initialize some variables + */ + memset(&S, 0, sizeof(sysconnect)); + S.sendto = TRUE; + S.receivefrom = FALSE; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10.2 GLOBAL EDIT TIC AREAS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Delete connection"); + mvprintw( 8, 6, "2. Add new connection"); + mvprintw( 9, 6, "3. Replace connection"); + mvprintw(10, 6, "4. Change connection status"); + mvprintw(11, 6, "5. Change aka to use"); + mvprintw(12, 6, "6. Delete TIC area"); + + memset(&a1, 0, sizeof(fidoaddr)); + memset(&a2, 0, sizeof(fidoaddr)); + + menu = select_menu(6); + switch (menu) { + case 0: return; + case 1: a1 = PullUplink((char *)"AKA TO DELETE"); + break; + case 2: a2 = PullUplink((char *)"AKA TO ADD"); + break; + case 3: a1 = PullUplink((char *)"AKA TO REPLACE"); + a2 = PullUplink((char *)"NEW AKA"); + break; + case 4: S.aka = PullUplink((char *)"AKA TO CHANGE STATUS"); + ShowTicStatus(S); + S.sendto = edit_bool(8,16,S.sendto, (char *)"^Send^ files to this node"); + S.receivefrom = edit_bool(9,16,S.receivefrom, (char *)"^Receive^ files from this node"); + S.pause = edit_bool(10,16,S.pause, (char *)"Is this node ^paused^"); + break; + case 5: akan = PickAka((char *)"10.2.5", TRUE); + break; + } + + E_Group(&mgr, (char *)"SELECT TIC GROUPS TO CHANGE"); + + /* + * Show settings before proceeding + */ + switch (menu) { + case 1: mvprintw(7, 6, "Delete aka %s", aka2str(a1)); + break; + case 2: mvprintw(7, 6, "Add aka %s", aka2str(a2)); + break; + case 3: p = xstrcpy(aka2str(a1)); + mvprintw(7, 6, "Replace aka %s with %s", p, aka2str(a2)); + free(p); + break; + case 4: ShowTicStatus(S); + mvprintw(14, 6, "Change the link status"); + case 5: if (akan != -1) + mvprintw( 7, 6, "Set %s as new aka to use", aka2str(CFG.aka[akan])); + break; + case 6: mvprintw(7, 6, "Delete TIC areas"); + break; + } + + if (yes_no((char *)"Perform changes")) { + working(1, 0, 0); + Areas = CountTicarea(); + Total = Done = 0; + + for (areanr = 1; areanr <= Areas; areanr++) { + offset = LoadTicRec(areanr, FALSE); + if (tic.Active && strlen(tic.Group)) { + for (tmp = mgr; tmp; tmp = tmp->next) { + if (tmp->tagged && (strcmp(tmp->group, tic.Group) == 0)) { + Total++; + switch (menu) { + case 1: fseek(ttfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) { + if ((Sc.aka.zone == a1.zone) && + (Sc.aka.net == a1.net) && + (Sc.aka.node == a1.node) && + (Sc.aka.point == a1.point)) { + fseek(ttfil, - sizeof(sysconnect), SEEK_CUR); + memset(&Sc, 0, sizeof(sysconnect)); + fwrite(&Sc, sizeof(sysconnect), 1, ttfil); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Deleted %s from %s", aka2str(a1), tic.Name); + } + break; + } + } + break; + case 2: fseek(ttfil, 0, SEEK_SET); + Found = FALSE; + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) + if ((Sc.aka.zone == a2.zone) && + (Sc.aka.net == a2.net) && + (Sc.aka.node == a2.node) && + (Sc.aka.point == a2.point)) { + Found = TRUE; + break; + } + if (Found) + break; + fseek(ttfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) { + if (Sc.aka.zone == 0) { + fseek(ttfil, - sizeof(sysconnect), SEEK_CUR); + memset(&Sc, 0, sizeof(sysconnect)); + Sc.aka.zone = a2.zone; + Sc.aka.net = a2.net; + Sc.aka.node = a2.node; + Sc.aka.point = a2.point; + Sc.sendto = TRUE; + Sc.receivefrom = FALSE; + sprintf(Sc.aka.domain, "%s", a2.domain); + fwrite(&Sc, sizeof(sysconnect), 1, ttfil); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Added %s to area %s", aka2str(a2), tic.Name); + } + break; + } + } + break; + case 3: fseek(ttfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) { + if ((Sc.aka.zone == a1.zone) && + (Sc.aka.net == a1.net) && + (Sc.aka.node == a1.node) && + (Sc.aka.point == a1.point)) { + Sc.aka.zone = a2.zone; + Sc.aka.net = a2.net; + Sc.aka.node = a2.node; + Sc.aka.point = a2.point; + sprintf(Sc.aka.domain, "%s", a2.domain); + fseek(ttfil, - sizeof(sysconnect), SEEK_CUR); + fwrite(&Sc, sizeof(sysconnect), 1, ttfil); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + p = xstrcpy(aka2str(a1)); + Syslog('+', "Changed %s into %s in area %s", p, aka2str(a2), tic.Name); + free(p); + } + break; + } + } + break; + case 4: fseek(ttfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) { + if ((Sc.aka.zone == S.aka.zone) && + (Sc.aka.net == S.aka.net) && + (Sc.aka.node == S.aka.node) && + (Sc.aka.point == S.aka.point)) { + Sc.sendto = S.sendto; + Sc.receivefrom = S.receivefrom; + Sc.pause = S.pause; + Sc.cutoff = S.cutoff; + fseek(ttfil, - sizeof(sysconnect), SEEK_CUR); + fwrite(&Sc, sizeof(sysconnect), 1, ttfil); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Changed status of %s in area %s", aka2str(S.aka), tic.Name); + } + break; + } + } + break; + case 5: if (akan != -1) { + if ((tic.Aka.zone != CFG.aka[akan].zone) || + (tic.Aka.net != CFG.aka[akan].net) || + (tic.Aka.node != CFG.aka[akan].node) || + (tic.Aka.point != CFG.aka[akan].point)) { + tic.Aka.zone = CFG.aka[akan].zone; + tic.Aka.net = CFG.aka[akan].net; + tic.Aka.node = CFG.aka[akan].node; + tic.Aka.point = CFG.aka[akan].point; + sprintf(tic.Aka.domain, "%s", CFG.aka[akan].domain); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Area %s now uses aka %s", tic.Name, aka2str(tic.Aka)); + } + } + } + break; + case 6: if (tic.Active) { + tic.Active = FALSE; + tic.Deleted = TRUE; + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Deleted TIC area %s", tic.Name); + } + } + break; + } + } + } + } + if (ttfil != NULL) + fclose(ttfil); + } + + working(0, 0, 0); + mvprintw(LINES -3, 6,"Made %d changes in %d possible areas", Done, Total); + (void)readkey(LINES -3, 50, LIGHTGRAY, BLACK); + if (Done) + TicUpdated = TRUE; + } + } + + tidy_grlist(&mgr); +} + + + + +/** + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditTicRec(int); +int EditTicRec(int Area) +{ + unsigned long crc1; + int tmp, i, changed = FALSE; + sysconnect System; + + clr_index(); + IsDoing("Edit Tic Area"); + + if (LoadTicRec(Area, TRUE) == -1) + return -1; + + SetTicScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6,16,55, tic.Comment); + show_str( 7,16,20, tic.Name); + show_int( 8,16, tic.FileArea); + show_str( 9,16,14, tic.Message); + show_str(10,16,12, tic.Group); + show_int(11,16, tic.KeepLatest); + show_str(12,16,20, aka2str(tic.Aka)); + show_str(13,16,5, tic.Convert); + show_str(14,16,14, tic.Banner); + show_bool(15,16, tic.Replace); + + show_bool( 7,51, tic.DupCheck); + show_bool( 8,51, tic.Secure); + show_bool( 9,51, tic.NoTouch); + show_bool(10,51, tic.VirScan); + show_bool(11,51, tic.Announce); + show_bool(12,51, tic.UpdMagic); + show_bool(13,51, tic.FileId); + show_bool(14,51, tic.ConvertAll); + show_bool(15,51, tic.SendOrg); + + show_bool( 7,73, tic.Mandat); + show_bool( 8,73, tic.Notified); + show_bool( 9,73, tic.UplDiscon); + show_bool(10,73, tic.Deleted); + show_bool(11,73, tic.Active); + + switch(select_menu(25)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&tic, crc1, tichdr.recsize); + fseek(ttfil, 0, 0); + for (i = 0; i <= (tichdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, ttfil); + crc1 = upd_crc32((char *)&System, crc1, sizeof(sysconnect)); + } + if ((TicCrc != crc1) || (changed)) { + if (yes_no((char *)"Record is changed, save") == 1) { + if (SaveTicRec(Area, TRUE) == -1) + return -1; + TicUpdated = 1; + Syslog('+', "Saved tic record %d", Area); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 6,16,55, tic.Comment, "The ^description^ for this area."); + case 2: E_STR( 7,16,20, tic.Name, "The ^name^ of this ^TIC^ area."); + case 3: tmp = PickFilearea((char *)"10.2.3"); + if (tmp != 0) + tic.FileArea = tmp; + SetTicScreen(); + break; + case 4: E_STR( 9,16,14, tic.Message, "The ^message^ to include with the .tic files."); + case 5: strcpy(tic.Group, PickFGroup((char *)"10.2.5")); + if (strlen(tic.Group)) { + tic.Aka = fgroup.UseAka; + /* + * If there is an uplink defined in the group, + * and the first connected system is empty, + * copy the uplink as default connection. + */ + if (fgroup.UpLink.zone) { + fseek(ttfil, 0, SEEK_SET); + fread(&System, sizeof(sysconnect), 1, ttfil); + if (!System.aka.zone) { + memset(&System, 0, sizeof(sysconnect)); + System.aka = fgroup.UpLink; + System.receivefrom = TRUE; + fseek(ttfil, 0, SEEK_SET); + fwrite(&System, sizeof(sysconnect), 1, ttfil); + } + } + } + SetTicScreen(); + break; + case 6: E_INT(11,16, tic.KeepLatest, "^Keep^ the ^latest^ number of files."); + case 7: tmp = PickAka((char *)"10.2.7", TRUE); + if (tmp != -1) + tic.Aka = CFG.aka[tmp]; + SetTicScreen(); + break; + case 8: strcpy(tic.Convert, PickArchive((char *)"10.2.8")); + SetTicScreen(); + break; + case 9: E_STR(14,16,14, tic.Banner, "The ^banner^ to put in the file archives"); + case 10:E_BOOL(15,16, tic.Replace, "Allow ^Replace^ files command"); + case 11:E_BOOL( 7,51, tic.DupCheck, "Check for ^duplicates^ in received files"); + case 12:E_BOOL( 8,51, tic.Secure, "Check for ^secure^ systems"); + case 13:E_BOOL( 9,51, tic.NoTouch, "Don't ^touch^ filedate"); + case 14:E_BOOL(10,51, tic.VirScan, "Check received files for ^virusses^"); + case 15:E_BOOL(11,51, tic.Announce, "^Announce^ received files"); + case 16:E_BOOL(12,51, tic.UpdMagic, "Update files ^magic^ names"); + case 17:E_BOOL(13,51, tic.FileId, "Extract ^FILE_ID.DIZ^ from received files"); + case 18:E_BOOL(14,51, tic.ConvertAll, "^Convert^ archive always"); + case 19:E_BOOL(15,51, tic.SendOrg, "^Send original^ file to downlinks"); + case 20:E_BOOL( 7,73, tic.Mandat, "Is this area ^mandatory^"); + case 21:E_BOOL( 8,73, tic.Notified, "Is the sysop ^notified^ if this area is (dis)connected"); + case 22:E_BOOL( 9,73, tic.UplDiscon, "Is the uplink ^disconnected^ from this area"); + case 23:E_BOOL(10,73, tic.Deleted, "Is this area ^deleted^"); + case 24:E_BOOL(11,73, tic.Active, "Is this area ^active^"); + case 25: + if (EditTicConnections(ttfil)) + changed = TRUE; + SetTicScreen(); + break; + + } + } +} + + + +void EditTicarea(void) +{ + int records, i, o, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountTicarea(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenTicarea() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 3, "10.2 TIC AREA SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&tichdr, sizeof(tichdr), 1, fil); + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = sizeof(tichdr) + (((o + i) - 1) * (tichdr.recsize + tichdr.syssize)); + fseek(fil, offset, 0); + fread(&tic, tichdr.recsize, 1, fil); + if (tic.Active) { + set_color(CYAN, BLACK); + sprintf(temp, "%3d. %-20s %-40s", o + i, tic.Name, tic. +Comment); + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d.", o + i); + } + mvprintw(y, 2, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_area(records, 10)); + + if (strncmp(pick, "-", 1) == 0) { + CloseTicarea(FALSE); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendTicarea() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "G", 1) == 0) { + TicGlobal(); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o = o + 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o = o - 10; + + if (strncmp(pick, "M", 1) == 0) + errmsg((char *)"This has no use here"); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + EditTicRec(atoi(pick)); + o = ((atoi(pick) - 1) / 10) * 10; + } + } +} + + + +char *PickTicarea(char *shdr) +{ + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + static char Buf[81]; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return '\0'; + } + + records = CountTicarea(); + if (records == -1) { + working(2, 0, 0); + return '\0'; + } + + working(0, 0, 0); + + for(;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. TIC AREA SELECT", shdr); + mvprintw(5, 3, temp); + set_color(CYAN, BLACK); + + if (records) { + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&tichdr, sizeof(tichdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = tichdr.hdrsize + (((o + i) - 1) * (tichdr.recsize + tichdr.syssize)); + fseek(fil, offset, SEEK_SET); + fread(&tic, tichdr.recsize, 1, fil); + if (tic.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-20s %-40s", o + i, tic.Name, tic.Comment); + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 10)); + + if (strncmp(pick, "-", 1) == 0) + return '\0'; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o += 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o -= 10; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + offset = tichdr.hdrsize + ((atoi(pick) -1) * (tichdr.recsize + tichdr.syssize)); + fseek(fil, offset, SEEK_SET); + fread(&tic, tichdr.recsize, 1, fil); + fclose(fil); + if (tic.Active) { + memset(&Buf, 0, sizeof(Buf)); + sprintf(Buf, "%s", tic.Name); + return Buf; + } + } + } + } +} + + + +int GroupInTic(char *Group) +{ + char temp[81]; + FILE *no; + int systems, Area = 0, RetVal = 0; + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return 0; + + fread(&tichdr, sizeof(tichdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, no); + systems = tichdr.syssize / sizeof(sysconnect); + + while ((fread(&tic, tichdr.recsize, 1, no)) == 1) { + Area++; + + if (!strcmp(tic.Group, Group) && strlen(tic.Group)) { + RetVal++; + Syslog('-', "Group %s in tic area %d: %s", Group, Area, tic.Name); + } + + fseek(no, tichdr.syssize, SEEK_CUR); + } + + fclose(no); + return RetVal; +} + + + +int NodeInTic(fidoaddr A) +{ + int i, Area = 0, RetVal = 0, systems; + FILE *no; + char temp[128]; + sysconnect S; + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return 0; + + fread(&tichdr, sizeof(tichdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, no); + systems = tichdr.syssize / sizeof(sysconnect); + + while ((fread(&tic, tichdr.recsize, 1, no)) == 1) { + Area++; + for (i = 0; i < systems; i++) { + fread(&S, sizeof(sysconnect), 1, no); + if (S.aka.zone && (S.aka.zone == A.zone) && (S.aka.net == A.net) && + (S.aka.node == A.node) && (S.aka.point == A.point) && tic.Active) { + RetVal++; + Syslog('-', "Node %s connected to tic area %d: %s", aka2str(A), Area, tic.Name); + } + } + } + + fclose(no); + return RetVal; +} + + + +int tic_areas_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81], status[4]; + FILE *no; + int i, systems, First = TRUE; + sysconnect System; + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + fread(&tichdr, sizeof(tichdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, no); + systems = tichdr.syssize / sizeof(sysconnect); + + while ((fread(&tic, tichdr.recsize, 1, no)) == 1) { + + page = newpage(fp, page); + + if (First) { + addtoc(fp, toc, 10, 2, page, (char *)"File processing areas"); + First = FALSE; + fprintf(fp, "\n"); + } else + fprintf(fp, "\n\n"); + + fprintf(fp, " Area tag %s\n", tic.Name); + fprintf(fp, " Active %s\n", getboolean(tic.Active)); + fprintf(fp, " Comment %s\n", tic.Comment); + fprintf(fp, " BBS area %ld\n", tic.FileArea); + fprintf(fp, " Message %s\n", tic.Message); + fprintf(fp, " Group %s\n", tic.Group); + fprintf(fp, " Keep Numbe %d\n", tic.KeepLatest); + fprintf(fp, " Fido Aka %s\n", aka2str(tic.Aka)); + fprintf(fp, " Convert to %s\n", tic.Convert); + fprintf(fp, " Convert all %s\n", getboolean(tic.ConvertAll)); + fprintf(fp, " Banner file %s\n", tic.Banner); + fprintf(fp, " Replace ok. %s\n", getboolean(tic.Replace)); + fprintf(fp, " Dupe check %s\n", getboolean(tic.DupCheck)); + fprintf(fp, " Secure %s\n", getboolean(tic.Secure)); + fprintf(fp, " No touch %s\n", getboolean(tic.NoTouch)); + fprintf(fp, " Virus scan %s\n", getboolean(tic.VirScan)); + fprintf(fp, " Announce %s\n", getboolean(tic.Announce)); + fprintf(fp, " Upd. magic %s\n", getboolean(tic.UpdMagic)); + fprintf(fp, " FILE_ID.DIZ %s\n", getboolean(tic.FileId)); + fprintf(fp, " Mandatory %s\n", getboolean(tic.Mandat)); + fprintf(fp, " Upl. discon %s\n", getboolean(tic.UplDiscon)); + fprintf(fp, " Notified %s\n\n", getboolean(tic.Notified)); + + for (i = 0; i < systems; i++) { + fread(&System, sizeof(sysconnect), 1, no); + if (System.aka.zone) { + memset(&status, 0, 4); + memset(&status, '-', 3); + if (System.sendto) + status[0] = 'S'; + if (System.receivefrom) + status[1] = 'R'; + if (System.pause) + status[2] = 'P'; + fprintf(fp, " Link %2d %s %s\n", i+1, status, aka2str(System.aka)); + } + } + } + + fclose(no); + return page; +} + + + diff --git a/mbsetup/m_ticarea.h b/mbsetup/m_ticarea.h new file mode 100644 index 00000000..a8f0fa11 --- /dev/null +++ b/mbsetup/m_ticarea.h @@ -0,0 +1,16 @@ +#ifndef _TICAREA_H +#define _TICAREA_H + + +int OpenTicarea(void); +void CloseTicarea(int); +int NodeInTic(fidoaddr); +int CountTicarea(void); +void EditTicarea(void); +char *PickTicarea(char *); +int GroupInTic(char *); +int tic_areas_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_tty.c b/mbsetup/m_tty.c new file mode 100644 index 00000000..b73c136c --- /dev/null +++ b/mbsetup/m_tty.c @@ -0,0 +1,518 @@ +/***************************************************************************** + * + * File ..................: setup/m_tty.c + * Purpose ...............: Setup Ttyinfo structure. + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_modem.h" +#include "m_global.h" +#include "m_tty.h" + + + +int TtyUpdated = 0; + + +/* + * Count nr of ttyinfo records in the database. + * Creates the database if it doesn't exist. + */ +int CountTtyinfo(void) +{ + FILE *fil; + char ffile[81]; + int count, i; + + sprintf(ffile, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + ttyinfohdr.hdrsize = sizeof(ttyinfohdr); + ttyinfohdr.recsize = sizeof(ttyinfo); + fwrite(&ttyinfohdr, sizeof(ttyinfohdr), 1, fil); + + for (i = 0; i < 10; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "Network port %d", i+11); + sprintf(ttyinfo.tty, "pts/%d", i); + sprintf(ttyinfo.speed, "10 mbit"); + sprintf(ttyinfo.flags, "IBN,IFC,ITN:60177,XX"); + ttyinfo.type = NETWORK; + ttyinfo.available = TRUE; + sprintf(ttyinfo.name, "Network port #%d", i+11); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + for (i = 0; i < 10; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "Network port %d", i+1); + sprintf(ttyinfo.tty, "ttyp%d", i); + sprintf(ttyinfo.speed, "10 mbit"); + sprintf(ttyinfo.flags, "IBN,IFC,ITN:60177,XX"); + ttyinfo.type = NETWORK; + ttyinfo.available = TRUE; + sprintf(ttyinfo.name, "Network port #%d", i+1); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + for (i = 0; i < 6; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "Console port %d", i+1); + sprintf(ttyinfo.tty, "tty%d", i); + sprintf(ttyinfo.speed, "10 mbit"); + ttyinfo.type = LOCAL; + ttyinfo.available = TRUE; + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + for (i = 0; i < 4; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "ISDN line %d", i+1); + sprintf(ttyinfo.tty, "ttyI%d", i); + sprintf(ttyinfo.speed, "64 kbits"); + sprintf(ttyinfo.flags, "XA,X75,CM"); + ttyinfo.type = ISDN; + ttyinfo.available = FALSE; + ttyinfo.callout = TRUE; + ttyinfo.honor_zmh = TRUE; + sprintf(ttyinfo.name, "ISDN line #%d", i+1); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + for (i = 0; i < 4; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "Modem line %d", i+1); + sprintf(ttyinfo.tty, "ttyS%d", i); + sprintf(ttyinfo.speed, "33.6 kbits"); + sprintf(ttyinfo.flags, "CM,XA,V32B,V42B,V34"); + ttyinfo.type = POTS; + ttyinfo.available = FALSE; + ttyinfo.callout = TRUE; + ttyinfo.honor_zmh = TRUE; + ttyinfo.portspeed = 57600; + sprintf(ttyinfo.name, "Modem line #%d", i+1); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + fclose(fil); + return 34; + } else + return -1; + } + + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - ttyinfohdr.hdrsize) / ttyinfohdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenTtyinfo(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = ttyinfohdr.recsize; + if (oldsize != sizeof(ttyinfo)) + TtyUpdated = 1; + else + TtyUpdated = 0; + ttyinfohdr.hdrsize = sizeof(ttyinfohdr); + ttyinfohdr.recsize = sizeof(ttyinfo); + fwrite(&ttyinfohdr, sizeof(ttyinfohdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&ttyinfo, 0, sizeof(ttyinfo)); + while (fread(&ttyinfo, oldsize, 1, fin) == 1) { + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fout); + memset(&ttyinfo, 0, sizeof(ttyinfo)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseTtyinfo(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *tty = NULL, *tmp; + + sprintf(fin, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + + if (TtyUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&ttyinfohdr, ttyinfohdr.hdrsize, 1, fi); + fwrite(&ttyinfohdr, ttyinfohdr.hdrsize, 1, fo); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fi) == 1) + if (!ttyinfo.deleted) + fill_stlist(&tty, ttyinfo.tty, ftell(fi) - ttyinfohdr.recsize); + sort_stlist(&tty); + + for (tmp = tty; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&ttyinfo, ttyinfohdr.recsize, 1, fi); + fwrite(&ttyinfo, ttyinfohdr.recsize, 1, fo); + } + + tidy_stlist(&tty); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"ttyinfo.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendTtyinfo(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + fclose(fil); + TtyUpdated = 1; + return 0; + } else + return -1; +} + + +void TtyScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "6. EDIT TTY LINE"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Comment"); + mvprintw( 8, 6, "2. TTY Device"); + mvprintw( 9, 6, "3. Phone nr."); + mvprintw(10, 6, "4. Line Speed"); + mvprintw(11, 6, "5. Fido Flags"); + mvprintw(12, 6, "6. Line Type"); + mvprintw(13, 6, "7. Available"); + mvprintw(14, 6, "8. Auth. log"); + mvprintw(15, 6, "9. Honor ZMH"); + mvprintw(16, 6, "10. Deleted"); + mvprintw(17, 6, "11. Callout"); + + mvprintw(15,31, "12. Portspeed"); + mvprintw(16,31, "13. Modemtype"); + mvprintw(17,31, "14. EMSI name"); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditTtyRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Ttyinfo"); + + sprintf(mfile, "%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(ttyinfohdr) + ((Area -1) * sizeof(ttyinfo)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&ttyinfo, sizeof(ttyinfo), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&ttyinfo, crc, sizeof(ttyinfo)); + working(0, 0, 0); + TtyScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,21,40, ttyinfo.comment); + show_str( 8,21, 6, ttyinfo.tty); + show_str( 9,21,25, ttyinfo.phone); + show_str(10,21,20, ttyinfo.speed); + show_str(11,21,30, ttyinfo.flags); + show_linetype(12,21, ttyinfo.type); + show_bool(13,21, ttyinfo.available); + show_bool(14,21, ttyinfo.authlog); + show_bool(15,21, ttyinfo.honor_zmh); + show_bool(16,21, ttyinfo.deleted); + show_bool(17,21, ttyinfo.callout); + show_int( 15,45, ttyinfo.portspeed); + show_str( 16,45,30,ttyinfo.modem); + show_str( 17,45,35,ttyinfo.name); + + j = select_menu(14); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&ttyinfo, crc1, sizeof(ttyinfo)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + fclose(fil); + TtyUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,21,40,ttyinfo.comment, "The ^Comment^ for this record") + case 2: E_STR( 8,21,7, ttyinfo.tty, "The ^Device name^ of this tty line") + case 3: E_STR( 9,21,25,ttyinfo.phone, "The ^Phone number^ or ^Hostname^ or ^IP address^ of this tty line") + case 4: E_STR( 10,21,20,ttyinfo.speed, "The ^Speed^ of this device") + case 5: E_STR( 11,21,30,ttyinfo.flags, "The ^Fidonet Capability Flags^ for this tty line") + case 6: ttyinfo.type = edit_linetype(12,21, ttyinfo.type); break; + case 7: E_BOOL(13,21, ttyinfo.available,"Switch if this tty line is ^Available^ for use.") + case 8: E_BOOL(14,21, ttyinfo.authlog, "Is mgetty ^Auth^ logging available") + case 9: E_BOOL(15,21, ttyinfo.honor_zmh,"Honor ^Zone Mail Hour^ on this tty line") + case 10:E_BOOL(16,21, ttyinfo.deleted, "Is this tty line ^deleted") + case 11:E_BOOL(17,21, ttyinfo.callout, "Is this line available for ^calling out^") + case 12:E_INT (15,45, ttyinfo.portspeed,"The ^locked speed^ of this tty port (only for modems)") + case 13:strcpy(ttyinfo.modem, PickModem((char *)"6.13")); TtyScreen(); break; + case 14:E_STR( 17,45,30,ttyinfo.name, "The ^EMSI name^ for this tty line") + } + } + + return 0; +} + + + +void EditTtyinfo(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountTtyinfo(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenTtyinfo() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "6. TTY LINES SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20 ; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(ttyinfohdr) + (((o + i) - 1) * ttyinfohdr.recsize); + fseek(fil, offset, 0); + fread(&ttyinfo, ttyinfohdr.recsize, 1, fil); + if (ttyinfo.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-6s %-25s", o+i, ttyinfo.tty, ttyinfo.comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseTtyinfo(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendTtyinfo() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + EditTtyRec(atoi(pick)); + o = ((atoi(pick) -1) / 20) * 20; + } + } +} + + + +int tty_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *tty; + int j; + + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + if ((tty = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 6, 0, page, (char *)"TTY lines information"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, tty); + + while ((fread(&ttyinfo, ttyinfohdr.recsize, 1, tty)) == 1) { + if (j == 3) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " TTY name %s\n", ttyinfo.comment); + fprintf(fp, " Device name %s\n", ttyinfo.tty); + fprintf(fp, " Phone or DNS %s\n", ttyinfo.phone); + fprintf(fp, " Line speed %s\n", ttyinfo.speed); + fprintf(fp, " Fido flags %s\n", ttyinfo.flags); + fprintf(fp, " Equipment %s\n", getlinetype(ttyinfo.type)); + fprintf(fp, " Available %s\n", getboolean(ttyinfo.available)); + fprintf(fp, " Auth. log %s\n", getboolean(ttyinfo.authlog)); + fprintf(fp, " Honor ZMH %s\n", getboolean(ttyinfo.honor_zmh)); + fprintf(fp, " Callout %s\n", getboolean(ttyinfo.callout)); + fprintf(fp, " Modem type %s\n", ttyinfo.modem); + fprintf(fp, " Locked speed %ld\n", ttyinfo.portspeed); + fprintf(fp, " EMSI name %s\n", ttyinfo.name); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(tty); + return page; +} + + diff --git a/mbsetup/m_tty.h b/mbsetup/m_tty.h new file mode 100644 index 00000000..e25eac4c --- /dev/null +++ b/mbsetup/m_tty.h @@ -0,0 +1,10 @@ +#ifndef _TTY_H +#define _TTY_H + + +int CountTtyinfo(void); +void EditTtyinfo(void); +int tty_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_users.c b/mbsetup/m_users.c new file mode 100644 index 00000000..7f7fba2a --- /dev/null +++ b/mbsetup/m_users.c @@ -0,0 +1,509 @@ +/***************************************************************************** + * + * File ..................: setup/m_users.c + * Purpose ...............: Edit Users + * Last modification date : 29-Jul-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_archive.h" +#include "m_protocol.h" +#include "m_users.h" + + + +int UsrUpdated = 0; + + +/* + * Count nr of usrconfig records in the database. + * Creates the database if it doesn't exist. + */ +int CountUsers(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + usrconfighdr.hdrsize = sizeof(usrconfighdr); + usrconfighdr.recsize = sizeof(usrconfig); + fwrite(&usrconfighdr, sizeof(usrconfighdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + count = 0; + fread(&usrconfighdr, sizeof(usrconfighdr), 1, fil); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, fil) == 1) { + count++; + } + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenUsers(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/users.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/users.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&usrconfighdr, sizeof(usrconfighdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = usrconfighdr.recsize; + if (oldsize != sizeof(usrconfig)) + UsrUpdated = 1; + else + UsrUpdated = 0; + usrconfighdr.hdrsize = sizeof(usrconfighdr); + usrconfighdr.recsize = sizeof(usrconfig); + fwrite(&usrconfighdr, sizeof(usrconfighdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&usrconfig, 0, sizeof(usrconfig)); + while (fread(&usrconfig, oldsize, 1, fin) == 1) { + fwrite(&usrconfig, sizeof(usrconfig), 1, fout); + memset(&usrconfig, 0, sizeof(usrconfig)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseUsers(void) +{ + char fin[81], fout[81]; + + sprintf(fin, "%s/etc/users.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/users.temp", getenv("MBSE_ROOT")); + + if (UsrUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + if ((rename(fout, fin)) == 0) + unlink(fout); + Syslog('+', "Updated \"users.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendUsers(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/users.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&usrconfig, 0, sizeof(usrconfig)); + usrconfig.MailScan = TRUE; + usrconfig.ieFILE = TRUE; + fwrite(&usrconfig, sizeof(usrconfig), 1, fil); + fclose(fil); + UsrUpdated = 1; + return 0; + } else + return -1; +} + + + +void Screen1(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "15. EDIT USER"); + set_color(CYAN, BLACK); + mvprintw( 4,21, "First login"); + mvprintw( 5,21, "Last login"); + mvprintw( 6, 2, "1. Full Name"); + mvprintw( 7, 2, "2. Handle"); + mvprintw( 8, 2, "3. Location"); + mvprintw( 9, 2, "4. Address 1"); + mvprintw(10, 2, "5. Address 2"); + mvprintw(11, 2, "6. Address 3"); + mvprintw(12, 2, "7. Voicephone"); + mvprintw(13, 2, "8. Dataphone"); + mvprintw(14, 2, "9. Security"); + mvprintw(15, 2, "10. Birthdate"); + mvprintw(16, 2, "11. Expirydate"); + mvprintw(17, 2, "12. Expiry Sec"); + mvprintw(18, 2, "13. Unix uid"); + mvprintw(19, 2, "14. Comment"); + + mvprintw(12,37, "15. Password"); + mvprintw(13,37, "16. Sex"); + mvprintw(14,37, "17. Credit"); + mvprintw(15,37, "18. Protocol"); + mvprintw(16,37, "19. Archiver"); + mvprintw(17,37, "20. Hidden"); + mvprintw(18,37, "21. Hotkeys"); + + mvprintw( 4,63, "22. Color"); + mvprintw( 5,63, "23. Deleted"); + mvprintw( 6,63, "24. No Kill"); + mvprintw( 7,63, "25. Fs Chat"); + mvprintw( 8,63, "26. Locked"); + mvprintw( 9,63, "27. Silent"); + mvprintw(10,63, "28. CLS"); + mvprintw(11,63, "29. More"); + mvprintw(12,63, "30. Fs Edit"); + mvprintw(13,63, "31. MailScan"); + mvprintw(14,63, "32. Guest"); + mvprintw(15,63, "33. ShowNews"); + mvprintw(16,63, "34. NewFiles"); + mvprintw(17,63, "35. Ext Info"); + mvprintw(18,63, "36. Email"); +} + + + +void Fields1(void) +{ + char Date[30]; + struct tm *ld; + + set_color(WHITE, BLACK); + ld = localtime(&usrconfig.tFirstLoginDate); + sprintf(Date, "%02d-%02d-%04d %02d:%02d:%02d", ld->tm_mday, + ld->tm_mon+1, ld->tm_year + 1900, ld->tm_hour, ld->tm_min, ld->tm_sec); + show_str( 4,33,19, Date); + ld = localtime(&usrconfig.tLastLoginDate); + sprintf(Date, "%02d-%02d-%04d %02d:%02d:%02d", ld->tm_mday, + ld->tm_mon+1, ld->tm_year + 1900, ld->tm_hour, ld->tm_min, ld->tm_sec); + show_str( 5,33,19, Date); + show_str( 6,17,35, usrconfig.sUserName); + show_str( 7,17,35, usrconfig.sHandle); + show_str( 8,17,27, usrconfig.sLocation); + show_str( 9,17,40, usrconfig.address[0]); + show_str(10,17,40, usrconfig.address[1]); + show_str(11,17,40, usrconfig.address[2]); + show_str(12,17,19, usrconfig.sVoicePhone); + show_str(13,17,19, usrconfig.sDataPhone); + show_int(14,17, usrconfig.Security.level); + show_str(15,17,10, usrconfig.sDateOfBirth); + show_str(16,17,10, usrconfig.sExpiryDate); + show_int(17,17, usrconfig.ExpirySec.level); + show_str(18,17, 8, usrconfig.Name); + show_str(19,17,63, usrconfig.sComment); + + if (usrconfig.iPassword == 0) + show_str(12,50,12, (char *)"Invalid"); + else + show_str(12,50,12, (char *)"********"); + show_str( 13,50, 7,usrconfig.sSex); + show_int( 14,50, usrconfig.Credit); + show_str( 15,50,12,usrconfig.sProtocol); + show_str( 16,50, 5,usrconfig.Archiver); + show_bool(17,50, usrconfig.Hidden); + show_bool(18,50, usrconfig.HotKeys); + + show_bool( 4,76, usrconfig.GraphMode); + show_bool( 5,76, usrconfig.Deleted); + show_bool( 6,76, usrconfig.NeverDelete); + show_bool( 7,76, usrconfig.Chat); + show_bool( 8,76, usrconfig.LockedOut); + show_bool( 9,76, usrconfig.DoNotDisturb); + show_bool(10,76, usrconfig.Cls); + show_bool(11,76, usrconfig.More); + show_bool(12,76, usrconfig.FsMsged); + show_bool(13,76, usrconfig.MailScan); + show_bool(14,76, usrconfig.Guest); + show_bool(15,76, usrconfig.ieNEWS); + show_bool(16,76, usrconfig.ieFILE); + show_bool(17,76, usrconfig.OL_ExtInfo); + show_bool(18,76, usrconfig.Email); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditUsrRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j = 0; + unsigned long crc, crc1; + char temp[81]; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Users"); + + sprintf(mfile, "%s/etc/users.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(usrconfighdr) + ((Area -1) * sizeof(usrconfig)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&usrconfig, sizeof(usrconfig), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&usrconfig, crc, sizeof(usrconfig)); + working(0, 0, 0); + Screen1(); + + for (;;) { + Fields1(); + j = select_menu(36); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&usrconfig, crc1, sizeof(usrconfig)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&usrconfig, sizeof(usrconfig), 1, fil); + fclose(fil); + UsrUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 6,17,35,usrconfig.sUserName,"The ^First and Last name^ of this user") + case 2: E_STR( 7,17,35,usrconfig.sHandle, "The ^Handle^ of this user") + case 3: E_STR( 8,17,27,usrconfig.sLocation,"The users ^Location^") + case 4: + case 5: + case 6: E_STR(j+5,17,40,usrconfig.address[j-4],"^Address^") + case 7: E_STR(12,17,16, usrconfig.sVoicePhone, "The ^Voice Phone^ number of this user") + case 8: E_STR(13,17,16, usrconfig.sDataPhone, "The ^Data Phone^ number of this user") + case 9: E_USEC(14,17, usrconfig.Security, "15.9 EDIT USER SECURITY", Screen1) + break; + case 10:E_STR(15,17,10, usrconfig.sDateOfBirth,"The ^Date of Birth^ in DD-MM-YYYY format") + case 11:E_STR(16,17,10, usrconfig.sExpiryDate, "The ^Expiry Date^ in DD-MM-YYYY format, 00-00-0000 is no expire") + case 12:E_INT(17,17, usrconfig.ExpirySec.level,"The ^Expiry Level^ for this user") + case 13:E_STR(18,17,8, usrconfig.Name, "The ^Unix username^ for this user") + case 14:E_STR(19,17,62, usrconfig.sComment, "A ^Comment^ for this user") + case 15:strcpy(temp, edit_str(12,50,12, usrconfig.Password, (char *)"Enter the ^password^ for this user")); + if (strlen(temp)) { + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + strcpy(usrconfig.Password, temp); + usrconfig.iPassword = StringCRC32(tu(temp)); + } else { + working(2, 0, 0); + working(0, 0, 0); + } + break; + case 16:strcpy(usrconfig.sSex, tl(edit_str(13,50,7, usrconfig.sSex, (char *)"^Male^ or ^Female^"))); + break; + case 17:E_INT(14,50, usrconfig.Credit, "Users ^Credit^") + case 18:strcpy(temp, PickProtocol(15)); + if (strlen(temp) != 0) + strcpy(usrconfig.sProtocol, temp); + clr_index(); + Screen1(); + Fields1(); + break; + case 19:strcpy(temp, PickArchive((char *)"15")); + if (strlen(temp) != 0) + strcpy(usrconfig.Archiver, temp); + clr_index(); + Screen1(); + Fields1(); + break; + case 20:E_BOOL(17,50,usrconfig.Hidden, "Is user ^hidden^ on the BBS") + case 21:E_BOOL(18,50,usrconfig.HotKeys, "Is user using ^HotKeys^ for menus") + case 22:E_BOOL( 4,76,usrconfig.GraphMode, "Is user using ^ANSI^ colors") + case 23:E_BOOL( 5,76,usrconfig.Deleted, "Is user marked for ^deletion^") + case 24:E_BOOL( 6,76,usrconfig.NeverDelete, "^Never delete^ this user") + case 25:E_BOOL( 7,76,usrconfig.Chat, "User has ^IEMSI Chat^ capability") + case 26:E_BOOL( 8,76,usrconfig.LockedOut, "User is ^Locked Out^ of this BBS") + case 27:E_BOOL( 9,76,usrconfig.DoNotDisturb, "User will not be ^disturbed^") + case 28:E_BOOL(10,76,usrconfig.Cls, "Send ^ClearScreen code^ to users terminal") + case 29:E_BOOL(11,76,usrconfig.More, "User uses the ^More prompt^") + case 30:E_BOOL(12,76,usrconfig.FsMsged, "User uses the ^Fullscreen editor^") + case 31:E_BOOL(13,76,usrconfig.MailScan, "Don't check for ^new mail^") + case 32:E_BOOL(14,76,usrconfig.Guest, "This is a ^Guest^ account") + case 33:E_BOOL(15,76,usrconfig.ieNEWS, "Show ^News Bulletins^ when logging in") + case 34:E_BOOL(16,76,usrconfig.ieFILE, "Show ^New Files^ when logging in") + case 35:E_BOOL(17,76,usrconfig.OL_ExtInfo, "Add ^Extended Message Info^ in OLR download") + case 36:E_BOOL(18,76,usrconfig.Email, "User has a ^private email^ mailbox") + } + } + + return 0; +} + + + +void EditUsers(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountUsers(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenUsers() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 3, "15. USERS EDITOR"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/users.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&usrconfighdr, sizeof(usrconfighdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(usrconfighdr) + (((i + o) - 1) * usrconfighdr.recsize); + fseek(fil, offset, 0); + fread(&usrconfig, usrconfighdr.recsize, 1, fil); + if (!usrconfig.Deleted) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, usrconfig.sUserName); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseUsers(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendUsers() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditUsrRec(atoi(pick)); + } +} + + diff --git a/mbsetup/m_users.h b/mbsetup/m_users.h new file mode 100644 index 00000000..4bdd8740 --- /dev/null +++ b/mbsetup/m_users.h @@ -0,0 +1,11 @@ +/* m_users.h */ + +#ifndef _USERS_H +#define _USERS_H + + +int CountUsers(void); +void EditUsers(void); + +#endif + diff --git a/mbsetup/m_virus.c b/mbsetup/m_virus.c new file mode 100644 index 00000000..e232816c --- /dev/null +++ b/mbsetup/m_virus.c @@ -0,0 +1,419 @@ +/***************************************************************************** + * + * File ..................: setup/m_virus.c + * Purpose ...............: Setup Virus structure. + * Last modification date : 22-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_virus.h" + + + +int VirUpdated = 0; + + +/* + * Count nr of virscan records in the database. + * Creates the database if it doesn't exist. + */ +int CountVirus(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + virscanhdr.hdrsize = sizeof(virscanhdr); + virscanhdr.recsize = sizeof(virscan); + fwrite(&virscanhdr, sizeof(virscanhdr), 1, fil); + + /* + * Create some default records + */ + memset(&virscan, 0, sizeof(virscan)); + sprintf(virscan.comment, "AntiVir/Linux Scanner"); + sprintf(virscan.scanner, "/usr/bin/antivir"); + sprintf(virscan.options, "-allfiles -s -q"); + virscan.available = TRUE; + virscan.error = 0; + fwrite(&virscan, sizeof(virscan), 1, fil); + + memset(&virscan, 0, sizeof(virscan)); + sprintf(virscan.comment, "McAfee VirusScan for Linux"); + sprintf(virscan.scanner, "/usr/local/bin/uvscan"); + sprintf(virscan.options, "--noboot --noexpire -r --secure -"); + virscan.available = TRUE; + virscan.error = 0; + fwrite(&virscan, sizeof(virscan), 1, fil); + + fclose(fil); + return 2; + } else + return -1; + } + + fread(&virscanhdr, sizeof(virscanhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - virscanhdr.hdrsize) / virscanhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenVirus(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/virscan.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&virscanhdr, sizeof(virscanhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = virscanhdr.recsize; + if (oldsize != sizeof(virscan)) + VirUpdated = 1; + else + VirUpdated = 0; + virscanhdr.hdrsize = sizeof(virscanhdr); + virscanhdr.recsize = sizeof(virscan); + fwrite(&virscanhdr, sizeof(virscanhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&virscan, 0, sizeof(virscan)); + while (fread(&virscan, oldsize, 1, fin) == 1) { + fwrite(&virscan, sizeof(virscan), 1, fout); + memset(&virscan, 0, sizeof(virscan)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseVirus(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *vir = NULL, *tmp; + + sprintf(fin, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/virscan.temp", getenv("MBSE_ROOT")); + + if (VirUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&virscanhdr, virscanhdr.hdrsize, 1, fi); + fwrite(&virscanhdr, virscanhdr.hdrsize, 1, fo); + + while (fread(&virscan, virscanhdr.recsize, 1, fi) == 1) + if (!virscan.deleted) + fill_stlist(&vir, virscan.comment, ftell(fi) - virscanhdr.recsize); + sort_stlist(&vir); + + for (tmp = vir; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&virscan, virscanhdr.recsize, 1, fi); + fwrite(&virscan, virscanhdr.recsize, 1, fo); + } + + tidy_stlist(&vir); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"virscan.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendVirus(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/virscan.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&virscan, 0, sizeof(virscan)); + fwrite(&virscan, sizeof(virscan), 1, fil); + fclose(fil); + VirUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditVirRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit VirScan"); + + sprintf(mfile, "%s/etc/virscan.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(virscanhdr) + ((Area -1) * sizeof(virscan)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&virscan, sizeof(virscan), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&virscan, crc, sizeof(virscan)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 2, "4. EDIT VIRUS SCANNER"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Comment"); + mvprintw( 8, 2, "2. Command"); + mvprintw( 9, 2, "3. Options"); + mvprintw(10, 2, "4. Available"); + mvprintw(11, 2, "5. Deleted"); + mvprintw(12, 2, "6. Error lvl"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16,40, virscan.comment); + show_str( 8,16,64, virscan.scanner); + show_str( 9,16,64, virscan.options); + show_bool(10,16, virscan.available); + show_bool(11,16, virscan.deleted); + show_int( 12,16, virscan.error); + + j = select_menu(6); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&virscan, crc1, sizeof(virscan)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&virscan, sizeof(virscan), 1, fil); + fclose(fil); + VirUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,16,40,virscan.comment, "The ^Comment^ for this record") + case 2: E_STR( 8,16,64,virscan.scanner, "The full ^name and path^ to the binary of this scanner") + case 3: E_STR( 9,16,64,virscan.options, "The ^commandline options^ for this scanner") + case 4: E_BOOL(10,16, virscan.available,"Switch if this virus scanner is ^Available^ for use.") + case 5: E_BOOL(11,16, virscan.deleted, "Is this scanner ^deleted^") + case 6: E_INT( 12,16, virscan.error, "The ^Error Level^ the scanner returns when no virus is found") + } + } + + return 0; +} + + + +void EditVirus(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountVirus(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenVirus() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "4. VIRUS SCANNERS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/virscan.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&virscanhdr, sizeof(virscanhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(virscanhdr) + ((i - 1) * virscanhdr.recsize); + fseek(fil, offset, 0); + fread(&virscan, virscanhdr.recsize, 1, fil); + if (i == 11) { + x = 42; + y = 7; + } + if (virscan.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", i, virscan.comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseVirus(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendVirus() == 0) { + records++; + working(3, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditVirRec(atoi(pick)); + } +} + + +int virus_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *vir; + int j; + + sprintf(temp, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + if ((vir = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 4, 0, page, (char *)"Virus scanners"); + j = 0; + fprintf(fp, "\n\n"); + fread(&virscanhdr, sizeof(virscanhdr), 1, vir); + + while ((fread(&virscan, virscanhdr.recsize, 1, vir)) == 1) { + + if (j == 5) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Scanner name %s\n", virscan.comment); + fprintf(fp, " Command line %s\n", virscan.scanner); + fprintf(fp, " Options %s\n", virscan.options); + fprintf(fp, " Available %s\n", getboolean(virscan.available)); + fprintf(fp, " Errorlevel OK %d\n", virscan.error); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(vir); + return page; +} + + diff --git a/mbsetup/m_virus.h b/mbsetup/m_virus.h new file mode 100644 index 00000000..791ea11c --- /dev/null +++ b/mbsetup/m_virus.h @@ -0,0 +1,12 @@ +/* m_archive.h */ + +#ifndef _VIRUS_H +#define _VIRUS_H + + +int CountVirus(void); +void EditVirus(void); +int virus_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/mbsetup.c b/mbsetup/mbsetup.c new file mode 100644 index 00000000..f0c599c6 --- /dev/null +++ b/mbsetup/mbsetup.c @@ -0,0 +1,452 @@ +/***************************************************************************** + * + * File ..................: mbsetup.c + * Purpose ...............: Setup Program + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2801 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_bbs.h" +#include "m_mail.h" +#include "m_tic.h" +#include "m_fido.h" +#include "m_archive.h" +#include "m_virus.h" +#include "m_tty.h" +#include "m_limits.h" +#include "m_users.h" +#include "m_node.h" +#include "m_fdb.h" +#include "m_new.h" +#include "m_ff.h" +#include "m_modem.h" +#include "m_marea.h" +#include "m_ngroup.h" +#include "m_service.h" +#include "m_domain.h" +#include "m_task.h" + + +mode_t oldmask; /* Old umask value */ +extern int do_quiet; /* Suppress log to screen */ +int exp_golded = FALSE; /* Export GoldED config */ + + +static void die(int onsig) +{ + FILE *fp; + char *temp; + int i; + + signal(onsig, SIG_IGN); + screen_stop(); + + exp_golded = TRUE; + if (exp_golded && (config_read() != -1)) { + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/golded.inc", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "w")) != NULL) { + fprintf(fp, "; GoldED.inc -- Automatic created by mbsetup %s -- Do not edit!\n\n", VERSION); + fprintf(fp, "; Basic information\n;\n"); + fprintf(fp, "USERNAME %s\n\n", CFG.sysop_name); + fprintf(fp, "ADDRESS %s\n", aka2str(CFG.aka[0])); + for (i = 1; i < 40; i++) + if (CFG.akavalid[i]) + fprintf(fp, "AKA %s\n", aka2str(CFG.aka[i])); + fprintf(fp, "\n"); + + gold_akamatch(fp); + + fprintf(fp, "; JAM MessageBase Setup\n;\n"); + fprintf(fp, "JAMPATH %s/tmp/\n", getenv("MBSE_ROOT")); + fprintf(fp, "JAMHARDDELETE NO\n\n"); + + fprintf(fp, "; Semaphore files\n;\n"); + fprintf(fp, "SEMAPHORE NETSCAN %s/sema/mailout\n", getenv("MBSE_ROOT")); + fprintf(fp, "SEMAPHORE ECHOSCAN %s/sema/mailout\n\n", getenv("MBSE_ROOT")); + + gold_areas(fp); + Syslog('+', "Created new %s", temp); + } else { + WriteError("$Could not create %s", temp); + } + + free(temp); + } + + umask(oldmask); + if (onsig && (onsig <= NSIG)) + WriteError("MBSETUP finished on signal %s", SigName[onsig]); + else + Syslog(' ', "MBSETUP finished"); + ExitClient(0); +} + + + +void soft_info(void); +void soft_info(void) +{ + char *temp; + + temp = calloc(81, sizeof(char)); + clr_index(); + set_color(YELLOW, BLACK); + center_addstr( 6, (char *)"MBSE BBS"); + set_color(WHITE, BLACK); + center_addstr( 8, (char *)Copyright); + set_color(YELLOW, BLACK); + center_addstr(10, (char *)"Made in the Netherlands"); + set_color(WHITE, BLACK); +#ifdef __GLIBC__ + sprintf(temp, "Compiled on glibc v%d.%d", __GLIBC__, __GLIBC_MINOR__); +#else +#ifdef __GNU_LIBRARY__ + sprintf(temp, "Compiled on libc v%d", __GNU_LIBRARY__); +#else + sprintf(temp, "Compiled on unknown library"); +#endif +#endif + center_addstr(12, temp); + set_color(LIGHTGREEN, BLACK); + center_addstr(LINES -8, (char *)"This is free software; released under the terms of the GNU General"); + center_addstr(LINES -7, (char *)"Public License as published by the Free Software Foundation."); + set_color(CYAN, BLACK); + free(temp); + center_addstr(LINES -4, (char *)"Press any key"); + readkey(LINES - 4, COLS / 2 + 8, LIGHTGRAY, BLACK); +} + + + +void site_docs(void); +void site_docs(void) +{ + FILE *fp, *toc; + char temp[81], temp1[81]; + int page = 0, line = 0; + + if (config_read() == -1) + return; + + sprintf(temp, "%s/doc/site.doc", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "w")) == NULL) + return; + + sprintf(temp1, "%s/tmp/toc.tmp", getenv("MBSE_ROOT")); + if ((toc = fopen(temp1, "w+")) == NULL) { + fclose(fp); + return; + } + + clr_index(); + working(1, 0, 0); + IsDoing("Making Sitedocs"); + Syslog('+', "Start creating sitedocs"); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "17. CREATING SITEDOCS"); + set_color(CYAN, BLACK); + mvprintw( 7,11, (char *)"Create document in file %s", temp); + fflush(stdout); + + page = global_doc(fp, toc, page); + page = fido_doc(fp, toc, page); + page = archive_doc(fp, toc, page); + page = virus_doc(fp, toc, page); + page = modem_doc(fp, toc, page); + page = tty_doc(fp, toc, page); + page = node_doc(fp, toc, page); + page = bbs_doc(fp, toc, page); + page = mail_doc(fp, toc, page); + page = tic_doc(fp, toc, page); + page = newf_group_doc(fp, toc, page); + page = new_doc(fp, toc, page); + page = ff_doc(fp, toc, page); + page = service_doc(fp, toc, page); + page = domain_doc(fp, toc, page); + page = task_doc(fp, toc, page); + + /* + * Append table of contents + */ + page = newpage(fp, page); + addtoc(fp, toc, 17, 0, page, (char *)"Table of contents"); + fprintf(fp, "\n\n"); + line = 4; + rewind(toc); + + while (fgets(temp, 256, toc) != NULL) { + fprintf(fp, "%s", temp); + line++; + if (line == 56) { + page = newpage(fp, page); + line = 0; + } + } + + fprintf(fp, "\f"); + fclose(fp); + fclose(toc); + unlink(temp1); + + Syslog('+', "Sitedocs created"); + + page = line = 0; + sprintf(temp, "%s/doc/xref.doc", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "w")) == NULL) + return; + + sprintf(temp1, "%s/tmp/toc.tmp", getenv("MBSE_ROOT")); + if ((toc = fopen(temp1, "w+")) == NULL) { + fclose(fp); + return; + } + + Syslog('+', "Start creating crossreference"); + mvprintw( 8,11, (char *)"Create document in file %s", temp); + fflush(stdout); + + page = limit_users_doc(fp, toc, page); + + /* + * Append table of contents + */ + page = newpage(fp, page); + addtoc(fp, toc, 99, 0, page, (char *)"Table of contents"); + fprintf(fp, "\n\n"); + line = 4; + rewind(toc); + + while (fgets(temp, 256, toc) != NULL) { + fprintf(fp, "%s", temp); + line++; + if (line == 56) { + page = newpage(fp, page); + line = 0; + } + } + + fprintf(fp, "\f"); + fclose(fp); + fclose(toc); + unlink(temp1); + + Syslog('+', "Crossreference created"); + + page = line = 0; + sprintf(temp, "%s/doc/stat.doc", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "w")) == NULL) + return; + + sprintf(temp1, "%s/tmp/toc.tmp", getenv("MBSE_ROOT")); + if ((toc = fopen(temp1, "w+")) == NULL) { + fclose(fp); + return; + } + + Syslog('+', "Start creating statistics"); + mvprintw( 9,11, (char *)"Create document in file %s", temp); + fflush(stdout); + + /* + * Append table of contents + */ + page = newpage(fp, page); + addtoc(fp, toc, 99, 0, page, (char *)"Table of contents"); + fprintf(fp, "\n\n"); + line = 4; + rewind(toc); + + while (fgets(temp, 256, toc) != NULL) { + fprintf(fp, "%s", temp); + line++; + if (line == 56) { + page = newpage(fp, page); + line = 0; + } + } + + fprintf(fp, "\f"); + fclose(fp); + fclose(toc); + unlink(temp1); + + Syslog('+', "Statistics created"); + + working(0, 0, 0); + + center_addstr(LINES -4, (char *)"Press any key"); + readkey(LINES -4, COLS / 2 + 8, LIGHTGRAY, BLACK); + return; +} + + + +int main(int argc, char *argv[]) +{ + int loop = 1; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * Find out who is on the keyboard or automated the keyboard. + */ + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbsetup", (char *)"nowhere", (char *)"mbsetup.log", 0x1f, (char *)"error.log"); + + /* + * Read the global configuration data + */ + config_check(getenv("MBSE_ROOT")); + + /* + * Setup several signals so when the program terminate's it + * will properly close the curses screens. + */ + signal(SIGINT, (void (*))die); + signal(SIGBUS, (void (*))die); + signal(SIGSEGV,(void (*))die); + signal(SIGTERM,(void (*))die); + signal(SIGKILL,(void (*))die); + + oldmask = umask(002); + + screen_start((char *)"MBsetup"); + do_quiet = TRUE; + Syslog(' ', " "); + Syslog(' ', "MBSETUP v%s started by %s", VERSION, pw->pw_name); + + do { + IsDoing("Browsing Menu"); + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "0. MAIN SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Global configuration"); + mvprintw( 8, 6, "2. Edit Fido Networks"); + mvprintw( 9, 6, "3. Edit Archiver Programs"); + mvprintw(10, 6, "4. Edit Virus Scanners"); + mvprintw(11, 6, "5. Edit Modem types"); + mvprintw(12, 6, "6. Edit TTY lines info"); + mvprintw(13, 6, "7. Edit Fidonet Nodes"); + mvprintw(14, 6, "8. Edit BBS Setup"); + mvprintw(15, 6, "9. Edit Mail Setup"); + mvprintw(16, 6, "10. Edit File Echo's setup"); + mvprintw( 7,46, "11. Edit Newfiles Groups"); + mvprintw( 8,46, "12. Edit Newfiles Reports"); + mvprintw( 9,46, "13. Edit FileFind Setup"); + mvprintw(10,46, "14. Edit Files Database"); + mvprintw(11,46, "15. Edit BBS Users"); + mvprintw(12,46, "16. Edit Services"); + mvprintw(13,46, "17. Edit Domains"); + mvprintw(14,46, "18. Edit Task Manager"); + mvprintw(15,46, "19. Show software information"); + mvprintw(16,46, "20. Create site documents"); + + switch(select_menu(20)) { + case 0: + loop = 0; + break; + case 1: + global_menu(); + break; + case 2: + EditFidonet(); + break; + case 3: + EditArchive(); + break; + case 4: + EditVirus(); + break; + case 5: + EditModem(); + break; + case 6: + EditTtyinfo(); + break; + case 7: + EditNodes(); + break; + case 8: + bbs_menu(); + break; + case 9: + mail_menu(); + break; + case 10: + tic_menu(); + break; + case 11: + EditNGroup(); + break; + case 12: + EditNewfiles(); + break; + case 13: + EditFilefind(); + break; + case 14: + EditFDB(); + break; + case 15: + EditUsers(); + break; + case 16: + EditService(); + break; + case 17: + EditDomain(); + break; + case 18: + task_menu(); + break; + case 19: + soft_info(); + break; + case 20: + site_docs(); + break; + } + } while (loop == 1); + + die(0); + return 0; +} + diff --git a/mbsetup/mutil.c b/mbsetup/mutil.c new file mode 100644 index 00000000..893a19dc --- /dev/null +++ b/mbsetup/mutil.c @@ -0,0 +1,140 @@ +/***************************************************************************** + * + * File ..................: mutil.c + * Purpose ...............: Menu Utils + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" + + + +unsigned char readkey(int y, int x, int fg, int bg) +{ + int rc = -1, i; + unsigned char ch = 0; + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 9"); + exit(1); + } + Setraw(); + + i = 0; + while (rc == -1) { + if ((i % 10) == 0) + show_date(fg, bg, 0, 0); + + locate(y, x); + fflush(stdout); + rc = Waitchar(&ch, 5); + if ((rc == 1) && (ch != KEY_ESCAPE)) + break; + + if ((rc == 1) && (ch == KEY_ESCAPE)) + rc = Escapechar(&ch); + + if (rc == 1) + break; + i++; + Nopper(); + } + + Unsetraw(); + close(ttyfd); + + return ch; +} + + + +unsigned char testkey(int y, int x) +{ + int rc; + unsigned char ch = 0; + + locate(y, x); + fflush(stdout); + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 9"); + exit(1); + } + Setraw(); + + rc = Waitchar(&ch, 100); + if (rc == 1) { + if (ch == KEY_ESCAPE) + rc = Escapechar(&ch); + } + + Unsetraw(); + close(ttyfd); + + if (rc == 1) + return ch; + else + return '\0'; +} + + + +int newpage(FILE *fp, int page) +{ + page++; + fprintf(fp, "\f MBSE BBS v%-53s page %d\n", VERSION, page); + return page; +} + + + +void addtoc(FILE *fp, FILE *toc, int chapt, int par, int page, char *title) +{ + char temp[81]; + char *tit; + + sprintf(temp, "%s ", title); + tit = xstrcpy(title); + tu(tit); + + if (par) { + fprintf(toc, " %2d.%-3d %s %d\n", chapt, par, padleft(temp, 50, '.'), page); + fprintf(fp, "\n\n %d.%d. %s\n\n", chapt, par, tit); + } else { + fprintf(toc, " %2d %s %d\n", chapt, padleft(temp, 52, '.'), page); + fprintf(fp, "\n\n %d. %s\n", chapt, tit); + } + free(tit); +} + + + diff --git a/mbsetup/mutil.h b/mbsetup/mutil.h new file mode 100644 index 00000000..ea78cecb --- /dev/null +++ b/mbsetup/mutil.h @@ -0,0 +1,10 @@ +#ifndef _MUTIL_H +#define _MUTIL_H + +unsigned char readkey(int, int, int, int); +unsigned char testkey(int, int); +int newpage(FILE *, int); +void addtoc(FILE *, FILE *, int, int, int, char *); + +#endif + diff --git a/mbsetup/screen.c b/mbsetup/screen.c new file mode 100644 index 00000000..2f8f6b18 --- /dev/null +++ b/mbsetup/screen.c @@ -0,0 +1,271 @@ +/***************************************************************************** + * + * File ..................: screen.c + * Purpose ...............: Screen functions for setup. + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/ansi.h" +#include "../lib/common.h" +#include "screen.h" + + + +/************************************************************************* + * + * Global section + */ + + +void clrtoeol() +{ + int i; + + printf("\r"); + for (i = 0; i < COLS; i++) + putchar(' '); + printf("\r"); + fflush(stdout); +} + + + +void hor_lin(int y, int x, int len) +{ + int i; + + locate(y, x); + for (i = 0; i < len; i++) + putchar('-'); + fflush(stdout); +} + + + +static int old_f = -1; +static int old_b = -1; + +void set_color(int f, int b) +{ + if ((f != old_f) || (b != old_b)) { + old_f = f; + old_b = b; + colour(f, b); + fflush(stdout); + } +} + + + +static time_t lasttime; + +/* + * Show the current date & time in the second status row + */ +void show_date(int fg, int bg, int y, int x) +{ + time_t now; + char *p; + + time(&now); + if (now != lasttime) { + lasttime = now; + set_color(LIGHTGREEN, BLUE); + p = ctime(&now); + Striplf(p); + mvprintw(1, 44, (char *)"%s TZUTC %s", p, gmtoffset(now)); + p = asctime(gmtime(&now)); + Striplf(p); + mvprintw(2, 44, (char *)"%s UTC", p); + if (y && x) + locate(y, x); + set_color(fg, bg); + } +} + + + +void center_addstr(int y, char *s) +{ + mvprintw(y, (COLS / 2) - (strlen(s) / 2), s); +} + + + +/* + * Curses and screen initialisation. + */ +void screen_start(char *name) +{ + int i; + + TermInit(1); + /* + * Overwrite screen the first time, if user had it black on white + * it will change to white on black. clear() won't do the trick. + */ + set_color(LIGHTGRAY, BLUE); + locate(1, 1); + for (i = 0; i < LINES; i++) { + if (i == 3) + colour(LIGHTGRAY, BLACK); + clrtoeol(); + if (i < LINES) + printf("\n"); + } + fflush(stdout); + + set_color(WHITE, BLUE); + locate(1, 1); + printf((char *)"%s for MBSE BBS version %s", name, VERSION); + set_color(YELLOW, BLUE); + locate(2, 1); + printf((char *)ShortRight); + set_color(LIGHTGRAY, BLACK); + show_date(LIGHTGRAY, BLACK, 0, 0); + fflush(stdout); +} + + + +/* + * Screen deinit + */ +void screen_stop() +{ + set_color(LIGHTGRAY, BLACK); + clear(); + fflush(stdout); +} + + + +/* + * Message at the upperright window about actions + */ +void working(int txno, int y, int x) +{ + int i; + + /* + * If txno not 0 there will be something written. The + * reversed attributes for mono, or white on red for + * color screens is set. The cursor is turned off and + * original cursor position is saved. + */ + show_date(LIGHTGRAY, BLACK, 0, 0); + + if (txno != 0) + set_color(YELLOW, RED); + else + set_color(LIGHTGRAY, BLACK); + + switch (txno) { + case 0: mvprintw(4, 66, (char *)" "); + break; + case 1: mvprintw(4, 66, (char *)"Working . . ."); + break; + case 2: mvprintw(4, 66, (char *)">>> ERROR <<<"); + for (i = 1; i <= 5; i++) { + putchar(7); + fflush(stdout); + usleep(150000); + } + usleep(550000); + break; + case 3: mvprintw(4, 66, (char *)"Form inserted"); + putchar(7); + fflush(stdout); + sleep(1); + break; + case 4: mvprintw(4, 66, (char *)"Form deleted "); + putchar(7); + fflush(stdout); + sleep(1); + break; + } + + show_date(LIGHTGRAY, BLACK, 0, 0); + set_color(LIGHTGRAY, BLACK); + if (y && x) + locate(y, x); + fflush(stdout); +} + + + +/* + * Clear the middle window + */ +void clr_index() +{ + int i; + + set_color(LIGHTGRAY, BLACK); + for (i = 3; i <= (LINES - 1); i++) { + locate(i, 1); + clrtoeol(); + } +} + + + +/* + * Show help at the bottom of the screen. + */ +void showhelp(char *T) +{ + int f, i, x, forlim; + + f = FALSE; + locate(LINES-1, 1); + set_color(WHITE, RED); + clrtoeol(); + x = 0; + forlim = strlen(T); + + for (i = 0; i < forlim; i++) { + if (T[i] == '^') { + if (f == FALSE) { + f = TRUE; + set_color(YELLOW, RED); + } else { + f = FALSE; + set_color(WHITE, RED); + } + } else { + putchar(T[i]); + x++; + } + } + set_color(LIGHTGRAY, BLACK); + fflush(stdout); +} + + diff --git a/mbsetup/screen.h b/mbsetup/screen.h new file mode 100644 index 00000000..01f9809f --- /dev/null +++ b/mbsetup/screen.h @@ -0,0 +1,19 @@ +#ifndef _SCREEN_H +#define _SCREEN_H + + +void clrtoeol(void); +void hor_lin(int y, int x, int len); +void set_color(int f, int b); +void show_date(int f, int b, int y, int x); +void center_addstr(int y, char *s); +void screen_start(char *); +void screen_stop(void); +void working(int txno, int y, int x); +void clr_index(void); +void showhelp(char *T); + +// int menu_prompt(void); + +#endif + diff --git a/mbsetup/stlist.c b/mbsetup/stlist.c new file mode 100644 index 00000000..4d4c1d3e --- /dev/null +++ b/mbsetup/stlist.c @@ -0,0 +1,117 @@ +/***************************************************************************** + * + * File ..................: stlist.c + * Purpose ...............: String sorting for databases. + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "stlist.h" + + +/* + * Tidy the strings array + */ +void tidy_stlist(st_list ** fdp) +{ + st_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + + *fdp = NULL; +} + + + +/* + * Add a string to the array + */ +void fill_stlist(st_list **fdp, char *stringname, long pos) +{ + st_list *tmp; + + tmp = (st_list *)malloc(sizeof(st_list)); + tmp->next = *fdp; + sprintf(tmp->string, "%s", stringname); + tmp->pos = pos; + *fdp = tmp; +} + + + +int compstring(st_list **, st_list **); + +/* + * Sort the array of strings + */ +void sort_stlist(st_list **fdp) +{ + st_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) + return; + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (st_list **)malloc(n * sizeof(st_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) + vector[i++] = ta; + + qsort(vector, n, sizeof(st_list*), (int(*)(const void*, const void*))compstring); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compstring(st_list **fdp1, st_list **fdp2) +{ + return strcmp((*fdp1)->string, (*fdp2)->string); +} + diff --git a/mbsetup/stlist.h b/mbsetup/stlist.h new file mode 100644 index 00000000..4e08f459 --- /dev/null +++ b/mbsetup/stlist.h @@ -0,0 +1,17 @@ +#ifndef _STLIST_H +#define _STLIST_H + +typedef struct _st_list { + struct _st_list *next; + char string[81]; + long pos; +} st_list; + + +void tidy_stlist(st_list **); +void fill_stlist(st_list **, char *, long); +void sort_stlist(st_list **); + + +#endif + diff --git a/mbtask/Makefile.am b/mbtask/Makefile.am new file mode 100644 index 00000000..c81fd24e --- /dev/null +++ b/mbtask/Makefile.am @@ -0,0 +1,34 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +EXTRA_DIST = issue + +noinst_PROGRAMS = mbtask + +mbtask_SOURCES = mbtask.c mbtask.h signame.c signame.h taskutil.c taskutil.h \ +taskcomm.c taskcomm.h taskstat.c taskstat.h taskdisk.c taskdisk.h \ +taskregs.c taskregs.h taskinfo.c taskinfo.h outstat.c outstat.h \ +scanout.c scanout.h nodelist.c nodelist.h callstat.c callstat.h libs.h + +LDADD = ../lib/libmemwatch.a + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(INSTALL) -s -o root -g root -m 6711 mbtask $(bindir) + @if [ -f $(sysconfdir)/mbsed.conf ]; then \ + rm $(sysconfdir)/mbsed.conf ; \ + fi + @if [ -f $(sysconfdir)/client.conf ]; then \ + rm $(sysconfdir)/client.conf ; \ + fi + @if [ -f $(bindir)/mbsed ]; then \ + rm $(bindir)/mbsed ; \ + fi + @if [ ! -f $(sysconfdir)/issue ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0644 issue $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0644 issue $(sysconfdir)"; \ + fi + diff --git a/mbtask/Makefile.in b/mbtask/Makefile.in new file mode 100644 index 00000000..af3981fa --- /dev/null +++ b/mbtask/Makefile.in @@ -0,0 +1,396 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = issue + +noinst_PROGRAMS = mbtask + +mbtask_SOURCES = mbtask.c mbtask.h signame.c signame.h taskutil.c taskutil.h taskcomm.c taskcomm.h taskstat.c taskstat.h taskdisk.c taskdisk.h taskregs.c taskregs.h taskinfo.c taskinfo.h outstat.c outstat.h scanout.c scanout.h nodelist.c nodelist.h callstat.c callstat.h libs.h + + +LDADD = ../lib/libmemwatch.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbtask_OBJECTS = mbtask.o signame.o taskutil.o taskcomm.o taskstat.o \ +taskdisk.o taskregs.o taskinfo.o outstat.o scanout.o nodelist.o \ +callstat.o +mbtask_LDADD = $(LDADD) +mbtask_DEPENDENCIES = ../lib/libmemwatch.a +mbtask_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbtask_SOURCES) +OBJECTS = $(mbtask_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbtask/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbtask: $(mbtask_OBJECTS) $(mbtask_DEPENDENCIES) + @rm -f mbtask + $(LINK) $(mbtask_LDFLAGS) $(mbtask_OBJECTS) $(mbtask_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbtask + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +callstat.o: callstat.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskutil.h callstat.h +mbtask.o: mbtask.c libs.h ../config.h ../lib/memwatch.h ../lib/structs.h \ + signame.h taskstat.h taskutil.h taskregs.h taskcomm.h outstat.h \ + nodelist.h mbtask.h +nodelist.o: nodelist.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskutil.h nodelist.h +outstat.o: outstat.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskutil.h scanout.h nodelist.h callstat.h \ + outstat.h +scanout.o: scanout.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskutil.h scanout.h +signame.o: signame.c signame.h +taskcomm.o: taskcomm.c libs.h ../config.h ../lib/memwatch.h taskstat.h \ + taskregs.h taskdisk.h taskinfo.h taskutil.h taskcomm.h +taskdisk.o: taskdisk.c libs.h ../config.h ../lib/memwatch.h taskdisk.h \ + taskutil.h +taskinfo.o: taskinfo.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskinfo.h +taskregs.o: taskregs.c libs.h ../config.h ../lib/memwatch.h taskstat.h \ + taskregs.h taskutil.h +taskstat.o: taskstat.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskstat.h outstat.h taskutil.h +taskutil.o: taskutil.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h signame.h scanout.h taskutil.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(INSTALL) -s -o root -g root -m 6711 mbtask $(bindir) + @if [ -f $(sysconfdir)/mbsed.conf ]; then \ + rm $(sysconfdir)/mbsed.conf ; \ + fi + @if [ -f $(sysconfdir)/client.conf ]; then \ + rm $(sysconfdir)/client.conf ; \ + fi + @if [ -f $(bindir)/mbsed ]; then \ + rm $(bindir)/mbsed ; \ + fi + @if [ ! -f $(sysconfdir)/issue ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0644 issue $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0644 issue $(sysconfdir)"; \ + fi + +# 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/mbtask/callstat.c b/mbtask/callstat.c new file mode 100644 index 00000000..d49cf0e6 --- /dev/null +++ b/mbtask/callstat.c @@ -0,0 +1,135 @@ +/***************************************************************************** + * + * File ..................: mbtask/callstat.c + * Purpose ...............: Read mailer last call status + * Last modification date : 08-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskutil.h" +#include "callstat.h" + + +extern struct sysconfig CFG; + + +char *stsname(faddr *); +char *stsname(faddr *addr) +{ + static char buf[PATH_MAX]; + char *p, *domain=NULL; + char zpref[8]; + int i; + + sprintf(buf, "%s", CFG.outbound); + + if (CFG.addr4d) { + if ((addr->zone == 0) || (addr->zone == CFG.aka[0].zone)) + zpref[0] = '\0'; + else + sprintf(zpref, ".%03x", addr->zone); + } else { + /* + * If we got a 5d address we use the given domain, if + * we got a 4d address, we look for a matching domain name. + */ + if (addr->domain) + domain = xstrcpy(addr->domain); + else + for (i = 0; i < 40; i++) + if (CFG.aka[i].zone == addr->zone) { + domain = xstrcpy(CFG.aka[i].domain); + break; + } + + if ((domain != NULL) && (strlen(CFG.aka[0].domain) != 0) && + (strcasecmp(domain,CFG.aka[0].domain) != 0)) { + if ((p = strrchr(buf,'/'))) + p++; + else + p = buf; + strcpy(p, domain); + for (; *p; p++) + *p = tolower(*p); + for (i = 0; i < 40; i++) + if ((strlen(CFG.aka[i].domain)) && + (strcasecmp(CFG.aka[i].domain, domain) == 0)) + break; + + /* + * The default zone must be the first one in the + * setup, other zones get the hexadecimal zone + * number appended. + */ + if (CFG.aka[i].zone == addr->zone) + zpref[0] = '\0'; + else + sprintf(zpref, ".%03x", addr->zone); + } else { + /* + * this is our primary domain + */ + if ((addr->zone == 0) || (addr->zone == CFG.aka[0].zone)) + zpref[0]='\0'; + else + sprintf(zpref,".%03x",addr->zone); + } + } + + p = buf + strlen(buf); + + if (addr->point) + sprintf(p,"%s/%04x%04x.pnt/%08x.sts", zpref,addr->net,addr->node,addr->point); + else + sprintf(p,"%s/%04x%04x.sts",zpref,addr->net,addr->node); + + if (domain) + free(domain); + return buf; +} + + + +callstat *getstatus(faddr *addr) +{ + static callstat cst; + FILE *fp; + + cst.trytime = 0L; + cst.tryno = 0; + cst.trystat = 0; + + if ((fp = fopen(stsname(addr), "r"))) { + fread(&cst, sizeof(callstat), 1, fp); + fclose(fp); + } + + return &cst; +} + + diff --git a/mbtask/callstat.h b/mbtask/callstat.h new file mode 100644 index 00000000..dbe5bdbc --- /dev/null +++ b/mbtask/callstat.h @@ -0,0 +1,26 @@ +#ifndef CALLSTAT_H +#define CALLSTAT_H + + +#define ST_PORTERR 1 +#define ST_NOCONN 2 +#define ST_MDMERR 3 +#define ST_LOCKED 4 +#define ST_LOOKUP 6 +#define ST_NOCALL7 7 +#define ST_NOCALL8 8 +#define ST_NOPORT 9 +#define ST_NOTZMH 10 +#define ST_SESSION 30 + + +typedef struct _callstat { + time_t trytime; + int tryno; + int trystat; +} callstat; + + +callstat *getstatus(faddr*); + +#endif diff --git a/mbtask/issue b/mbtask/issue new file mode 100644 index 00000000..5011e912 --- /dev/null +++ b/mbtask/issue @@ -0,0 +1,12 @@ + + .--. Welcome at MBSE BBS Professional + |o_o | -------------------------------- + |:_/ | + // \\ \\ Abandon all hope ye who have entered cyberspace. + (| | ) + /'\\_ _/\`\\ + \\___)=(___/ +Powered by Linux. + +To start the bbs login with "bbs" without quotes. + diff --git a/mbtask/libs.h b/mbtask/libs.h new file mode 100644 index 00000000..d7698ea9 --- /dev/null +++ b/mbtask/libs.h @@ -0,0 +1,166 @@ +/***************************************************************************** + * + * File ..................: libs.h + * Purpose ...............: Libraries include list + * Last modification date : 05-jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 Internet: mbse@user.sourceforge.net + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#ifndef _LIBS_H +#define _LIBS_H + +#define TRUE 1 +#define FALSE 0 +#define SS_BUFSIZE 1024 /* Streams socket buffersize */ + + +#include "../config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../lib/memwatch.h" + + +/* + * Some older systems don;t have this + */ +#ifndef ICMP_FILTER +#define ICMP_FILTER 1 + +struct icmp_filter { + u_int32_t data; +}; + +#endif + + +/* some older glibc versions seem to lack this. */ +# ifndef IP_PKTINFO +# define IP_PKTINFO 8 +# endif +# ifndef CMSG_LEN +/* ---- from glibc 2.1.2 */ + + +/* Ancillary data object manipulation macros. */ +# if !defined __STRICT_ANSI__ && defined __GNUC__ && __GNUC__ >= 2 +# define CMSG_DATA(cmsg) ((cmsg)->__cmsg_data) +# else +# define CMSG_DATA(cmsg) ((unsigned char *) ((struct cmsghdr *) (cmsg) + 1)) +# endif +# define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr (mhdr, cmsg) +# define CMSG_FIRSTHDR(mhdr) \ + ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) \ + ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) NULL) +# define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \ + & ~(sizeof (size_t) - 1)) +# define CMSG_SPACE(len) (CMSG_ALIGN (len) \ + + CMSG_ALIGN (sizeof (struct cmsghdr))) +# define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +extern struct cmsghdr *__cmsg_nxthdr __P ((struct msghdr *__mhdr, + struct cmsghdr *__cmsg)); +# ifdef __USE_EXTERN_INLINES +# ifndef _EXTERN_INLINE +# define _EXTERN_INLINE extern __inline +# endif +_EXTERN_INLINE struct cmsghdr * +__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg) __THROW +{ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) + /* The kernel header does this so there may be a reason. */ + return 0; + + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); + if ((unsigned char *) (__cmsg + 1) >= ((unsigned char *) __mhdr->msg_control + + __mhdr->msg_controllen) + || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) + >= ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) + /* No more entries. */ + return 0; + return __cmsg; +} +# endif /* Use `extern inline'. */ +# endif + + +/* A macro to extract the pointer to the address of a struct sockaddr (_in or _in6) */ +#define SOCKA_A4(a) ((void *)&((struct sockaddr_in *)(a))->sin_addr) + + +/* Some old libs don't have socklen_t */ +#ifndef socklen_t +#define socklen_t unsigned int +#endif + + +#pragma pack(1) + +#define MAXNAME 35 +#define MAXUFLAGS 16 + +typedef struct _faddr { + char *name; + unsigned int point; + unsigned int node; + unsigned int net; + unsigned int zone; + char *domain; +} faddr; + + + + +#endif + diff --git a/mbtask/mbtask.c b/mbtask/mbtask.c new file mode 100644 index 00000000..ae0e13d4 --- /dev/null +++ b/mbtask/mbtask.c @@ -0,0 +1,1440 @@ +/***************************************************************************** + * + * File ..................: mbtask/mbtask.c + * Purpose ...............: MBSE BBS Task Manager + * Last modification date : 09-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "signame.h" +#include "taskstat.h" +#include "taskutil.h" +#include "taskregs.h" +#include "taskcomm.h" +#include "outstat.h" +#include "nodelist.h" +#include "mbtask.h" + + + +/* + * Defines. + * SLOWRUN is number of seconds for mailer calls. Use between 5 and 30. + */ +#define MAXTASKS 10 +#define SLOWRUN 20 +#define TMPNAME "TMP." +#define LCKNAME "LOCKTASK" +#define ICMP_BASEHDR_LEN 8 +#define ICMP_MAX_ERRS 5 +#define SET_SOCKA_LEN4(socka) +#define Copyright "Copyright (C) 1997-2001 Michiel Broek, All Rights Reserved" + + +typedef enum {P_INIT, P_SENT, P_FAIL, P_OK, P_ERROR, P_NONE} PINGSTATE; + + + +/* + * Global variables + */ +static onetask task[MAXTASKS]; /* Array with tasks */ +reg_info reginfo[MAXCLIENT]; /* Array with clients */ +static pid_t pgrp; /* Pids group */ +static char lockfile[PATH_MAX]; /* Lockfile */ +int sock = -1; /* Datagram socket */ +struct sockaddr_un servaddr; /* Server address */ +struct sockaddr_un from; /* From address */ +int fromlen; +static char spath[PATH_MAX]; /* Socket path */ +int logtrans = 0; /* Log transactions */ +struct taskrec TCFG; /* Task config record */ +struct sysconfig CFG; /* System config */ +struct _nodeshdr nodeshdr; /* Nodes header record */ +struct _nodes nodes; /* Nodes data record */ +struct _fidonethdr fidonethdr; /* Fidonet header rec. */ +struct _fidonet fidonet; /* Fidonet data record */ +time_t tcfg_time; /* Config record time */ +time_t cfg_time; /* Config record time */ +char tcfgfn[PATH_MAX]; /* Config file name */ +char cfgfn[PATH_MAX]; /* Config file name */ +int ping_isocket; /* Ping socket */ +int icmp_errs = 0; /* ICMP error counter */ +int internet = FALSE; /* Internet is down */ +float Load; /* System Load */ +int Processing; /* Is system running */ +int ZMH = FALSE; /* Zone Mail Hour */ +int UPSalarm = FALSE; /* UPS alarm status */ +extern int s_bbsopen; /* BBS open semafore */ +extern int s_scanout; /* Scan outbound sema */ +extern int s_mailout; /* Mail out semafore */ +extern int s_mailin; /* Mail in semafore */ +extern int s_index; /* Compile nl semafore */ +extern int s_newnews; /* New news semafore */ +extern int s_reqindex; /* Create req index sem */ +extern int s_msglink; /* Messages link sem */ +int pingstate = P_INIT; /* Ping state */ +int pingnr = 1; /* Ping #, 1 or 2 */ +int pingresult[2]; /* Ping results */ +char pingaddress[41]; /* Ping current address */ + + + +/* + * Load main configuration, if it doesn't exist, create it. + * This is the case the very first time when you start MBSE BBS. + */ +void load_maincfg(void) +{ + FILE *fp; + struct utsname un; + int i; + + if ((fp = fopen(cfgfn, "r")) == NULL) { + memset(&CFG, 0, sizeof(CFG)); + + /* + * Fill Registration defaults + */ + sprintf(CFG.bbs_name, "MBSE BBS"); + uname((struct utsname *)&un); +#ifdef __USE_GNU + sprintf(CFG.sysdomain, "%s.%s", un.nodename, un.domainname); +#else + sprintf(CFG.sysdomain, "%s.%s", un.nodename, un.__domainname); +#endif + sprintf(CFG.comment, "MBSE Linux BBS development"); + sprintf(CFG.origin, "MBSE Linux BBS. Made in the Netherlands"); + sprintf(CFG.location, "Earth"); + + /* + * Fill Filenames defaults + */ + sprintf(CFG.logfile, "system.log"); + sprintf(CFG.error_log, "error.log"); + sprintf(CFG.default_menu, "main.mnu"); + sprintf(CFG.current_language, "english.lang"); + sprintf(CFG.chat_log, "chat.log"); + sprintf(CFG.welcome_logo, "logo.asc"); + + /* + * Fill Global defaults + */ + sprintf(CFG.bbs_menus, "%s/english/menus", getenv("MBSE_ROOT")); + sprintf(CFG.bbs_txtfiles, "%s/english/txtfiles", getenv("MBSE_ROOT")); + sprintf(CFG.bbs_usersdir, "%s/home", getenv("MBSE_ROOT")); + sprintf(CFG.nodelists, "/var/spool/mbse/nodelist"); + sprintf(CFG.inbound, "/var/spool/mbse/unknown"); + sprintf(CFG.pinbound, "/var/spool/mbse/inbound"); + sprintf(CFG.outbound, "/var/spool/mbse/outbound"); + sprintf(CFG.dospath, "a:"); /* The biggest floppy on earth, JvdW. */ + sprintf(CFG.uxpath, "/var/spool/mbse"); + sprintf(CFG.badtic, "/var/spool/mbse/badtic"); + sprintf(CFG.ticout, "/var/spool/mbse/ticqueue"); + sprintf(CFG.req_magic, "%s/magic", getenv("MBSE_ROOT")); + + /* + * Newfiles reports + */ + sprintf(CFG.ftp_base, "/var/spool/mbse/ftp"); + CFG.newdays = 30; + CFG.security.level = 20; + CFG.new_split = 27; + CFG.new_force = 30; + + /* + * BBS Globals + */ + CFG.CityLen = 6; + CFG.max_login = 5; + CFG.elite_mode = FALSE; + CFG.exclude_sysop = TRUE; + CFG.iConnectString = FALSE; + CFG.iAskFileProtocols = FALSE; + CFG.sysop_access = 32000; + CFG.password_length = 4; + CFG.iPasswd_Char = '.'; + CFG.idleout = 3; + CFG.iQuota = 10; + CFG.iCRLoginCount = 10; + CFG.bbs_loglevel = DLOG_ALLWAYS | DLOG_ERROR | DLOG_ATTENT | DLOG_NORMAL | DLOG_VERBOSE; + CFG.util_loglevel = DLOG_ALLWAYS | DLOG_ERROR | DLOG_ATTENT | DLOG_NORMAL | DLOG_VERBOSE; + CFG.OLR_NewFileLimit = 30; + CFG.OLR_MaxReq = 25; + CFG.slow_util = TRUE; + CFG.iCrashLevel = 100; + CFG.iAttachLevel = 100; + CFG.new_groups = 25; + + CFG.slow_util = TRUE; + CFG.iCrashLevel = 100; + CFG.iAttachLevel = 100; + CFG.new_groups = 25; + sprintf(CFG.startname, "bbs"); + CFG.freespace = 10; + + /* + * New Users + */ + CFG.newuser_access.level = 5; + CFG.iCapUserName = TRUE; + CFG.iAnsi = TRUE; + CFG.iDataPhone = TRUE; + CFG.iVoicePhone = TRUE; + CFG.iDOB = TRUE; + CFG.iTelephoneScan = TRUE; + CFG.iLocation = TRUE; + CFG.iHotkeys = TRUE; + CFG.iCapLocation = FALSE; + CFG.AskAddress = FALSE; + CFG.GiveEmail = TRUE; + + /* + * Colors + */ + CFG.TextColourF = 3; + CFG.TextColourB = 0; + CFG.UnderlineColourF = 14; + CFG.UnderlineColourB = 0; + CFG.InputColourF = 11; + CFG.InputColourB = 0; + CFG.CRColourF = 15; + CFG.CRColourB = 0; + CFG.MoreF = 13; + CFG.MoreB = 0; + CFG.HiliteF = 15; + CFG.HiliteB = 0; + CFG.FilenameF = 14; + CFG.FilenameB = 0; + CFG.FilesizeF = 13; + CFG.FilesizeB = 0; + CFG.FiledateF = 10; + CFG.FiledateB = 0; + CFG.FiledescF = 3; + CFG.FiledescB = 0; + CFG.MsgInputColourF = 3; + CFG.MsgInputColourB = 0; + + /* + * NextUser Door + */ + sprintf(CFG.sNuScreen, "welcome"); + sprintf(CFG.sNuQuote, "Please press [ENTER] to continue: "); + + /* + * Safe Door + */ + CFG.iSafeFirstDigit = 1; + CFG.iSafeSecondDigit = 2; + CFG.iSafeThirdDigit = 3; + CFG.iSafeMaxTrys = 4; + CFG.iSafeMaxNumber = 20; + CFG.iSafeNumGen = FALSE; + strcpy(CFG.sSafePrize, "Free access for a year!"); + sprintf(CFG.sSafeWelcome, "safewel"); + sprintf(CFG.sSafeOpened, "safeopen"); + + /* + * Paging + */ + CFG.iPageLength = 30; + CFG.iMaxPageTimes = 5; + CFG.iAskReason = TRUE; + CFG.iSysopArea = 1; + CFG.iExternalChat = FALSE; + strcpy(CFG.sExternalChat, "/usr/local/bin/chat"); + CFG.iAutoLog = TRUE; + strcpy(CFG.sChatDevice, "/dev/tty01"); + CFG.iChatPromptChk = TRUE; + CFG.iStopChatTime = TRUE; + for (i = 0; i < 7; i++) { + sprintf(CFG.cStartTime[i], "18:00"); + sprintf(CFG.cStopTime[i], "23:59"); + } + + /* + * Time Bank + */ + CFG.iMaxTimeBalance = 200; + CFG.iMaxTimeWithdraw = 100; + CFG.iMaxTimeDeposit = 60; + CFG.iMaxByteBalance = 500; + CFG.iMaxByteWithdraw = 300; + CFG.iMaxByteDeposit = 150; + strcpy(CFG.sTimeRatio, "3:1"); + strcpy(CFG.sByteRatio, "3:1"); + + /* + * Fill ticconf defaults + */ + CFG.ct_ResFuture = TRUE; + CFG.ct_ReplExt = TRUE; + CFG.ct_PlusAll = TRUE; + CFG.ct_Notify = TRUE; + CFG.ct_Message = TRUE; + CFG.ct_TIC = TRUE; + CFG.tic_days = 30; + sprintf(CFG.hatchpasswd, "DizIzMyBIGseeKret"); + CFG.drspace = 2048; + CFG.tic_systems = 10; + CFG.tic_groups = 25; + CFG.tic_dupes = 16000; + + /* + * Fill Mail defaults + */ + CFG.maxpktsize = 150; + CFG.maxarcsize = 300; + sprintf(CFG.badboard, "/var/spool/mbse/mail/badmail"); + sprintf(CFG.dupboard, "/var/spool/mbse/mail/dupmail"); + sprintf(CFG.popnode, "localhost"); + sprintf(CFG.smtpnode, "localhost"); + sprintf(CFG.nntpnode, "localhost"); + CFG.toss_days = 30; + CFG.toss_dupes = 16000; + CFG.toss_old = 60; + CFG.defmsgs = 500; + CFG.defdays = 90; + CFG.toss_systems = 10; + CFG.toss_groups = 25; + CFG.UUCPgate.zone = 2; + CFG.UUCPgate.net = 292; + CFG.UUCPgate.node = 875; + sprintf(CFG.UUCPgate.domain, "fidonet"); + CFG.nntpdupes = 16000; + + for (i = 0; i < 32; i++) + sprintf(CFG.fname[i], "Flag %d", i+1); + + + /* + * Fido mailer defaults + */ + CFG.timeoutreset = 3L; + CFG.timeoutconnect = 60L; + sprintf(CFG.phonetrans[0].match, "31-255"); + sprintf(CFG.phonetrans[1].match, "31-"); + sprintf(CFG.phonetrans[1].repl, "0"); + sprintf(CFG.phonetrans[2].repl, "00"); + CFG.Speed = 9600; + CFG.dialdelay = 60; + sprintf(CFG.Flags, "CM,XX,IBN,IFC,ITN"); + CFG.cico_loglevel = DLOG_ALLWAYS | DLOG_ERROR | DLOG_ATTENT | DLOG_NORMAL | DLOG_VERBOSE; + + /* + * FTP Server + */ + CFG.ftp_limit = 20; + CFG.ftp_loginfails = 2; + CFG.ftp_compress = TRUE; + CFG.ftp_tar = TRUE; + CFG.ftp_log_cmds = TRUE; + CFG.ftp_anonymousok = TRUE; + CFG.ftp_mbseok = FALSE; + sprintf(CFG.ftp_readme_login, "README*"); + sprintf(CFG.ftp_readme_cwd, "README*"); + sprintf(CFG.ftp_msg_login, "/welcome.msg"); + sprintf(CFG.ftp_msg_cwd, ".message"); + sprintf(CFG.ftp_msg_shutmsg, "/etc/nologin"); + sprintf(CFG.ftp_upl_path, "%s/incoming", CFG.ftp_base); + sprintf(CFG.ftp_banner, "%s/etc/ftpbanner", getenv("MBSE_ROOT")); + sprintf(CFG.ftp_email, "sysop@%s", CFG.sysdomain); + sprintf(CFG.ftp_pth_filter, "^[-A-Za-z0-9_\\.]*$ ^\\. ^-"); + sprintf(CFG.ftp_pth_message, "%s/etc/pathmsg", getenv("MBSE_ROOT")); + + /* + * WWW defaults + */ + sprintf(CFG.www_root, "/var/lib/apache/htdocs"); + sprintf(CFG.www_link2ftp, "files"); + sprintf(CFG.www_url, "http://%s", CFG.sysdomain); + sprintf(CFG.www_charset, "ISO 8859-1"); + sprintf(CFG.www_tbgcolor, "Silver"); + sprintf(CFG.www_hbgcolor, "Aqua"); + sprintf(CFG.www_author, "Your Name"); + sprintf(CFG.www_convert,"/usr/X11R6/bin/convert -geometry x100"); + sprintf(CFG.www_icon_home, "up.gif"); + sprintf(CFG.www_name_home, "Home"); + sprintf(CFG.www_icon_back, "back.gif"); + sprintf(CFG.www_name_back, "Back"); + sprintf(CFG.www_icon_prev, "left.gif"); + sprintf(CFG.www_name_prev, "Previous page"); + sprintf(CFG.www_icon_next, "right.gif"); + sprintf(CFG.www_name_next, "Next page"); + CFG.www_files_page = 10; + + if ((fp = fopen(cfgfn, "a+")) == NULL) { + perror(""); + fprintf(stderr, "Can't create %s\n", cfgfn); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(2); + } + fwrite(&CFG, sizeof(CFG), 1, fp); + fclose(fp); + } else { + fread(&CFG, sizeof(CFG), 1, fp); + fclose(fp); + } + + cfg_time = file_time(cfgfn); +} + + + +/* + * Load task configuration data. + */ +void load_taskcfg(void) +{ + FILE *fp; + + if ((fp = fopen(tcfgfn, "r")) == NULL) { + memset(&TCFG, 0, sizeof(TCFG)); + TCFG.maxload = 1.50; + sprintf(TCFG.zmh_start, "02:30"); + sprintf(TCFG.zmh_end, "03:30"); + sprintf(TCFG.cmd_mailout, "%s/bin/mbfido scan web -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_mailin, "%s/bin/mbfido tic toss web -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_newnews, "%s/bin/mbfido news web -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_mbindex1, "%s/bin/mbindex -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_mbindex2, "%s/bin/goldnode -f -q", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_msglink, "%s/bin/mbmsg link -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_reqindex, "%s/bin/mbfile index -quiet", getenv("MBSE_ROOT")); + TCFG.ipblocks = TRUE; + TCFG.max_pots = 1; + TCFG.max_isdn = 0; + TCFG.max_tcp = 0; + if ((fp = fopen(tcfgfn, "a+")) == NULL) { + tasklog('?', "$Can't create %s", tcfgfn); + die(2); + } + fwrite(&TCFG, sizeof(TCFG), 1, fp); + fclose(fp); + tasklog('+', "Created new %s", tcfgfn); + } else { + fread(&TCFG, sizeof(TCFG), 1, fp); + fclose(fp); + } + + tcfg_time = file_time(tcfgfn); +} + + + +/* + * Launch an external program in the background. + * On success add it to the tasklist and return + * the pid. + */ +pid_t launch(char *cmd, char *opts, char *name, int tasktype) +{ + char buf[PATH_MAX]; + char *vector[16]; + int i, rc = 0; + pid_t pid = 0; + + if (checktasks(0) >= MAXTASKS) { + tasklog('?', "Launch: can't execute %s, maximum tasks reached", cmd); + return 0; + } + + if (opts == NULL) + sprintf(buf, "%s", cmd); + else + sprintf(buf, "%s %s", cmd, opts); + + i = 0; + vector[i++] = strtok(buf," \t\n\0"); + while ((vector[i++] = strtok(NULL," \t\n")) && (i<16)); + vector[15] = NULL; + + if (file_exist(vector[0], X_OK)) { + tasklog('?', "Launch: can't execute %s, command not found", vector[0]); + return 0; + } + + pid = fork(); + switch (pid) { + case -1: + tasklog('?', "$Launch: error, can't fork grandchild"); + return 0; + case 0: + /* From Paul Vixies cron: */ + (void)setsid(); /* It doesn't seem to help */ + close(0); + if (open("/dev/null", O_RDONLY) != 0) { + tasklog('?', "$Launch: \"%s\": reopen of stdin to /dev/null failed", buf); +#ifdef MEMWATCH + mwTerm(); +#endif + _exit(-1); + } + close(1); + if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { + tasklog('?', "$Launch: \"%s\": reopen of stdout to /dev/null failed", buf); +#ifdef MEMWATCH + mwTerm(); +#endif + _exit(-1); + } + close(2); + if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { + tasklog('?', "$Launch: \"%s\": reopen of stderr to /dev/null failed", buf); +#ifdef MEMWATCH + mwTerm(); +#endif + _exit(-1); + } + errno = 0; + rc = execv(vector[0],vector); + tasklog('?', "$Launch: execv \"%s\" failed, returned %d", cmd, rc); +#ifdef MEMWATCH + mwTerm(); +#endif + _exit(-1); + default: + /* grandchild's daddy's process */ + break; + } + + /* + * Add it to the tasklist. + */ + for (i = 0; i < MAXTASKS; i++) { + if (strlen(task[i].name) == 0) { + strcpy(task[i].name, name); + strcpy(task[i].cmd, cmd); + if (opts) + strcpy(task[i].opts, opts); + task[i].pid = pid; + task[i].status = 0; + task[i].running = TRUE; + task[i].rc = 0; + task[i].tasktype = tasktype; + break; + } + } + + if (opts) + tasklog('+', "Launch: task %d \"%s %s\" success, pid=%d", i, cmd, opts, pid); + else + tasklog('+', "Launch: task %d \"%s\" success, pid=%d", i, cmd, pid); + return pid; +} + + + +/* + * Count specific running tasks + */ +int runtasktype(int tasktype) +{ + int i, count = 0; + + for (i = 0; i < MAXTASKS; i++) { + if (strlen(task[i].name) && task[i].running && (task[i].tasktype == tasktype)) + count++; + } + return count; +} + + + +/* + * Check all running tasks registered in the tasklist. + * Report programs that are stopped. If signal is set + * then send that signal. + */ +int checktasks(int onsig) +{ + int i, j, rc, count = 0, first = TRUE, status, do_outstat = FALSE; + + for (i = 0; i < MAXTASKS; i++) { + if (strlen(task[i].name)) { + + if (onsig) { + if (kill(task[i].pid, onsig) == 0) + tasklog('+', "%s to %s (pid %d) succeeded", SigName[onsig], task[i].name, task[i].pid); + else + tasklog('+', "%s to %s (pid %d) failed", SigName[onsig], task[i].name, task[i].pid); + } + + task[i].rc = wait4(task[i].pid, &status, WNOHANG | WUNTRACED, NULL); + if (task[i].rc) { + task[i].running = FALSE; + if (task[i].tasktype == CALL_POTS || task[i].tasktype == CALL_ISDN || task[i].tasktype == CALL_IP) + do_outstat = TRUE; + } + + if (first && task[i].rc) { + first = FALSE; + tasklog('t', "Task T pid stat status rc status"); + tasklog('t', "---------------- - ----- ---- ----------- ----- --------"); + for (j = 0; j < MAXTASKS; j++) + if (strlen(task[j].name)) + tasklog('t', "%-16s %d %5d %s %-11d %5d %08x", task[j].name, + task[j].tasktype, task[j].pid, task[j].running?"runs":"stop", + task[j].status, task[j].rc, task[j].status); + } + + switch (task[i].rc) { + case -1: + if (errno == ECHILD) + tasklog('+', "Task %d \"%s\" is ready", i, task[i].name); + else + tasklog('+', "Task %d \"%s\" is ready, error: %s", i, task[i].name, strerror(errno)); + break; + case 0: + /* + * Update last known status when running. + */ + task[i].status = status; + count++; + break; + default: + tasklog('+', "errno=%d %s", errno, strerror(errno)); + if (WIFEXITED(task[i].status)) { + rc = WEXITSTATUS(task[i].status); + if (rc) + tasklog('+', "Task %s is ready, error=%d", task[i].name, rc); + else + tasklog('+', "Task %s is ready", task[i].name); + } else if (WIFSIGNALED(task[i].status)) { + rc = WTERMSIG(task[i].status); + if (rc <= 31) + tasklog('+', "Task %s terminated on signal %s (%d)", task[i].name, SigName[rc], rc); + else + tasklog('+', "Task %s terminated with error nr %d", task[i].name, rc); + } else if (WIFSTOPPED(task[i].status)) { + rc = WSTOPSIG(task[i].status); + tasklog('+', "Task %s stopped on signal %s (%d)", task[i].name, SigName[rc], rc); + } else { + tasklog('+', "FIXME: 1"); + } + break; + } + + if (!task[i].running) + memset(&task[i], 0, sizeof(onetask)); + } + } + + if (do_outstat) + outstat(); + + return count; +} + + + +void die(int onsig) +{ + int i, count; + + signal(onsig, SIG_IGN); + tasklog('+', "Shutting down on signal %s", SigName[onsig]); + + /* + * First check if there are tasks running, if so try to stop them + */ + if ((count = checktasks(0))) { + tasklog('+', "There are %d tasks running, sending SIGTERM", count); + checktasks(SIGTERM); + for (i = 0; i < 15; i++) { + sleep(1); + count = checktasks(0); + if (count == 0) + break; + } + if (count) { + /* + * There are some diehards running... + */ + tasklog('+', "There are %d tasks running, sending SIGKILL", count); + count = checktasks(SIGKILL); + } + if (count) { + sleep(1); + count = checktasks(0); + if (count) + tasklog('?', "Still %d tasks running, giving up", count); + } + } + + ulocktask(); + if (sock != -1) + close(sock); + if (ping_isocket != -1) + close(ping_isocket); + if (!file_exist(spath, R_OK)) { + unlink(spath); + } + tasklog(' ', "MBTASK finished"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(onsig); +} + + + +/* + * Put a lock on this program. + */ +int locktask(char *root) +{ + char Tmpfile[81]; + FILE *fp; + pid_t oldpid; + + sprintf(Tmpfile, "%s/var/", root); + strcpy(lockfile, Tmpfile); + sprintf(Tmpfile + strlen(Tmpfile), "%s%u", TMPNAME, getpid()); + sprintf(lockfile + strlen(lockfile), "%s", LCKNAME); + + if ((fp = fopen(Tmpfile, "w")) == NULL) { + perror("mbtask"); + printf("Can't create lockfile \"%s\"\n", Tmpfile); + return 1; + } + fprintf(fp, "%10u\n", getpid()); + fclose(fp); + + while (TRUE) { + if (link(Tmpfile, lockfile) == 0) { + unlink(Tmpfile); + return 0; + } + if ((fp = fopen(lockfile, "r")) == NULL) { + perror("mbtask"); + printf("Can't open lockfile \"%s\"\n", Tmpfile); + unlink(Tmpfile); + return 1; + } + if (fscanf(fp, "%u", &oldpid) != 1) { + perror("mbtask"); + printf("Can't read old pid from \"%s\"\n", Tmpfile); + fclose(fp); + unlink(Tmpfile); + return 1; + } + fclose(fp); + if (kill(oldpid,0) == -1) { + if (errno == ESRCH) { + printf("Stale lock found for pid %u\n", oldpid); + unlink(lockfile); + /* no return, try lock again */ + } else { + perror("mbtask"); + printf("Kill for %u failed\n",oldpid); + unlink(Tmpfile); + return 1; + } + } else { + printf("Another mbtask is already running, pid=%u\n", oldpid); + unlink(Tmpfile); + return 1; + } + } +} + + + +void ulocktask(void) +{ + if (lockfile) + (void)unlink(lockfile); +} + + + +/* + * Takes a packet as send out and a recieved ICMP packet and looks whether the ICMP packet is + * an error reply on the sent-out one. packet is only the packet (without IP header). + * errmsg includes an IP header. + * to is the destination address of the original packet (the only thing that is actually + * compared of the IP header). The RFC sais that we get at least 8 bytes of the offending packet. + * We do not compare more, as this is all we need. + */ +static int icmp4_errcmp(char *packet, int plen, struct in_addr *to, char *errmsg, int elen, int errtype) +{ + struct iphdr iph; + struct icmphdr icmph; + struct iphdr eiph; + char *data; + + /* XXX: lots of memcpy to avoid unaligned accesses on alpha */ + if (elen < sizeof(struct iphdr)) + return 0; + memcpy(&iph, errmsg, sizeof(iph)); + if (iph.protocol != IPPROTO_ICMP || elen < iph.ihl * 4 + ICMP_BASEHDR_LEN + sizeof(eiph)) + return 0; + memcpy(&icmph, errmsg + iph.ihl * 4, ICMP_BASEHDR_LEN); + memcpy(&eiph, errmsg + iph.ihl * 4 + ICMP_BASEHDR_LEN, sizeof(eiph)); + if (elen < iph.ihl * 4 + ICMP_BASEHDR_LEN + eiph.ihl * 4 + 8) + return 0; + data = errmsg + iph.ihl * 4 + ICMP_BASEHDR_LEN + eiph.ihl * 4; + return icmph.type == errtype && memcmp(&to->s_addr, &eiph.daddr, sizeof(to->s_addr)) == 0 && + memcmp(data, packet, plen < 8 ?plen:8) == 0; +} + + + +unsigned short get_rand16(void) +{ + return random()&0xffff; +} + + +short p_sequence = 0; +unsigned short id; +struct icmphdr icmpd; +struct sockaddr_in to; + +/* + * IPv4/ICMPv4 ping. Called from ping (see below) + */ +int ping_send(struct in_addr addr) +{ + int len; + int isock; + struct icmp_filter f; + unsigned long sum; + unsigned short *ptr; + + isock = ping_isocket; + p_sequence = 1; + id = (unsigned short)get_rand16(); /* randomize a ping id */ + + /* Fancy ICMP filering -- only on Linux (as far is I know) */ + + /* In fact, there should be macros for treating icmp_filter, but I haven't found them in Linux 2.2.15. + * So, set it manually and unportable ;-) */ + /* This filter lets ECHO_REPLY (0), DEST_UNREACH(3) and TIME_EXCEEDED(11) pass. */ + /* !(0000 1000 0000 1001) = 0xff ff f7 f6 */ + f.data=0xfffff7f6; + if (setsockopt(isock, SOL_RAW, ICMP_FILTER, &f, sizeof(f)) == -1) { + if (icmp_errs < ICMP_MAX_ERRS) + tasklog('?', "$icmp ping: setsockopt() failed %d", isock); + return -1; + } + + icmpd.type = ICMP_ECHO; + icmpd.code = 0; + icmpd.checksum = 0; + icmpd.un.echo.id = htons((short)id); + icmpd.un.echo.sequence = htons(p_sequence); + + /* Checksumming - Algorithm taken from nmap. Thanks... */ + + ptr = (unsigned short *)&icmpd; + sum = 0; + + for (len = 0; len < 4; len++) { + sum += *ptr++; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + icmpd.checksum = ~sum; + + memset(&to, 0, sizeof(to)); + to.sin_family = AF_INET; + to.sin_port = 0; + to.sin_addr = addr; + SET_SOCKA_LEN4(to); + if (sendto(isock, &icmpd, ICMP_BASEHDR_LEN, 0, (struct sockaddr *)&to, sizeof(to)) == -1) { + if (icmp_errs < ICMP_MAX_ERRS) + tasklog('?', "$icmp ping: sendto()"); + return -2; + } + return 0; +} + + + +int ping_receive(struct in_addr addr) +{ + char buf[1024]; + int isock; + int len; + struct sockaddr_in ffrom; + struct icmphdr icmpp; + struct iphdr iph; + socklen_t sl; + struct pollfd pfd; + + isock = ping_isocket; + + pfd.fd = isock; + pfd.events = POLLIN; + /* + * 10 mSec is enough, this function is called at regular intervals. + */ + if (poll(&pfd, 1, 10) < 0) { + if (icmp_errs < ICMP_MAX_ERRS) + tasklog('?', "$poll/select failed"); + return -3; + } + + if (pfd.revents & POLLIN || pfd.revents & POLLERR || pfd.revents & POLLHUP || pfd.revents & POLLNVAL) { + sl = sizeof(ffrom); + if ((len = recvfrom(isock, &buf, sizeof(buf), 0,(struct sockaddr *)&ffrom, &sl)) != -1) { + if (len > sizeof(struct iphdr)) { + memcpy(&iph, buf, sizeof(iph)); + if (len - iph.ihl * 4 >= ICMP_BASEHDR_LEN) { + memcpy(&icmpp, ((unsigned long int *)buf)+iph.ihl, sizeof(icmpp)); + if (iph.saddr == addr.s_addr && + icmpp.type == ICMP_ECHOREPLY && + ntohs(icmpp.un.echo.id) == id && + ntohs(icmpp.un.echo.sequence) <= p_sequence) { + return 0; + } else { + /* No regular echo reply. Maybe an error? */ + if (icmp4_errcmp((char *)&icmpd, ICMP_BASEHDR_LEN, + &to.sin_addr, buf, len, ICMP_DEST_UNREACH) || + icmp4_errcmp((char *)&icmpd, ICMP_BASEHDR_LEN, + &to.sin_addr, buf, len, ICMP_TIME_EXCEEDED)) { + return -4; + } + } + } + } + } else { + return -5; /* error */ + } + } + return -6; /* no answer */ +} + + + +/* + * Check semafore's, system status flags etc. This is called + * each second to test for condition changes. + */ +void check_sema(void); +void check_sema(void) +{ + /* + * Check UPS status. + */ + if (IsSema((char *)"upsalarm")) { + if (!UPSalarm) + tasklog('!', "UPS: power failure"); + UPSalarm = TRUE; + } else { + if (UPSalarm) + tasklog('!', "UPS: the power is back"); + UPSalarm = FALSE; + } + if (IsSema((char *)"upsdown")) { + tasklog('!', "UPS: power failure, starting shutdown"); + /* + * Since the upsdown semafore is permanent, the system WILL go down + * there is no point for this program to stay. Signal all tasks and stop. + */ + die(SIGTERM); + } + + /* + * Check Zone Mail Hour + */ + get_zmh(); + + /* + * Newnews semafore can also be set in the semafore directory. + */ + if (IsSema((char *)"newnews")) { + RemoveSema((char *)"newnews"); + s_newnews = TRUE; + } +} + + + +void scheduler(void) +{ + struct passwd *pw; + int running = 0, rc, rlen; + int LOADhi = FALSE, oldmin = 70, olddo = 70; + char *cmd = NULL, doing[32], buf[2048]; + time_t now; + struct tm *tm; + FILE *fp; + float lavg1, lavg2, lavg3; + struct pollfd pfd; + struct in_addr paddr; + + InitFidonet(); + + /* + * Registrate this server for mbmon in slot 0. + */ + reginfo[0].pid = getpid(); + sprintf(reginfo[0].tty, "-"); + sprintf(reginfo[0].uname, "mbse"); + sprintf(reginfo[0].prg, "mbtask"); + sprintf(reginfo[0].city, "localhost"); + sprintf(reginfo[0].doing, "Start"); + reginfo[0].started = time(NULL); + + Processing = TRUE; + TouchSema((char *)"mbtask.last"); + pw = getpwuid(getuid()); + + /* + * Setup UNIX Datagram socket + */ + if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { + tasklog('?', "$Can't create socket"); + die(1); + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sun_family = AF_UNIX; + strcpy(servaddr.sun_path, spath); + + if (bind(sock, &servaddr, sizeof(servaddr)) < 0) { + close(sock); + sock = -1; + tasklog('?', "$Can't bind socket %s", spath); + die(1); + } + + pingresult[1] = TRUE; + pingresult[2] = TRUE; + initnl(); + sem_set((char *)"scanout", TRUE); + + do { + /* + * Poll UNIX Datagram socket until the defined timeout. + */ + pfd.fd = sock; + pfd.events = POLLIN | POLLPRI; + pfd.revents = 0; + rc = poll(&pfd, 1, 1000); + if (rc == -1) { + /* + * Poll can be interrupted by a finished child so that's not a real error. + */ + if (errno != EINTR) { + tasklog('?', "$poll() rc=%d sock=%d, events=%04x", rc, sock, pfd.revents); + } + } else if (rc) { + if (pfd.revents & POLLIN) { + memset(&buf, 0, sizeof(buf)); + fromlen = sizeof(from); + rlen = recvfrom(sock, buf, sizeof(buf) -1, 0, &from, &fromlen); + do_cmd(buf); + } else { + tasklog('-', "Return poll rc=%d, events=%04x", rc, pfd.revents); + } + } + + /* + * Check all registered connections and semafore's + */ + reg_check(); + check_sema(); + + /* + * Check the systems load average. + */ + if ((fp = fopen((char *)"/proc/loadavg", "r"))) { + if (fscanf(fp, "%f %f %f", &lavg1, &lavg2, &lavg3) == 3) { + Load = lavg1; + if (lavg1 >= TCFG.maxload) { + if (!LOADhi) { + tasklog('!', "System load too high: %2.2f (%2.2f)", lavg1, TCFG.maxload); + LOADhi = TRUE; + } + } else { + if (LOADhi) { + tasklog('!', "System load normal: %2.2f (%2.2f)", lavg1, TCFG.maxload); + LOADhi = FALSE; + } + } + } + fclose(fp); + } + + /* + * Report to the system monitor. + */ + memset(&doing, 0, sizeof(doing)); + if ((running = checktasks(0))) + sprintf(doing, "Run %d tasks", running); + else if (UPSalarm) + sprintf(doing, "UPS alarm"); + else if (!s_bbsopen) + sprintf(doing, "BBS is closed"); + else if (Processing) + sprintf(doing, "Waiting (%d)", oldmin); + else + sprintf(doing, "Overload %2.2f", lavg1); + + sprintf(reginfo[0].doing, "%s", doing); + reginfo[0].lastcon = time(NULL); + + /* + * Touch the mbtask.last semafore to prove this daemon + * is actually running. + * Reload configuration data if the file is changed. + */ + now = time(NULL); + tm = localtime(&now); + if (tm->tm_min != olddo) { + olddo = tm->tm_min; + TouchSema((char *)"mbtask.last"); + if (file_time(tcfgfn) != tcfg_time) { + tasklog('+', "Task configuration changed, reloading"); + load_taskcfg(); + } + if (file_time(cfgfn) != cfg_time) { + tasklog('+', "Main configuration changed, reloading"); + load_maincfg(); + } + } + + if (s_bbsopen && !UPSalarm && !LOADhi) { + + if (!Processing) { + tasklog('+', "Resuming normal operations"); + Processing = TRUE; + } + + /* + * Here we run all normal operations. + */ + if (s_mailout && (!runtasktype(MBFIDO))) { + launch(TCFG.cmd_mailout, NULL, (char *)"mailout", MBFIDO); + running = checktasks(0); + s_mailout = FALSE; + } + + if (s_mailin && (!runtasktype(MBFIDO))) { + launch(TCFG.cmd_mailin, NULL, (char *)"mailin", MBFIDO); + running = checktasks(0); + s_mailin = FALSE; + } + + if (s_newnews && (!runtasktype(MBFIDO))) { + launch(TCFG.cmd_newnews, NULL, (char *)"newnews", MBFIDO); + running = checktasks(0); + s_newnews = FALSE; + } + + /* + * Only run the nodelist compiler if nothing else + * is running. There's no hurry to compile the + * new lists. If more then one compiler is defined, + * start them in parallel. + */ + if (s_index && (!running)) { + if (strlen(TCFG.cmd_mbindex1)) + launch(TCFG.cmd_mbindex1, NULL, (char *)"compiler 1", MBINDEX); + if (strlen(TCFG.cmd_mbindex2)) + launch(TCFG.cmd_mbindex2, NULL, (char *)"compiler 2", MBINDEX); + if (strlen(TCFG.cmd_mbindex3)) + launch(TCFG.cmd_mbindex3, NULL, (char *)"compiler 3", MBINDEX); + running = checktasks(0); + s_index = FALSE; + } + + /* + * Linking messages is also only done when there is + * nothing else to do. + */ + if (s_msglink && (!running)) { + launch(TCFG.cmd_msglink, NULL, (char *)"msglink", MBFIDO); + running = checktasks(0); + s_msglink = FALSE; + } + + /* + * Creating filerequest indexes. + */ + if (s_reqindex && (!running)) { + launch(TCFG.cmd_reqindex, NULL, (char *)"reqindex", MBFILE); + running = checktasks(0); + s_reqindex = FALSE; + } + + if ((tm->tm_sec / SLOWRUN) != oldmin) { + + /* + * These tasks run once per 20 seconds. + */ + oldmin = tm->tm_sec / SLOWRUN; + + /* + * If the previous pingstat is still P_SENT, the we now consider it a timeout. + */ + if (pingstate == P_SENT) { + pingresult[pingnr] = FALSE; + icmp_errs++; + if (icmp_errs < ICMP_MAX_ERRS) + tasklog('p', "ping %s seq=%d timeout", pingaddress, p_sequence); + } + + /* + * Check internet connection with ICMP ping + */ + rc = 0; + if (pingnr == 1) { + pingnr = 2; + if (strlen(TCFG.isp_ping2)) { + sprintf(pingaddress, "%s", TCFG.isp_ping2); + } else { + pingstate = P_NONE; + } + } else { + pingnr = 1; + if (strlen(TCFG.isp_ping1)) { + sprintf(pingaddress, "%s", TCFG.isp_ping1); + } else { + pingstate = P_NONE; + } + } + + if (inet_aton(pingaddress, &paddr)) { + rc = ping_send(paddr); + if (internet) + tasklog('p', "ping send %s id=%d rc=%d", pingaddress, id, rc); + if (rc) { + if (icmp_errs++ < ICMP_MAX_ERRS) + tasklog('?', "ping send %s rc=%d", pingaddress, rc); + pingstate = P_FAIL; + pingresult[pingnr] = FALSE; + } else { + pingstate = P_SENT; + } + } else { + if (icmp_errs++ < ICMP_MAX_ERRS) + tasklog('?', "Ping address %d is invalid \"%s\"", pingnr, pingaddress); + pingstate = P_NONE; + } + + if (pingresult[1] == FALSE && pingresult[2] == FALSE) { + icmp_errs++; + if (internet) { + tasklog('!', "Internet connection is down"); + internet = FALSE; + } + } else { + if (!internet) { + tasklog('!', "Internet connection is up"); + internet = TRUE; + } + icmp_errs = 0; + } + + /* + * Run the mailer if something to do. For now we run just + * one task and lock it with CALL_POTS. + * Later tasks for different calltypes should run parallel. + */ + if (s_scanout && !runtasktype(CALL_POTS)) { + cmd = xstrcpy(pw->pw_dir); + cmd = xstrcat(cmd, (char *)"/bin/mbcico"); + launch(cmd, (char *)"-r1", (char *)"mbcico", CALL_POTS); + running = checktasks(0); + free(cmd); + cmd = NULL; + } + } + + switch (pingstate) { + case P_NONE: pingresult[pingnr] = TRUE; + break; + case P_SENT: rc = ping_receive(paddr); + if (!rc) { + pingstate = P_OK; + pingresult[pingnr] = TRUE; + if (internet) + tasklog('p', "ping recv %s id=%d rc=%d", pingaddress, id, rc); + } else { + if (rc != -6) + tasklog('p', "ping recv %s id=%d rc=%d", pingaddress, id, rc); + } + break; + } + + } else { + if (Processing) { + tasklog('+', "Suspending operations"); + Processing = FALSE; + } + } + } while (TRUE); +} + + + +int main(int argc, char **argv) +{ + struct passwd *pw; + int i; + pid_t frk; + FILE *fp; + +#ifdef MEMWATCH + mwInit(); +#endif + /* + * Print copyright notices and setup logging. + */ + printf("MBTASK: MBSE BBS v%s Task Manager Daemon\n", VERSION); + printf(" %s\n\n", Copyright); + + /* + * Catch all the signals we can, and ignore the rest. Note that SIGKILL can't be ignored + * but that's live. This daemon should only be stopped by SIGTERM. + */ + for(i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + /* + * Create the ping socket while we are still root. + */ + if ((ping_isocket = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) { + perror(""); + printf("socket init failed, is mbtask not installed setuid root?\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + /* + * mbtask is setuid root, drop privileges to user mbse. + * This will stay forever like this, no need to become + * root again. The child can't even become root anymore. + */ + pw = getpwnam((char *)"mbse"); + if (setuid(pw->pw_uid)) { + perror(""); + printf("can't setuid to mbse\n"); + close(ping_isocket); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + if (setgid(pw->pw_gid)) { + perror(""); + printf("can't setgid to bbs\n"); + close(ping_isocket); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + umask(007); + if (locktask(pw->pw_dir)) { + close(ping_isocket); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + sprintf(cfgfn, "%s/etc/config.data", getenv("MBSE_ROOT")); + load_maincfg(); + + tasklog(' ', " "); + tasklog(' ', "MBTASK v%s", VERSION); + sprintf(tcfgfn, "%s/etc/task.data", getenv("MBSE_ROOT")); + load_taskcfg(); + status_init(); + + memset(&task, 0, sizeof(task)); + memset(®info, 0, sizeof(reginfo)); + sprintf(spath, "%s/tmp/mbtask", getenv("MBSE_ROOT")); + + /* + * Server initialization is complete. Now we can fork the + * daemon and return to the user. We need to do a setpgrp + * so that the daemon will no longer be assosiated with the + * users control terminal. This is done before the fork, so + * that the child will not be a process group leader. Otherwise, + * if the child were to open a terminal, it would become + * associated with that terminal as its control terminal. + */ + if ((pgrp = setpgrp()) == -1) { + tasklog('?', "$setpgrp failed"); + die(0); + } + + frk = fork(); + switch (frk) { + case -1: + tasklog('?', "$Unable to fork daemon"); + die(0); + case 0: + /* + * Starting the deamon child process here. + */ + fclose(stdin); + fclose(stdout); + fclose(stderr); + scheduler(); + /* Not reached */ + default: + /* + * Here we detach this process and let the child + * run the deamon process. Put the child's pid + * in the lockfile before leaving. + */ + if ((fp = fopen(lockfile, "w"))) { + fprintf(fp, "%10u\n", frk); + fclose(fp); + } + tasklog('+', "Starting daemon with pid %d", frk); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(0); + } + + /* + * Not reached + */ + return 0; +} + + + diff --git a/mbtask/mbtask.h b/mbtask/mbtask.h new file mode 100644 index 00000000..6584d67b --- /dev/null +++ b/mbtask/mbtask.h @@ -0,0 +1,52 @@ +#ifndef _MBTASK_H +#define _MBTASK_H + + +typedef enum {CALL_POTS, CALL_ISDN, CALL_IP, MBFIDO, MBINDEX, MBFILE} TASKTYPE; + + +/* + * Running tasks information + */ +typedef struct _onetask { + char name[16]; /* Name of the task */ + char cmd[PATH_MAX]; /* Command to binary */ + char opts[128]; /* Commandline opts */ + int tasktype; /* Type of task */ + pid_t pid; /* Pid of task */ + int running; /* Running or not */ + int status; /* Waitpid status */ + int rc; /* Exit code */ +} onetask; + + + +/* + * Logging flagbits, ' ' ? ! + - + */ +#define DLOG_ALLWAYS 0x00000001 +#define DLOG_ERROR 0x00000002 +#define DLOG_ATTENT 0x00000004 +#define DLOG_NORMAL 0x00000008 +#define DLOG_VERBOSE 0x00000010 + + + +time_t file_time(char *); +void load_maincfg(void); +void load_taskcfg(void); +pid_t launch(char *, char *, char *, int); +int runtasktype(int); +int checktasks(int); +void die(int); +static int icmp4_errcmp(char *, int, struct in_addr *, char *, int, int); +unsigned short get_rand16(void); +int ping_send(struct in_addr); +int ping_receive(struct in_addr); +void scheduler(void); +int locktask(char *); +void ulocktask(void); + + +#endif + diff --git a/mbtask/nodelist.c b/mbtask/nodelist.c new file mode 100644 index 00000000..1de7dcb6 --- /dev/null +++ b/mbtask/nodelist.c @@ -0,0 +1,572 @@ +/***************************************************************************** + * + * File ..................: nodelist.c + * Purpose ...............: Read nodelists information + * Last modification date : 06-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskutil.h" +#include "nodelist.h" + + +#define NULLDOMAIN "nulldomain" + + +struct _pkey pkey[] = { + {(char *)"Down", NL_NODE, NL_DOWN}, + {(char *)"Hold", NL_NODE, NL_HOLD}, + {(char *)"Region", NL_REGION, NL_REGION}, + {(char *)"Host", NL_HOST, NL_HOST}, + {(char *)"Hub", NL_HUB, NL_HUB}, + {(char *)"Point", NL_POINT, NL_POINT}, + {(char *)"Pvt", NL_NODE, NL_NODE}, + {NULL, 0, 0} +}; + + + +struct _okey okey[] = { + {(char *)"CM", OL_CM}, + {(char *)"MO", OL_MO}, + {(char *)"LO", OL_LO}, + {(char *)"MN", OL_MN}, + {NULL, 0} +}; + +struct _fkey fkey[] = { + {(char *)"V22", NL_V22}, + {(char *)"V29", NL_V29}, + {(char *)"V32", NL_V32}, + {(char *)"V32B",NL_V32B | NL_V32}, + {(char *)"V34", NL_V34}, + {(char *)"V42", NL_V42 | NL_MNP}, + {(char *)"V42B",NL_V42B | NL_V42 | NL_MNP}, + {(char *)"MNP", NL_MNP}, + {(char *)"H96", NL_H96}, + {(char *)"HST", NL_HST | NL_MNP}, + {(char *)"H14", NL_H14 | NL_HST | NL_MNP}, + {(char *)"H16", NL_H16 | NL_H14 | NL_HST | NL_MNP | NL_V42 | NL_V42B}, + {(char *)"MAX", NL_MAX}, + {(char *)"PEP", NL_PEP}, + {(char *)"CSP", NL_CSP}, + {(char *)"V32T",NL_V32T | NL_V32B | NL_V32}, + {(char *)"VFC", NL_VFC}, + {(char *)"ZYX", NL_ZYX | NL_V32B | NL_V32 | NL_V42B | NL_V42 | NL_MNP}, + {(char *)"X2C", NL_X2C | NL_X2S | NL_V34}, + {(char *)"X2S", NL_X2S | NL_V34}, + {(char *)"V90C",NL_V90C | NL_V90S | NL_V34}, + {(char *)"V90S",NL_V90S | NL_V34}, + {(char *)"Z19", NL_Z19 | NL_V32B | NL_V32 | NL_V42B | NL_V42 | NL_MNP | NL_ZYX}, + {NULL, 0} +}; + +struct _xkey xkey [] = { + {(char *)"XA", RQ_XA}, + {(char *)"XB", RQ_XB}, + {(char *)"XC", RQ_XC}, + {(char *)"XP", RQ_XP}, + {(char *)"XR", RQ_XR}, + {(char *)"XW", RQ_XW}, + {(char *)"XX", RQ_XX}, + {NULL, 0} +}; + +struct _dkey dkey [] = { + {(char *)"V110L", ND_V110L}, + {(char *)"V110H", ND_V110H}, + {(char *)"V120L", ND_V120L}, + {(char *)"V120H", ND_V120H}, + {(char *)"X75", ND_X75}, + {NULL, 0} +}; + +struct _ikey ikey [] = { + {(char *)"IBN", IP_IBN}, + {(char *)"IFC", IP_IFC}, + {(char *)"ITN", IP_ITN}, + {(char *)"IVM", IP_IVM}, + {(char *)"IP", IP_IP}, + {(char *)"IFT", IP_IFT}, + {NULL, 0} +}; + +extern struct sysconfig CFG; + + +int initnl(void) +{ + int rc = 0; + FILE *dbf, *fp; + char *filexnm, *path; + struct _nlfil fdx; + + filexnm = xstrcpy(CFG.nodelists); + filexnm = xstrcat(filexnm,(char *)"/node.files"); + + if ((dbf = fopen(filexnm, "r")) == NULL) { + tasklog('?', "$Can't open %s", filexnm); + rc = 101; + } else { + path = calloc(PATH_MAX, sizeof(char)); + + while (fread(&fdx, sizeof(fdx), 1, dbf) == 1) { + sprintf(path, "%s/%s", CFG.nodelists, fdx.filename); + if ((fp = fopen(path, "r")) == NULL) { + tasklog('?', "$Can't open %s", path); + rc = 101; + } else { + fclose(fp); + } + } + + fclose(dbf); + free(path); + } + + free(filexnm); + return rc; +} + + + +int comp_node(struct _nlidx, struct _ixentry); +int comp_node(struct _nlidx fap1, struct _ixentry fap2) +{ + if (fap1.zone != fap2.zone) + return (fap1.zone - fap2.zone); + else if (fap1.net != fap2.net) + return (fap1.net - fap2.net); + else if (fap1.node != fap2.node) + return (fap1.node - fap2.node); + else + return (fap1.point - fap2.point); +} + + + +node *getnlent(faddr *addr) +{ + FILE *fp; + static node nodebuf; + static char buf[256], *p, *q; + struct _ixentry xaddr; + int i, j, Found = FALSE; + int ixflag, stdflag; + char *mydomain, *path; + struct _nlfil fdx; + struct _nlidx ndx; + long lowest, highest, current; + + tasklog('s', "getnlent: %s", ascfnode(addr,0xff)); + + mydomain = xstrcpy(CFG.aka[0].domain); + if (mydomain == NULL) + mydomain = (char *)NULLDOMAIN; + + nodebuf.addr.domain = NULL; + nodebuf.addr.zone = 0; + nodebuf.addr.net = 0; + nodebuf.addr.node = 0; + nodebuf.addr.point = 0; + nodebuf.addr.name = NULL; + nodebuf.upnet = 0; + nodebuf.upnode = 0; + nodebuf.region = 0; + nodebuf.type = 0; + nodebuf.pflag = 0; + nodebuf.name = NULL; + nodebuf.location = NULL; + nodebuf.sysop = NULL; + nodebuf.phone = NULL; + nodebuf.speed = 0; + nodebuf.mflags = 0L; + nodebuf.oflags = 0L; + nodebuf.xflags = 0L; + nodebuf.iflags = 0L; + nodebuf.dflags = 0L; + nodebuf.uflags[0] = NULL; + + if (addr == NULL) + goto retdummy; + + if (addr->zone == 0) + addr->zone = CFG.aka[0].zone; + xaddr.zone = addr->zone; + nodebuf.addr.zone = addr->zone; + xaddr.net = addr->net; + nodebuf.addr.net = addr->net; + xaddr.node = addr->node; + nodebuf.addr.node = addr->node; + xaddr.point = addr->point; + nodebuf.addr.point = addr->point; + + if (initnl()) + goto retdummy; + + /* + * First, lookup node in index. NOTE -- NOT 5D YET + */ + path = calloc(128, sizeof(char)); + sprintf(path, "%s/%s", CFG.nodelists, "node.index"); + if ((fp = fopen(path, "r")) == NULL) { + tasklog('?', "$Can't open %s", path); + free(path); + goto retdummy; + } + + fseek(fp, 0, SEEK_END); + highest = ftell(fp) / sizeof(ndx); + lowest = 0; + + while (TRUE) { + current = ((highest - lowest) / 2) + lowest; + fseek(fp, current * sizeof(ndx), SEEK_SET); + if (fread(&ndx, sizeof(ndx), 1, fp) != 1) + break; + + if (comp_node(ndx, xaddr) == 0) { + Found = TRUE; + break; + } + if (comp_node(ndx, xaddr) < 0) + lowest = current; + else + highest = current; + if ((highest - lowest) <= 1) + break; + } + + fclose(fp); + + if (!Found) { + free(path); + goto retdummy; + } + + sprintf(path, "%s/%s", CFG.nodelists, "node.files"); + if ((fp = fopen(path, "r")) == NULL) { + tasklog('?', "$Can't open %s", path); + free(path); + goto retdummy; + } + + /* + * Get filename from node.files + */ + for (i = 0; i < (ndx.fileno +1); i++) + fread(&fdx, sizeof(fdx), 1, fp); + fclose(fp); + + /* CHECK DOMAIN HERE */ + + /* + * Open and read in real nodelist + */ + sprintf(path, "%s/%s", CFG.nodelists, fdx.filename); + if ((fp = fopen(path, "r")) == NULL) { + tasklog('?', "$Can't open %s", path); + free(path); + goto retdummy; + } + free(path); + + if (fseek(fp, ndx.offset, SEEK_SET) != 0) { + tasklog('?', "$Seek failed for nodelist entry"); + fclose(fp); + goto retdummy; + } + + if (fgets(buf, sizeof(buf)-1, fp) == NULL) { + tasklog('?', "$fgets failed for nodelist entry"); + fclose(fp); + goto retdummy; + } + fclose(fp); + + nodebuf.type = ndx.type; + nodebuf.pflag = ndx.pflag; + + if (*(p = buf + strlen(buf) -1) == '\n') + *p = '\0'; + if (*(p = buf + strlen(buf) -1) == '\r') + *p = '\0'; + for (p = buf; *p; p++) + if (*p == '_') + *p = ' '; + + p = buf; + + if ((q = strchr(p,','))) + *q++ = '\0'; + + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.name = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.location = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.sysop = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + if (strcasecmp(p, "-Unpublished-") == 0) + nodebuf.phone = NULL; + else + nodebuf.phone = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.speed = atoi(p); + + /* + * Process the nodelist flags. + */ + ixflag = 0; + stdflag = TRUE; + for (p = q; p; p = q) { + if ((q = strchr(p, ','))) + *q++ = '\0'; + if ((strncasecmp(p, "U", 1) == 0) && (strlen(p) == 1)) { + stdflag = FALSE; + } else { + /* + * Experimental: process authorized flags and + * User flags both as authorized. + */ + for (j = 0; fkey[j].key; j++) + if (strcasecmp(p, fkey[j].key) == 0) + nodebuf.mflags |= fkey[j].flag; + for (j = 0; okey[j].key; j++) + if (strcasecmp(p, okey[j].key) == 0) + nodebuf.oflags |= okey[j].flag; + for (j = 0; dkey[j].key; j++) + if (strcasecmp(p, dkey[j].key) == 0) + nodebuf.dflags |= dkey[j].flag; + for (j = 0; ikey[j].key; j++) + if (strncasecmp(p, ikey[j].key, strlen(ikey[j].key)) == 0) + nodebuf.iflags |= ikey[j].flag; + for (j = 0; xkey[j].key; j++) + if (strcasecmp(p, xkey[j].key) == 0) + nodebuf.xflags |= xkey[j].flag; + if (!stdflag) { + if (ixflag < MAXUFLAGS) { + nodebuf.uflags[ixflag++] = p; + if (ixflag < MAXUFLAGS) + nodebuf.uflags[ixflag] = NULL; + } + } + } + } + + nodebuf.addr.name = nodebuf.sysop; + nodebuf.addr.domain = xstrcpy(fdx.domain); + nodebuf.upnet = ndx.upnet; + nodebuf.upnode = ndx.upnode; + nodebuf.region = ndx.region; + if (addr->domain == NULL) + addr->domain = xstrcpy(nodebuf.addr.domain); + + moflags(nodebuf.mflags); + diflags(nodebuf.dflags); + ipflags(nodebuf.iflags); + olflags(nodebuf.oflags); + free(mydomain); + + return &nodebuf; + +badsyntax: + tasklog('?', "nodelist %d offset +%lu: bad syntax in line \"%s\"", + ndx.fileno, (unsigned long)ndx.offset, buf); + /* fallthrough */ + +retdummy: + memset(&nodebuf, 0, sizeof(nodebuf)); + nodebuf.pflag = NL_DUMMY; + nodebuf.name = (char *)"Unknown"; + nodebuf.location = (char *)"Nowhere"; + nodebuf.sysop = (char *)"Sysop"; + nodebuf.phone = NULL; + nodebuf.speed = 2400; + free(mydomain); + + return &nodebuf; +} + + + +void olflags(unsigned long flags) +{ + char *t; + + t = xstrcpy((char *)"Mailer flags :"); + if (flags & OL_CM) + t = xstrcat(t, (char *)" CM"); + if (flags & OL_MO) + t = xstrcat(t, (char *)" MO"); + if (flags & OL_LO) + t = xstrcat(t, (char *)" LO"); + if (flags & OL_MN) + t = xstrcat(t, (char *)" MN"); + tasklog('s', "%s", t); + free(t); +} + + + +void moflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + t = xstrcpy((char *)"Modem flags :"); + if (flags & NL_V22) + t = xstrcat(t, (char *)" V22"); + if (flags & NL_V29) + t = xstrcat(t, (char *)" V29"); + if (flags & NL_V32) + t = xstrcat(t, (char *)" V32"); + if (flags & NL_V32B) + t = xstrcat(t, (char *)" V32B"); + if (flags & NL_V34) + t = xstrcat(t, (char *)" V34"); + if (flags & NL_V42) + t = xstrcat(t, (char *)" V42"); + if (flags & NL_V42B) + t = xstrcat(t, (char *)" V42B"); + if (flags & NL_MNP) + t = xstrcat(t, (char *)" MNP"); + if (flags & NL_H96) + t = xstrcat(t, (char *)" H96"); + if (flags & NL_HST) + t = xstrcat(t, (char *)" HST"); + if (flags & NL_H14) + t = xstrcat(t, (char *)" H14"); + if (flags & NL_H16) + t = xstrcat(t, (char *)" H16"); + if (flags & NL_MAX) + t = xstrcat(t, (char *)" MAX"); + if (flags & NL_PEP) + t = xstrcat(t, (char *)" PEP"); + if (flags & NL_CSP) + t = xstrcat(t, (char *)" CSP"); + if (flags & NL_V32T) + t = xstrcat(t, (char *)" V32T"); + if (flags & NL_VFC) + t = xstrcat(t, (char *)" VFC"); + if (flags & NL_ZYX) + t = xstrcat(t, (char *)" ZYX"); + if (flags & NL_X2C) + t = xstrcat(t, (char *)" X2C"); + if (flags & NL_X2S) + t = xstrcat(t, (char *)" X2S"); + if (flags & NL_V90C) + t = xstrcat(t, (char *)" V90C"); + if (flags & NL_V90S) + t = xstrcat(t, (char *)" V90S"); + tasklog('s', "%s", t); + free(t); +} + + + +void diflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + + t = xstrcpy((char *)"ISDN flags :"); + if (flags & ND_V110L) + t = xstrcat(t, (char *)" V110L"); + if (flags & ND_V110H) + t = xstrcat(t, (char *)" V110H"); + if (flags & ND_V120L) + t = xstrcat(t, (char *)" V120L"); + if (flags & ND_V120H) + t = xstrcat(t, (char *)" V120H"); + if (flags & ND_X75) + t = xstrcat(t, (char *)" X75"); + tasklog('s', "%s", t); + free(t); +} + + + +void ipflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + + t = xstrcpy((char *)"TCP/IP flags :"); + if (flags & IP_IBN) + t = xstrcat(t, (char *)" IBN"); + if (flags & IP_IFC) + t = xstrcat(t, (char *)" IFC"); + if (flags & IP_ITN) + t = xstrcat(t, (char *)" ITN"); + if (flags & IP_IVM) + t = xstrcat(t, (char *)" IVM"); + if (flags & IP_IP) + t = xstrcat(t, (char *)" IP"); + tasklog('s', "%s", t); + free(t); +} + + + diff --git a/mbtask/nodelist.h b/mbtask/nodelist.h new file mode 100644 index 00000000..6668c904 --- /dev/null +++ b/mbtask/nodelist.h @@ -0,0 +1,189 @@ +#ifndef _NODELIST_H +#define _NODELIST_H + +/* +#include "../config.h" + +#pragma pack(1) +*/ + +#define MAXNAME 35 +#define MAXUFLAGS 16 + + +/* + * Analogue Modem flag values, order is important, first the + * compresion capabilities, then the linespeeds. This is late + * tested by portsel to find the fastest common connection + * speed for a given line if you have multiple dialout modems. + */ +#define NL_MNP 0x00000001L +#define NL_V42 0x00000002L +#define NL_V42B 0x00000004L +#define NL_V22 0x00000008L +#define NL_V29 0x00000010L +#define NL_V32 0x00000020L +#define NL_H96 0x00000040L +#define NL_HST 0x00000080L +#define NL_MAX 0x00000100L +#define NL_PEP 0x00000200L +#define NL_CSP 0x00000400L +#define NL_V32B 0x00000800L +#define NL_H14 0x00001000L +#define NL_V32T 0x00002000L +#define NL_H16 0x00004000L +#define NL_ZYX 0x00008000L +#define NL_Z19 0x00010000L +#define NL_VFC 0x00020000L +#define NL_V34 0x00040000L +#define NL_X2C 0x00080000L +#define NL_X2S 0x00100000L +#define NL_V90C 0x00200000L +#define NL_V90S 0x00400000L + + + +/* + * ISDN Flags + */ +#define ND_V110L 0x00000001L +#define ND_V110H 0x00000002L +#define ND_V120L 0x00000004L +#define ND_V120H 0x00000008L +#define ND_X75 0x00000010L + + + +/* + * TCP/IP flags + */ +#define IP_IBN 0x00000001L +#define IP_IFC 0x00000002L +#define IP_ITN 0x00000004L +#define IP_IVM 0x00000008L +#define IP_IP 0x00000010L +#define IP_IFT 0x00000020L + + + +/* + * Online special flags + */ +#define OL_CM 0x00000001L +#define OL_MO 0x00000002L +#define OL_LO 0x00000004L +#define OL_MN 0x00000008L + + + +/* + * Request flags + */ +#define RQ_RQMODE 0x0000000fL +#define RQ_RQ_BR 0x00000001L +#define RQ_RQ_BU 0x00000002L +#define RQ_RQ_WR 0x00000004L +#define RQ_RQ_WU 0x00000008L +#define RQ_XA (RQ_RQ_BR | RQ_RQ_BU | RQ_RQ_WR | RQ_RQ_WU) +#define RQ_XB (RQ_RQ_BR | RQ_RQ_BU | RQ_RQ_WR ) +#define RQ_XC (RQ_RQ_BR | RQ_RQ_WR | RQ_RQ_WU) +#define RQ_XP (RQ_RQ_BR | RQ_RQ_BU ) +#define RQ_XR (RQ_RQ_BR | RQ_RQ_WR ) +#define RQ_XW ( RQ_RQ_WR ) +#define RQ_XX ( RQ_RQ_WR | RQ_RQ_WU) + + + +/* + * Nodelist entry + */ +typedef struct _node { + faddr addr; /* Node address */ + unsigned short upnet; /* Uplink netnumber */ + unsigned short upnode; /* Uplink nodenumber */ + unsigned short region; /* Region belongin to */ + unsigned char type; + unsigned char pflag; + char *name; /* System name */ + char *location; /* System location */ + char *sysop; /* Sysop name */ + char *phone; /* Phone number */ + unsigned speed; /* Baudrate */ + unsigned long mflags; /* Modem flags */ + unsigned long dflags; /* ISDN flags */ + unsigned long iflags; /* TCP-IP flags */ + unsigned long oflags; /* Online flags */ + unsigned long xflags; /* Request flags */ + char *uflags[MAXUFLAGS]; /* User flags */ +} node; + + + +extern struct _fkey { + char *key; + unsigned long flag; +} fkey[]; + + + +extern struct _dkey { + char *key; + unsigned long flag; +} dkey[]; + + + +extern struct _ikey { + char *key; + unsigned long flag; +} ikey[]; + + + +extern struct _okey { + char *key; + unsigned long flag; +} okey[]; + + + +extern struct _xkey { + char *key; + unsigned long flag; +} xkey[]; + + + +extern struct _nodelist { + char *domain; + FILE *fp; +} *nodevector; + + + +struct _ixentry { + unsigned short zone; + unsigned short net; + unsigned short node; + unsigned short point; +}; + + + +extern struct _pkey { + char *key; + unsigned char type; + unsigned char pflag; +} pkey[]; + + +int initnl(void); +node *getnlent(faddr *); +void olflags(unsigned long); +void moflags(unsigned long); +void diflags(unsigned long); +void ipflags(unsigned long); + + +#endif + diff --git a/mbtask/outstat.c b/mbtask/outstat.c new file mode 100644 index 00000000..efc8c583 --- /dev/null +++ b/mbtask/outstat.c @@ -0,0 +1,249 @@ +/***************************************************************************** + * + * File ..................: mbtask/outstat.c + * Purpose ...............: Scan mail outbound status + * Last modification date : 08-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskutil.h" +#include "scanout.h" +#include "nodelist.h" +#include "callstat.h" +#include "outstat.h" + + +extern int do_quiet; +extern struct sysconfig CFG; + + + +static struct _alist +{ + struct _alist *next; /* Next entry */ + faddr addr; /* Node address */ + int flavors; /* ORed flavors of mail/files */ + time_t time; /* Date/time of mail/files */ + off_t size; /* Total size of mail/files */ + callstat cst; /* Last call status */ + unsigned long olflags; /* Nodelist online flags */ + unsigned long moflags; /* Nodelist modem flags */ + unsigned long diflags; /* Nodelist ISDN flags */ + unsigned long ipflags; /* Nodelist TCP/IP flags */ +} *alist = NULL; + + +#define F_NORMAL 1 +#define F_CRASH 2 +#define F_IMM 4 +#define F_HOLD 8 +#define F_FREQ 16 +#define F_POLL 32 + + + +int outstat() +{ + int rc, first = TRUE; + struct _alist *tmp, *old; + char flstr[6]; + char temp[81]; + + tasklog('+', "Scanning outbound"); + /* + * Clear current table + */ + for (tmp = alist; tmp; tmp = old) { + old = tmp->next; + free(tmp->addr.domain); + free(tmp); + } + alist = NULL; + + if ((rc = scanout(each))) { + tasklog('?', "Error scanning outbound, aborting"); + return rc; + } + + for (tmp = alist; tmp; tmp = tmp->next) { + if (first) { + tasklog('+', "Flavor Size Online Modem ISDN TCP/IP Calls Status Address"); + first = FALSE; + } + strcpy(flstr,"......"); + if ((tmp->flavors) & F_IMM ) flstr[0]='I'; + if ((tmp->flavors) & F_CRASH ) flstr[1]='C'; + if ((tmp->flavors) & F_NORMAL) flstr[2]='N'; + if ((tmp->flavors) & F_HOLD ) flstr[3]='H'; + if ((tmp->flavors) & F_FREQ ) flstr[4]='R'; + if ((tmp->flavors) & F_POLL ) flstr[5]='P'; + + sprintf(temp, "%s %8lu %08x %08x %08x %08x %5d %6d %s", flstr, (long)tmp->size, + (unsigned int)tmp->olflags, (unsigned int)tmp->moflags, + (unsigned int)tmp->diflags, (unsigned int)tmp->ipflags, + tmp->cst.tryno, tmp->cst.trystat, ascfnode(&(tmp->addr), 0x1f)); + tasklog('+', "%s", temp); + } + + return 0; +} + + + +int each(faddr *addr, char flavor, int isflo, char *fname) +{ + struct _alist **tmp; + struct stat st; + FILE *fp; + char buf[256], *p; + node *nlent; + callstat *cst; + + if ((isflo != OUT_PKT) && (isflo != OUT_FLO) && (isflo != OUT_REQ) && (isflo != OUT_POL)) + return 0; + + for (tmp = &alist; *tmp; tmp = &((*tmp)->next)) + if (((*tmp)->addr.zone == addr->zone) && ((*tmp)->addr.net == addr->net) && + ((*tmp)->addr.node == addr->node) && ((*tmp)->addr.point == addr->point) && + (((*tmp)->addr.domain == NULL) || (addr->domain == NULL) || + (strcasecmp((*tmp)->addr.domain,addr->domain) == 0))) + break; + if (*tmp == NULL) { + nlent = getnlent(addr); + *tmp = (struct _alist *)malloc(sizeof(struct _alist)); + (*tmp)->next = NULL; + (*tmp)->addr.name = NULL; + (*tmp)->addr.zone = addr->zone; + (*tmp)->addr.net = addr->net; + (*tmp)->addr.node = addr->node; + (*tmp)->addr.point = addr->point; + (*tmp)->addr.domain = xstrcpy(addr->domain); + if (nlent->addr.domain) + free(nlent->addr.domain); + (*tmp)->flavors = 0; + if (nlent->pflag != NL_DUMMY) { + (*tmp)->olflags = nlent->oflags; + (*tmp)->moflags = nlent->mflags; + (*tmp)->diflags = nlent->dflags; + (*tmp)->ipflags = nlent->iflags; + } else { + (*tmp)->olflags = 0L; + (*tmp)->moflags = 0L; + (*tmp)->diflags = 0L; + (*tmp)->ipflags = 0L; + } + time(&((*tmp)->time)); + (*tmp)->size = 0L; + } + + cst = getstatus(addr); + (*tmp)->cst.trytime = cst->trytime; + (*tmp)->cst.tryno = cst->tryno; + (*tmp)->cst.trystat = cst->trystat; + + if ((isflo == OUT_FLO) || (isflo == OUT_PKT)) + switch (flavor) { + case '?': break; + case 'i': (*tmp)->flavors |= F_IMM; break; + case 'o': (*tmp)->flavors |= F_NORMAL; break; + case 'c': (*tmp)->flavors |= F_CRASH; break; + case 'h': (*tmp)->flavors |= F_HOLD; break; + default: tasklog('?', "Unknown flavor: '%c'\n",flavor); break; + } + + if (stat(fname,&st) != 0) { + tasklog('?', "$Can't stat %s", fname); + st.st_size = 0L; + (void)time(&st.st_mtime); + } + + /* + * Find the oldest time + */ + if (st.st_mtime < (*tmp)->time) + (*tmp)->time = st.st_mtime; + + if (isflo == OUT_FLO) { + if ((fp = fopen(fname,"r"))) { + while (fgets(buf, sizeof(buf) - 1, fp)) { + if (*(p = buf + strlen(buf) - 1) == '\n') + *p-- = '\0'; + while (isspace(*p)) + *p-- = '\0'; + for (p = buf; *p; p++) + if (*p == '\\') + *p='/'; + for (p = buf; *p && isspace(*p); p++); + if (*p == '~') continue; + if ((*p == '#') || (*p == '-') || (*p == '^') || (*p == '@')) + p++; + if (stat(p, &st) != 0) { + if (strlen(CFG.dospath)) { + if (stat(Dos2Unix(p), &st) != 0) { + /* + * Fileattach dissapeared, maybe + * the node doesn't poll enough and + * is losing mail or files. + */ + st.st_size = 0L; + (void)time(&st.st_mtime); + } + } else { + if (stat(p, &st) != 0) { + st.st_size = 0L; + (void)time(&st.st_mtime); + } + } + } + + if ((p = strrchr(fname,'/'))) + p++; + else + p = fname; + if ((strlen(p) == 12) && (strspn(p,"0123456789abcdefABCDEF") == 8) && (p[8] == '.')) { + if (st.st_mtime < (*tmp)->time) + (*tmp)->time = st.st_mtime; + } + (*tmp)->size += st.st_size; + } + fclose(fp); + } else + tasklog('?', "Can't open %s", fname); + + } else if (isflo == OUT_PKT) { + (*tmp)->size += st.st_size; + } else if (isflo == OUT_REQ) { + (*tmp)->flavors |= F_FREQ; + } else if (isflo == OUT_POL) { + (*tmp)->flavors |= F_POLL; + } + + return 0; +} + + diff --git a/mbtask/outstat.h b/mbtask/outstat.h new file mode 100644 index 00000000..e1aadd6b --- /dev/null +++ b/mbtask/outstat.h @@ -0,0 +1,10 @@ +#ifndef _OUTSTAT_H +#define _OUTSTAT_H + + +int each(faddr *, char, int, char *); +int outstat(void); + + +#endif + diff --git a/mbtask/scanout.c b/mbtask/scanout.c new file mode 100644 index 00000000..f745a26d --- /dev/null +++ b/mbtask/scanout.c @@ -0,0 +1,242 @@ +/***************************************************************************** + * + * File ..................: mbtask/scanout.c + * Purpose ...............: Outbound scanning + * Last modification date : 09-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskutil.h" +#include "scanout.h" + + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + + +static faddr addr = { + NULL, + 0,0,0,0, + NULL +}; + + +extern struct sysconfig CFG; +extern struct _fidonet fidonet; + + + +static int scan_dir(int (*)(faddr*,char,int,char*),char*,int); +static int scan_dir(int (*fn)(faddr *, char, int, char *), char *dname, int ispoint) +{ + char fname[PATH_MAX]; + char flavor = '?'; + DIR *dp = NULL; + struct dirent *de; + int rc = 0, isflo, fage; + time_t t_start; + + t_start = time(NULL); +// tasklog('o' ,"scan_dir \"%s\" (%s)",MBSE_SS(dname),ispoint?"point":"node"); + + if ((dp = opendir(dname)) == NULL) { + tasklog('-', "Creating directory %s", dname); + /* + * Create a fake filename, mkdirs() likes that. + */ + sprintf(fname, "%s/foo", dname); + (void)mkdirs(fname); + if ((dp = opendir(dname)) == NULL) { + tasklog('o' ,"\"%s\" cannot be opened, proceed",MBSE_SS(dname)); + return 0; + } + } + + while ((de=readdir(dp))) + if ((strlen(de->d_name) == 12) && (de->d_name[8] == '.') && + (strspn(de->d_name,"0123456789abcdefABCDEF") == 8)) { +// tasklog('o' ,"checking: \"%s\"",de->d_name); + addr.point= 0; + strncpy(fname,dname,PATH_MAX-2); + strcat(fname,"/"); + strncat(fname,de->d_name,PATH_MAX-strlen(fname)-2); + + if ((strcasecmp(de->d_name+9,"pnt") == 0) && !ispoint) { + sscanf(de->d_name,"%04x%04x",&addr.net,&addr.node); + if ((rc = scan_dir(fn, fname, 1))) + goto exout; + } else if ((strcasecmp(de->d_name+8,".out") == 0) || + (strcasecmp(de->d_name+8,".cut") == 0) || + (strcasecmp(de->d_name+8,".hut") == 0) || + (strcasecmp(de->d_name+8,".iut") == 0) || + (strcasecmp(de->d_name+8,".opk") == 0) || + (strcasecmp(de->d_name+8,".cpk") == 0) || + (strcasecmp(de->d_name+8,".hpk") == 0) || + (strcasecmp(de->d_name+8,".ipk") == 0) || + (strcasecmp(de->d_name+8,".flo") == 0) || + (strcasecmp(de->d_name+8,".clo") == 0) || + (strcasecmp(de->d_name+8,".hlo") == 0) || + (strcasecmp(de->d_name+8,".ilo") == 0) || + (strcasecmp(de->d_name+8,".req") == 0) || + (strcasecmp(de->d_name+8,".pol") == 0)) { + if (ispoint) + sscanf(de->d_name,"%08x", &addr.point); + else + sscanf(de->d_name,"%04x%04x", &addr.net,&addr.node); + flavor = tolower(de->d_name[9]); + if (flavor == 'f') + flavor='o'; + if (strcasecmp(de->d_name+10,"ut") == 0) + isflo=OUT_PKT; + else if (strcasecmp(de->d_name+10,"pk") == 0) + isflo=OUT_DIR; + else if (strcasecmp(de->d_name+10,"lo") == 0) + isflo=OUT_FLO; + else if (strcasecmp(de->d_name+9,"req") == 0) + isflo=OUT_REQ; + else if (strcasecmp(de->d_name+9,"pol") == 0) + isflo=OUT_POL; + else + isflo=-1; +// tasklog('o' ,"%s \"%s\"", (isflo == OUT_FLO) ? "flo file" : "packet", de->d_name); + if ((rc=fn(&addr,flavor,isflo,fname))) + goto exout; + } else if ((strncasecmp(de->d_name+9,"su",2) == 0) || + (strncasecmp(de->d_name+9,"mo",2) == 0) || + (strncasecmp(de->d_name+9,"tu",2) == 0) || + (strncasecmp(de->d_name+9,"we",2) == 0) || + (strncasecmp(de->d_name+9,"th",2) == 0) || + (strncasecmp(de->d_name+9,"fr",2) == 0) || + (strncasecmp(de->d_name+9,"sa",2) == 0)) { + isflo = OUT_ARC; + if ((rc = fn(&addr, flavor, isflo, fname))) + goto exout; + +// tasklog('o' ,"arcmail file \"%s\"",de->d_name); + sprintf(fname, "%s/%s", dname, de->d_name); + fage = (int)((t_start - file_time(fname)) / 86400); + + if (file_size(fname) == 0) { +// tasklog('o', "Age %d days", fage); + /* + * Remove truncated ARCmail that has a day extension + * other then the current day or if the file is older + * then 6 days. + */ + if ((strncasecmp(de->d_name+9, dayname(), 2)) || (fage > 6)) { + if (unlink(fname) == 0) + tasklog('-', "Removed truncated ARCmail file %s", fname); + } + } + + if (CFG.toss_days && (fage > CFG.toss_days)) { + /* + * Remove ARCmail that is on hold too long. + */ + if (unlink(fname) == 0) + tasklog('+', "Removed ARCmail %s, %d days", fname, fage); + } + } else { +// tasklog('o' ,"skipping \"%s\"",de->d_name); + } + } + +exout: + closedir(dp); + return rc; +} + + + +int scanout(int (*fn)(faddr *, char, int, char *)) +{ + int i, j, rc = 0; + unsigned short zone = 0; + char fext[5]; + char *p = NULL, *q = NULL; + DIR *dp; + + if ((dp = opendir(CFG.outbound)) == NULL) { + tasklog('?', "$Can't open outbound directory \"%s\" for reading", MBSE_SS(CFG.outbound)); + return 1; + } + closedir(dp); + + /* + * Build outbound directory names with zone numbers. + */ + for (i = 0; i < 40; i++) { + if ((CFG.aka[i].zone) && (CFG.aka[i].zone != zone)) { + zone = CFG.aka[i].zone; + if (SearchFidonet(zone)) { + for (j = 0; j < 6; j++) { + /* + * Create outbound directory name for + * the primary aka of that zone. + */ + p = xstrcpy(CFG.outbound); + if (zone != CFG.aka[0].zone) { + if ((q = strrchr(p, '/'))) + *q = '\0'; + p = xstrcat(p, (char *)"/"); + p = xstrcat(p, fidonet.domain); + } + + /* + * Not primary zones in the domain get + * a directory extension. + */ + if (fidonet.zone[j]) { + if (j) { + sprintf(fext, ".%03x", fidonet.zone[j]); + p = xstrcat(p, fext); + } +// tasklog('o', "Zone %d Dir %s", fidonet.zone[j], p); + addr.zone = fidonet.zone[j]; + addr.domain = fidonet.domain; + + if ((rc = scan_dir(fn, p, 0))) { + if (p) + free(p); + p = NULL; + return rc; + } + } + + if (p) + free(p); + p = NULL; + } + } + } + } + return rc; +} + + diff --git a/mbtask/scanout.h b/mbtask/scanout.h new file mode 100644 index 00000000..b5dcdfc2 --- /dev/null +++ b/mbtask/scanout.h @@ -0,0 +1,13 @@ +#ifndef SCANOUT_H +#define SCANOUT_H + +#define OUT_PKT 0 +#define OUT_DIR 1 +#define OUT_FLO 2 +#define OUT_ARC 3 +#define OUT_REQ 4 +#define OUT_POL 5 + +extern int scanout(int (*)(faddr*,char,int,char*)); + +#endif diff --git a/mbtask/signame.c b/mbtask/signame.c new file mode 100644 index 00000000..1ccff62f --- /dev/null +++ b/mbtask/signame.c @@ -0,0 +1,94 @@ +/***************************************************************************** + * + * File ..................: signame.c + * Purpose ...............: Signal names + * Last modification date : 24-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "signame.h" + + +/* + * Signal handler signal names. + */ + +#ifdef __i386__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __PPC__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __sparc__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGLOST", "SIGUSR1", "SIGUSR2"}; +#endif + +#ifdef __alpha__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGINFO", "SIGUSR1", "SIGUSR2"}; + + +#endif + diff --git a/mbtask/signame.h b/mbtask/signame.h new file mode 100644 index 00000000..cfeb4e4b --- /dev/null +++ b/mbtask/signame.h @@ -0,0 +1,9 @@ +#ifndef _SIGNAME_H +#define _SIGNAME_H + + +char SigName[32][16]; + + +#endif + diff --git a/mbtask/taskcomm.c b/mbtask/taskcomm.c new file mode 100644 index 00000000..04a1771c --- /dev/null +++ b/mbtask/taskcomm.c @@ -0,0 +1,466 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskcomm.c + * Purpose ...............: MBSE BBS Daemon + * Last modification date : 05-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************** + * + * This program uses the BSD IPC stream sockets mechanism. This is the + * server program. You need an entry in /etc/services for tcp service + * "mbse" on port 60180. Yes, this is 1 higher as for ifcico. You don't + * need an entry in inetd.conf, because this program is written as a + * daemon for fast access. + * + *****************************************************************************/ + +#include "libs.h" +#include "taskstat.h" +#include "taskregs.h" +#include "taskdisk.h" +#include "taskinfo.h" +#include "taskutil.h" +#include "taskcomm.h" + + +extern int oserr; /* Copy of Unix error */ +extern int sock; /* Server socket */ +extern struct sockaddr_un from; /* From socket address */ +extern int fromlen; /* From address length */ +extern int logtrans; /* Log transactions */ + + +/************************************************************************ + * + * Logging procedures. + */ + +int userlog(char *); +int userlog(char *param) +{ + char *prname, *prpid, *grade, *msg; + static char lfn[64], token[14]; + + lfn[0] = '\0'; + strcpy(token, strtok(param, ",")); + strcpy(token, strtok(NULL, ",")); + sprintf(lfn, "%s/log/%s", getenv("MBSE_ROOT"), token); + prname = strtok(NULL, ","); + prpid = strtok(NULL, ","); + grade = strtok(NULL, ","); + msg = strtok(NULL, "\0"); + msg[strlen(msg) -1] = '\0'; + return ulog(lfn, grade, prname, prpid, msg); +} + + + +/* + * Process command received from the client. + */ +char *exe_cmd(char *); +char *exe_cmd(char *in) +{ + static char obuf[SS_BUFSIZE]; + static char ibuf[SS_BUFSIZE]; + static char cmd[4]; + static char token[SS_BUFSIZE]; + static char ebuf[19]; + static char *cnt, var1[16]; + int result; + + strcpy(ibuf, in); + strncpy(cmd, ibuf, 4); + token[0] = '\0'; + strcpy(ebuf, "200:1,Syntax error;"); + + /* + * Split the commandline after the colon so we can give the + * options directly to the actual functions. Also set a default + * and most used answer. + */ + strcpy(token, &ibuf[5]); + strcpy(obuf, "100:0;"); + + + /* + * The A(counting) commands. + * + * AINI:5,pid,tty,user,program,city; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "AINI", 4) == 0) { + if (reg_newcon(token) != -1) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ACLO:1,pid; + * 107:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd ,"ACLO", 4) == 0) { + if (reg_closecon(token) == 0) { + strcpy(obuf, "107:0;"); + return obuf; + } else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ADOI:2,pid,doing; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "ADOI", 4) == 0) { + if (reg_doing(token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ATTY:2,pid,tty; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "ATTY", 4) == 0) { + if (reg_tty(token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ALOG:5,file,program,pid,grade,text; + * 100:0; + * 201:1,errno; + */ + if (strncmp(cmd, "ALOG", 4) == 0) { + if (userlog(token) != 0) + sprintf(obuf, "201:1,%d;", oserr); + return obuf; + } + + /* + * AUSR:3,pid,user,city; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "AUSR", 4) == 0) { + if (reg_user(token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ADIS:2,pid,flag; (set Do Not Disturb). + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "ADIS", 4) == 0) { + if (reg_silent(token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ATIM:2,pid,seconds; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "ATIM", 4) == 0) { + if (reg_timer(TRUE, token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ADEF:1,pid; + * 100:0; + */ + if (strncmp(cmd, "ADEF", 4) == 0) { + if (reg_timer(FALSE, token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * The chat commands + * + * CIPM:1,pid; (Is personal message present) + * 100:2,fromname,message; + * 100:0; + */ + if (strncmp(cmd, "CIPM", 4) == 0) { + return reg_ipm(token); + } + + /* + * CSPM:3,fromuser,touser,text; (Send personal message). + * 100:1,n; n: 0=oke, 1=donotdisturb 2=buffer full 3=error + * 100:0; + */ + if (strncmp(cmd, "CSPM", 4) == 0) { + if ((result = reg_spm(token))) { + sprintf(obuf, "100:1,%d;", result); + return obuf; + } else + return obuf; + } + + /* + * The G(lobal) commands. + * + * GNOP:1,pid; + * 100:0; + */ + if (strncmp(cmd ,"GNOP", 4) == 0) { + reg_nop(token); + return obuf; + } + + /* + * GPNG:n,data; + * 100:n,data; + */ + if (strncmp(cmd, "GPNG", 4) == 0) { + sprintf(obuf, "100:%s", token); + return obuf; + } + + /* + * GVER:0; + * 100:1,Version ...; + */ + if (strncmp(cmd, "GVER", 4) == 0) { + sprintf(obuf, "100:1,Version %s;", VERSION); + return obuf; + } + + /* + * GSTA:0; + * 100:19,start,laststart,daily,startups,clients,tot_clients,tot_peak,tot_syntax,tot_comerr, + * today_clients,today_peak,today_syntax,today_comerr,!BBSopen,ZMH,internet,Processing,Load,sequence; + * 201:1,16; + */ + if (strncmp(cmd, "GSTA", 4) == 0) { + return stat_status(); + } + + /* + * GMON:1,n; n=1 First time + * 100:7,pid,tty,user,program,city,isdoing,starttime; + * 100:0; + */ + if (strncmp(cmd, "GMON", 4) == 0) { + cnt = strtok(token, ","); + strcpy(var1, strtok(NULL, ";")); + return get_reginfo(atoi(var1)); + } + + /* + * GDST:0; + * 100:n,data1,..,data10; + */ + if (strncmp(cmd, "GDST", 4) == 0) { + return get_diskstat(); + } + + /* + * GSYS:0; + * 100:7,calls,pots_calls,isdn_calls,network_calls,local_calls,startdate,last_caller; + * 201:1,16; + */ + if (strncmp(cmd, "GSYS", 4) == 0) { + return get_sysinfo(); + } + + /* + * GLCC:0; + * 100:1,n; + */ + if (strncmp(cmd, "GLCC", 4) == 0) { + return get_lastcallercount(); + } + + /* + * GLCR:1,recno; + * 100:9,user,location,level,device,time,mins,calls,speed,actions; + * 201:1,16; + */ + if (strncmp(cmd, "GLCR", 4) == 0) { + cnt = strtok(token, ","); + strcpy(var1, strtok(NULL, ";")); + return get_lastcallerrec(atoi(var1)); + } + + + /* + * The (S)tatus commands. + * + * SBBS:0; + * 100:2,n,status message; + */ + if (strncmp(cmd, "SBBS", 4) == 0) { + switch(stat_bbs_stat()) { + case 0: + sprintf(obuf, "100:2,0,The system is open for use;"); + break; + case 1: + sprintf(obuf, "100:2,1,The system is closed right now!;"); + break; + case 2: + sprintf(obuf, "100:2,2,The system is closed for Zone Mail Hour!;"); + break; + } + return obuf; + } + + /* + * SOPE:0; + * 100:0; + */ + if (strncmp(cmd, "SOPE", 4) == 0) { + stat_set_open(1); + return obuf; + } + + /* + * SCLO:1,message; + * 100:0; + */ + if (strncmp(cmd, "SCLO", 4) == 0) { + stat_set_open(0); + return obuf; + } + + /* + * SFRE:0; + * 100:1,Running utilities: n Active users: n; + * 100:0; + * 201:1,16; + */ + if (strncmp(cmd, "SFRE", 4) == 0) { + return reg_fre(); + } + + /* + * SSEQ:0; + * 100:1,number; + * 200:1,16; + */ + if (strncmp(cmd, "SSEQ", 4) == 0) { + return getseq(); + } + + /* + * SEST:1,semafore; Get status of semafore + * 100:1,n; 1 = set, 0 = not set + * 200:1,16; + */ + if (strncmp(cmd, "SEST", 4) == 0) { + return sem_status(token); + } + + /* + * SECR:1,semafore; Set semafore + * 100:0; + * 200:1,16; + */ + if (strncmp(cmd, "SECR", 4) == 0) { + return sem_create(token); + } + + /* + * SERM:1,semafore; Remove semafore + * 100:0; + * 200:1,16; + */ + if (strncmp(cmd, "SERM", 4) == 0) { + return sem_remove(token); + } + + + /* + * If we got this far, there must be an error. + */ + stat_inc_serr(); + return ebuf; +} + + + +void do_cmd(char *cmd) +{ + char buf[SS_BUFSIZE]; + int slen, tries = 0; + + sprintf(buf, "%s", exe_cmd(cmd)); + if (logtrans) { + tasklog('-', "< %s", cmd); + tasklog('-', "> %s", buf); + } + + for (;;) { + slen = sendto(sock, buf, strlen(buf), 0, &from, fromlen); + if (slen == -1) + tasklog('?', "$do_cmd(): sendto error %d %s", tries, from.sun_path); + else if (slen != strlen(buf)) + tasklog('?', "do_cmd(): send %d of %d bytes, try=%d", slen, strlen(buf), tries); + else + return; + tries++; + if (tries == 3) + return; + sleep(1); + } +} + + diff --git a/mbtask/taskcomm.h b/mbtask/taskcomm.h new file mode 100644 index 00000000..50c17b34 --- /dev/null +++ b/mbtask/taskcomm.h @@ -0,0 +1,7 @@ +#ifndef _TASKCOMM_H +#define _TASKCOMM_H + +void do_cmd(char *); + +#endif + diff --git a/mbtask/taskdisk.c b/mbtask/taskdisk.c new file mode 100644 index 00000000..a3019138 --- /dev/null +++ b/mbtask/taskdisk.c @@ -0,0 +1,93 @@ +/***************************************************************************** + * + * File ..................: mbtask/statdisk.c + * Purpose ...............: Give status of all filesystems + * Last modification date : 23-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 Internet: mbse@user.sourceforge.net + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "taskdisk.h" +#include "taskutil.h" + + + +/* + * This function returns the information of all mounted filesystems, + * but no more then 10 filesystems. + */ +char *get_diskstat() +{ + char *mtab, *dev, *fs, *type, *tmp = NULL; + FILE *fp; + int i = 0; + static char buf[SS_BUFSIZE]; + struct statfs sfs; + char tt[80]; + unsigned long temp; + + buf[0] = '\0'; + mtab = calloc(256, sizeof(char)); + if ((fp = fopen((char *)"/etc/mtab", "r")) == 0) { + sprintf(buf, "100:0;"); + return buf; + } + + while (fgets(mtab, 255, fp)) { + dev = strtok(mtab, " "); + fs = strtok(NULL, " "); + type = strtok(NULL, " "); + if (strncmp((char *)"/dev/", dev, 5) == 0) { + if (statfs(fs, &sfs) == 0) { + i++; + if (tmp == NULL) + tmp = xstrcpy((char *)","); + else + tmp = xstrcat(tmp, (char *)","); + tt[0] = '\0'; + temp = (unsigned long)(sfs.f_bsize / 512L); + sprintf(tt, "%lu %lu %s %s", + (unsigned long)(sfs.f_blocks * temp) / 2048L, + (unsigned long)(sfs.f_bavail * temp) / 2048L, + fs, type); + tmp = xstrcat(tmp, tt); + } + if (i == 10) /* No more then 10 filesystems */ + break; + } + } + fclose(fp); + + if (strlen(tmp) > (SS_BUFSIZE - 8)) + sprintf(buf, "100:0;"); + else + sprintf(buf, "100:%d%s;", i, tmp); + + return buf; +} + + + diff --git a/mbtask/taskdisk.h b/mbtask/taskdisk.h new file mode 100644 index 00000000..64617450 --- /dev/null +++ b/mbtask/taskdisk.h @@ -0,0 +1,8 @@ +#ifndef _TASKDISK_H +#define _TASKDISK_H + +char *get_diskstat(void); /* Get disk status */ + + +#endif + diff --git a/mbtask/taskinfo.c b/mbtask/taskinfo.c new file mode 100644 index 00000000..10c9d454 --- /dev/null +++ b/mbtask/taskinfo.c @@ -0,0 +1,138 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskinfo.c + * Purpose ...............: Give system information + * Last modification date : 24-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskinfo.h" + + + +/* + * Get BBS System info. + */ +char *get_sysinfo(void) +{ + FILE *fp; + static char buf[SS_BUFSIZE]; + char *temp; + struct sysrec SYSINFO; + + sprintf(buf, "201:1,16;"); + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r")) == NULL) { + free(temp); + return buf; + } + free(temp); + + if (fread(&SYSINFO, sizeof(SYSINFO), 1, fp) == 1) + sprintf(buf, "100:7,%ld,%ld,%ld,%ld,%ld,%s,%s;", SYSINFO.SystemCalls, + SYSINFO.Pots, SYSINFO.ISDN, SYSINFO.Network, SYSINFO.Local, + ctime(&SYSINFO.StartDate), SYSINFO.LastCaller); + fclose(fp); + + return buf; +} + + + +char *get_lastcallercount(void) +{ + static char buf[SS_BUFSIZE]; + char *temp; + FILE *fp; + struct lastcallershdr LCALLhdr; + + sprintf(buf, "201:1,16;"); + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/lastcall.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + free(temp); + return buf; + } + fread(&LCALLhdr, sizeof(LCALLhdr), 1, fp); + fseek(fp, 0, SEEK_END); + sprintf(buf, "100:1,%ld;", ((ftell(fp) - LCALLhdr.hdrsize) / LCALLhdr.recsize)); + fclose(fp); + return buf; +} + + + +char *get_lastcallerrec(int Rec) +{ + static char buf[SS_BUFSIZE]; + char *temp, action[8]; + FILE *fp; + struct lastcallershdr LCALLhdr; + struct lastcallers LCALL; + + sprintf(buf, "201:1,16;"); + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/lastcall.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + free(temp); + return buf; + } + fread(&LCALLhdr, sizeof(LCALLhdr), 1, fp); + fseek(fp, ((Rec -1) * LCALLhdr.recsize) + LCALLhdr.hdrsize, SEEK_SET); + + if (fread(&LCALL, LCALLhdr.recsize, 1, fp) == 1) { + LCALL.UserName[15] = '\0'; + LCALL.Location[12] = '\0'; + strcpy(action, "-------"); + if (LCALL.Hidden) + action[0] = 'H'; + if (LCALL.Download) + action[1] = 'D'; + if (LCALL.Upload) + action[2] = 'U'; + if (LCALL.Read) + action[3] = 'R'; + if (LCALL.Wrote) + action[4] = 'W'; + if (LCALL.Chat) + action[5] = 'C'; + if (LCALL.Olr) + action[6] = 'O'; + action[7] = '\0'; + sprintf(buf, "100:9,%s,%s,%d,%s,%s,%d,%d,%s,%s;", LCALL.UserName, LCALL.Location, + LCALL.SecLevel, LCALL.Device, LCALL.TimeOn, + LCALL.CallTime, LCALL.Calls, LCALL.Speed, action); + } + + fclose(fp); + return buf; +} + + diff --git a/mbtask/taskinfo.h b/mbtask/taskinfo.h new file mode 100644 index 00000000..a366cf06 --- /dev/null +++ b/mbtask/taskinfo.h @@ -0,0 +1,10 @@ +#ifndef _TASKINFO_H +#define _TASKINFO_H + +char *get_sysinfo(void); /* Get System Info */ +char *get_lastcallercount(void); /* Get Lastcallers count */ +char *get_lastcallerrec(int); /* Get Lastcaller record */ + + +#endif + diff --git a/mbtask/taskregs.c b/mbtask/taskregs.c new file mode 100644 index 00000000..804d4bf3 --- /dev/null +++ b/mbtask/taskregs.c @@ -0,0 +1,478 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskregs.c + * Purpose ...............: Buffers for registration information. + * Last modification date : 07-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "taskstat.h" +#include "taskregs.h" +#include "taskutil.h" + +extern reg_info reginfo[MAXCLIENT]; /* Array with clients */ +static int entrypos = 0; /* Status pointer */ + + +/*********************************************************************** + * + * Search for a pid. + */ +int reg_find(char *); +int reg_find(char *pids) +{ + int i; + + for (i = 0; i < MAXCLIENT; i++) { + if ((int)reginfo[i].pid == atoi(pids)) + return i; + } + + tasklog('?', "Panic, pid %s not found", pids); + return -1; +} + + + +/*********************************************************************** + * + * Registrate a new connection and fill the data. + */ + +int reg_newcon(char *data) +{ + char *cnt, *pid, *tty, *uid, *prg, *city; + int retval; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + tty = strtok(NULL, ","); + uid = strtok(NULL, ","); + prg = strtok(NULL, ","); + city = strtok(NULL, ";"); + + /* + * Abort if no empty record is found + */ + if ((retval = reg_find((char *)"0")) == -1) { + tasklog('?', "Maximum clients (%d) reached", MAXCLIENT); + return -1; + } + + memset((char *)®info[retval], 0, sizeof(reg_info)); + reginfo[retval].pid = atoi(pid); + strncpy((char *)®info[retval].tty, tty, 6); + strncpy((char *)®info[retval].uname, uid, 35); + strncpy((char *)®info[retval].prg, prg, 14); + strncpy((char *)®info[retval].city, city, 35); + strcpy((char *)®info[retval].doing, "-"); + reginfo[retval].started = time(NULL); + reginfo[retval].lastcon = time(NULL); + reginfo[retval].altime = 600; + + /* + * Everyone says do not disturb, unless the flag + * is cleared by the owner of this process. + */ + reginfo[retval].silent = 1; + + tasklog('-', "Registered client pgm \"%s\", pid %s, slot %d", prg, pid, retval); + stat_inc_clients(); + return retval; +} + + + +int reg_closecon(char *data) +{ + char *cnt, *pid; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ";"); + if ((rec = reg_find(pid)) == -1) + return -1; + + tasklog('-', "Unregistered client pgm \"%s\", pid %s, slot %d", reginfo[rec].prg, pid, rec); + memset(®info[rec], 0, sizeof(reg_info)); + stat_dec_clients(); + return 0; +} + + + +/* + * Check all registred connections. + */ +void reg_check(void) +{ + int i; + time_t Now; + + Now = time(NULL); + for (i = 1; i < MAXCLIENT; i++) { + if (reginfo[i].pid) { + if (kill(reginfo[i].pid, 0) == -1) { + if (errno == ESRCH) { + tasklog('?', "Stale registration found for pid %d (%s)", reginfo[i].pid, reginfo[i].prg); + memset(®info[i], 0, sizeof(reg_info)); + stat_dec_clients(); + } + } else { + /* + * Check timeout + */ + if ((Now - reginfo[i].lastcon) >= reginfo[i].altime) { + if (reginfo[i].altime < 600) { + kill(reginfo[i].pid, SIGKILL); + tasklog('+', "Send SIGKILL to pid %d", reginfo[i].pid); + } else { + kill(reginfo[i].pid, SIGTERM); + tasklog('+', "Send SIGTERM to pid %d", reginfo[i].pid); + } + /* + * 10 seconds to the next kill + */ + reginfo[i].altime = 10; + reginfo[i].lastcon = time(NULL); + } + } + } + } +} + + + +/* + * Update doing information for this process. + */ +int reg_doing(char *data) +{ + char *cnt, *pid, *line; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + line = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return -1; + + strncpy(reginfo[rec].doing, line, 35); + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Update timer using NOP + */ +int reg_nop(char *data) +{ + char *cnt, *pid; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ";"); + if ((rec = reg_find(pid)) == -1) + return -1; + + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Set new timer value + */ +int reg_timer(int Set, char *data) +{ + char *pid; + int cnt, rec, val; + + cnt = atoi(strtok(data, ",")); + if (Set) { + if (cnt != 2) + return -1; + pid = strtok(NULL, ","); + val = atoi(strtok(NULL, ";")); + if (val < 600) + val = 600; + } else { + if (cnt != 1) + return -1; + pid = strtok(NULL, ";"); + val = 600; + } + + if ((rec = reg_find(pid)) == -1) + return -1; + + reginfo[rec].altime = val; + reginfo[rec].lastcon = time(NULL); + tasklog('r', "Set timeout value for %d to %d", reginfo[rec].pid, val); + return 0; +} + + + +/* + * Update tty information for this process. + */ +int reg_tty(char *data) +{ + char *cnt, *pid, *tty; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + tty = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return -1; + + strncpy((char *)®info[rec].tty, tty, 6); + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Update the "do not disturb" flag. + */ +int reg_silent(char *data) +{ + char *cnt, *pid, *line; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + line = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return -1; + + reginfo[rec].silent = atoi(line); + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Update username and city for this process. + */ +int reg_user(char *data) +{ + char *cnt, *pid, *user, *city; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + user = strtok(NULL, ","); + city = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return -1; + + strncpy((char *)®info[rec].uname, user, 35); + strncpy((char *)®info[rec].city, city, 35); + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Check for personal message + */ +char *reg_ipm(char *data) +{ + char *cnt, *pid; + static char buf[128]; + int rec; + + buf[0] = '\0'; + + sprintf(buf, "100:0;"); + cnt = strtok(data, ","); + pid = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return buf; + + reginfo[rec].lastcon = time(NULL); + if (!reginfo[rec].ismsg) + return buf; + + buf[0] = '\0'; + sprintf(buf, "100:2,%s,%s;", reginfo[rec].fname[reginfo[rec].ptr_out], reginfo[rec].msg[reginfo[rec].ptr_out]); + if (reginfo[rec].ptr_out < RB) + reginfo[rec].ptr_out++; + else + reginfo[rec].ptr_out = 0; + if (reginfo[rec].ptr_out == reginfo[rec].ptr_in) + reginfo[rec].ismsg = FALSE; + tasklog('+', "reg_ipm: in=%d out=%d ismsg=%d", reginfo[rec].ptr_in, reginfo[rec].ptr_out, reginfo[rec].ismsg); + + return buf; +} + + + +/* + * Send personal message + */ +int reg_spm(char *data) +{ + char *cnt, *from, *too, *txt; + int i; + + cnt = strtok(data, ","); + from = strtok(NULL, ","); + too = strtok(NULL, ","); + txt = strtok(NULL, ";"); + + for (i = 1; i < MAXCLIENT; i++) { + if (reginfo[i].pid && (strcasecmp(reginfo[i].uname, too) == 0)) { + /* + * If the in and out pointers are the same and the + * message present flag is still set, then this user + * can't get anymore new messages. + */ + if (reginfo[i].ismsg && (reginfo[i].ptr_in == reginfo[i].ptr_out)) { + return 2; + } + + /* + * If user has the "do not distrurb" flag set. + */ + if (reginfo[i].silent) { + return 1; + } + + /* + * If all is well, insert the new message. + */ + strncpy((char *)®info[i].fname[reginfo[i].ptr_in], from, 35); + strncpy((char *)®info[i].msg[reginfo[i].ptr_in], txt, 80); + if (reginfo[i].ptr_in < RB) + reginfo[i].ptr_in++; + else + reginfo[i].ptr_in = 0; + reginfo[i].ismsg = TRUE; + tasklog('+', "reg_spm: in=%d out=%d ismsg=%d", reginfo[i].ptr_in, reginfo[i].ptr_out, reginfo[i].ismsg); + return 0; + } + } + + /* + * User not found + */ + return 3; +} + + + +char *reg_fre(void) +{ + static char buf[80]; + int i, users = 0, utils = 0; + + buf[0] = '\0'; + + for (i = 1; i < MAXCLIENT; i++) { + if (reginfo[i].pid) { + if ((!strncmp(reginfo[i].prg, "mbsebbs", 7)) || + (!strncmp(reginfo[i].prg, "mbftpd", 6))) + users++; + + if ((!strncmp(reginfo[i].prg, "mbfido", 6)) || + (!strncmp(reginfo[i].prg, "mbmail", 6)) || + (!strncmp(reginfo[i].prg, "mball", 5)) || + (!strncmp(reginfo[i].prg, "mbaff", 5)) || + (!strncmp(reginfo[i].prg, "mbcico", 6)) || + (!strncmp(reginfo[i].prg, "mbfile", 6)) || + (!strncmp(reginfo[i].prg, "mbmsg", 5)) || + (!strncmp(reginfo[i].prg, "mbindex", 7)) || + (!strncmp(reginfo[i].prg, "mbdiff", 6)) || + (!strncmp(reginfo[i].prg, "mbuser", 6))) + utils++; + } + } + + if (users || utils) + sprintf(buf, "100:1,Running utilities: %02d Active users: %02d;", utils, users); + else + sprintf(buf, "100:0;"); + return buf; +} + + + +/* + * Get registration information. The first time the parameter + * must be 1, for the next searches 0. Returns 100:0; if there + * is an error or the end of file is reached. + */ +char *get_reginfo(int first) +{ + static char buf[256]; + + memset(&buf, 0, sizeof(buf)); + sprintf(buf, "100:0;"); + + /* + * Loop forever until an error occours, eof is reached or + * the data is valid. Only in the last case valid data is + * returned to the caller. + */ + for (;;) { + if (first == 1) + entrypos = 0; + else + entrypos++; + + if (entrypos == MAXCLIENT) + return buf; + + if ((int)reginfo[entrypos].pid != 0) { + sprintf(buf, "100:7,%d,%s,%s,%s,%s,%s,%d;", + reginfo[entrypos].pid, reginfo[entrypos].tty, + reginfo[entrypos].uname, reginfo[entrypos].prg, + reginfo[entrypos].city, reginfo[entrypos].doing, + (int)reginfo[entrypos].started); + return buf; + } + } + /* never reached */ +} + + diff --git a/mbtask/taskregs.h b/mbtask/taskregs.h new file mode 100644 index 00000000..b70c1f6d --- /dev/null +++ b/mbtask/taskregs.h @@ -0,0 +1,49 @@ +#ifndef _TASKREGS_H +#define _TASKREGS_H + +#define MAXCLIENT 100 + + +/* + * Connected clients information + */ +#define RB 5 + +typedef struct _reg_info { + pid_t pid; /* Pid or zero if free */ + char tty[7]; /* Connected tty */ + char uname[36]; /* User name */ + char prg[15]; /* Program name */ + char city[36]; /* Users city */ + char doing[36]; /* What is going on */ + time_t started; /* Startime connection */ + time_t lastcon; /* Last connection */ + int altime; /* Alarm time */ + unsigned silent : 1; /* Do not disturb */ + unsigned chatting : 1; /* User is chatting */ + unsigned ismsg : 1; /* Message waiting */ + int channel; /* Chat channel */ + int ptr_in; /* Input buffer pointer */ + int ptr_out; /* Output buffer ptr */ + char fname[RB][36]; /* Message from user */ + char msg[RB][81]; /* The message itself */ +} reg_info; + + +void reg_init(void); +int reg_newcon(char *); +int reg_closecon(char *); +void reg_check(void); +int reg_doing(char *); +int reg_nop(char *); +int reg_timer(int, char *); +int reg_tty(char *); +int reg_user(char *); +int reg_silent(char *); +char *reg_ipm(char *); +int reg_spm(char *); +char *reg_fre(void); +char *get_reginfo(int); + +#endif + diff --git a/mbtask/taskstat.c b/mbtask/taskstat.c new file mode 100644 index 00000000..e9df9e2d --- /dev/null +++ b/mbtask/taskstat.c @@ -0,0 +1,438 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskstat.c + * Purpose ...............: Keep track of server status + * Last modification date : 09-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MB BBS 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 MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskstat.h" +#include "outstat.h" +#include "taskutil.h" + + + +/* + * Semafores + */ +int s_scanout = FALSE; +int s_mailout = FALSE; +int s_mailin = FALSE; +int s_reqindex = FALSE; +int s_index = FALSE; +int s_msglink = FALSE; +int s_newnews = FALSE; +int s_bbsopen = FALSE; +extern int UPSalarm; + + + +extern struct taskrec TCFG; +extern int internet; +extern int ZMH; + + +typedef struct { + long tot_clt; /* Total client connects */ + long peak_clt; /* Peak simultaneous tot_cltes */ + long s_error; /* Syntax errors from clients */ + long c_error; /* Comms errors from clients */ +} cl_stat; + + +typedef struct { + time_t start; /* Start date/time */ + time_t laststart; /* Last start date/time */ + time_t daily; /* Last daily update */ + long startups; /* Total starts */ + long clients; /* Connected clients */ + cl_stat total; /* Total statistics */ + cl_stat today; /* Todays statistics */ + unsigned open : 1; /* Is BBS open */ + unsigned long sequence; /* Sequencer counter */ +} status_r; + + +static char stat_fn[PATH_MAX]; /* Statusfile name */ +static status_r status; /* Status data */ +extern float Load; /* System Load */ +extern int Processing; /* Is system running */ + + +/************************************************************************ + * + * Initialize the statusfile, create it if necesary. + */ +void status_init() +{ + size_t cnt; + int stat_fd; + + sprintf(stat_fn, "%s/var/status.mbsed", getenv("MBSE_ROOT")); + + /* + * First check if this is the very first time we start the show. + * If so, we generate an empty status file with only the start + * date in it. + */ + stat_fd = open(stat_fn, O_RDWR); + if (stat_fd == -1) { + memset((char *)&status, 0, sizeof(status_r)); + status.start = time(NULL); + status.daily = time(NULL); + status.sequence = (unsigned long)time(NULL); + stat_fd = open(stat_fn, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + cnt = write(stat_fd, &status, sizeof(status_r)); + tasklog('+', "New statusfile created"); + lseek(stat_fd, 0, SEEK_SET); + } + + cnt = read(stat_fd, &status, sizeof(status_r)); + if (cnt != sizeof(status_r)) { + printf("Error reading status file\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + status.startups++; + status.laststart = time(NULL); + status.clients = 1; /* We are a client ourself */ + s_bbsopen = status.open; + lseek(stat_fd, 0, SEEK_SET); + cnt = write(stat_fd, &status, sizeof(status_r)); + if (cnt != sizeof(status_r)) { + tasklog('?', "$Error rewrite status file\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + close(stat_fd); +} + + + +/* + * Writeback the updated status record. + */ +void status_write(void); +void status_write(void) +{ + int d, stat_fd; + struct tm ttm, ytm; + time_t temp; + + temp = time(NULL); + ttm = *localtime(&temp); + ytm = *localtime(&status.daily); + + /* + * If we passed to the next day, zero the today counters + */ + if (ttm.tm_yday != ytm.tm_yday) { + tasklog('+', "Last days statistics:"); + tasklog('+', "Total clients : %lu", status.today.tot_clt); + tasklog('+', "Peak clients : %lu", status.today.peak_clt); + tasklog('+', "Syntax errors : %lu", status.today.s_error); + tasklog('+', "Comms errors : %lu", status.today.c_error); + + memset((char *)&status.today, 0, sizeof(cl_stat)); + status.daily = time(NULL); + tasklog('+', "Zeroed todays status counters"); + } + + stat_fd = open(stat_fn, O_RDWR); + d = lseek(stat_fd, 0, SEEK_SET); + d = write(stat_fd, &status, sizeof(status_r)); + if (d != sizeof(status_r)) + tasklog('?', "Error writing statusfile, only %d bytes", d); + + /* + * CLose the statusfile + */ + if (close(stat_fd) != 0) + tasklog('?', "$Error closing statusfile"); +} + + + +/************************************************************************* + * + * Various actions on the statusfile. + */ + + +/* + * Check for Zone Mail Hour, return TRUE if it is. + */ +int get_zmh() +{ + struct tm *l_date; + char sstime[6]; + time_t Now; + + Now = time(NULL); + l_date = gmtime(&Now); + sprintf(sstime, "%02d:%02d", l_date->tm_hour, l_date->tm_min); + + if ((strncmp(sstime, TCFG.zmh_start, 5) >= 0) && (strncmp(sstime, TCFG.zmh_end, 5) < 0)) { + if (!ZMH) { + CreateSema((char *)"zmh"); + sem_set((char *)"scanout", TRUE); + tasklog('!', "Start of Zone Mail Hour"); + ZMH = TRUE; + } + } else { + if (ZMH) { + RemoveSema((char *)"zmh"); + sem_set((char *)"scanout", TRUE); + tasklog('!', "End of Zone Mail Hour"); + ZMH = FALSE; + } + } + return ZMH; +} + + + +void stat_inc_clients() +{ + status.clients++; + status.total.tot_clt++; + status.today.tot_clt++; + if (status.clients >= status.total.peak_clt) + status.total.peak_clt = status.clients; + if (status.clients >= status.today.peak_clt) + status.today.peak_clt = status.clients; + + status_write(); +} + + + +void stat_dec_clients() +{ + status.clients--; + status_write(); +} + + + +void stat_set_open(int op) +{ + if (op) { + if (!s_bbsopen) { + tasklog('!', "The bbs is open"); + sem_set((char *)"scanout", TRUE); + } + } else { + if (s_bbsopen) { + tasklog('!', "The bbs is closed"); + } + } + s_bbsopen = status.open = op; + status_write(); +} + + + +void stat_inc_serr() +{ + status.total.s_error++; + status.today.s_error++; + status_write(); +} + + + +void stat_inc_cerr() +{ + status.total.c_error++; + status.today.c_error++; + status_write(); +} + + + +char *stat_status() +{ + static char buf[160]; + + buf[0] = '\0'; + sprintf(buf, "100:19,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%d,%d,%d,%d,%2.2f,%lu;", + status.start, status.laststart, status.daily, + status.startups, status.clients, + status.total.tot_clt, status.total.peak_clt, + status.total.s_error, status.total.c_error, + status.today.tot_clt, status.today.peak_clt, + status.today.s_error, status.today.c_error, + status.open, get_zmh(), internet, Processing, Load, status.sequence); + return buf; +} + + + +/* + * Return open status: + * 0 = open. + * 1 = closed. + * 2 = Zone Mail Hour. + */ +int stat_bbs_stat() +{ + if (!status.open) + return 1; + if (get_zmh()) + return 2; + return 0; +} + + + +/* + * Get next sequence number + */ +char *getseq(void) +{ + static char buf[80]; + + buf[0] = '\0'; + status.sequence++; + status_write(); + sprintf(buf, "100:1,%lu;", status.sequence); + return buf; +} + + + +int sem_set(char *sem, int value) +{ + int rc = TRUE; + + tasklog('s', "sem_set(%s, %s)", sem, value?"TRUE":"FALSE"); + + if (!strcmp(sem, "scanout")) { + if (value && !s_scanout) { + outstat(); + } + s_scanout = value; + } else if (!strcmp(sem, "mailout")) { + s_mailout = value; + } else if (!strcmp(sem, "mailin")) { + s_mailin = value; + } else if (!strcmp(sem, "mbindex")) { + s_index = value; + } else if (!strcmp(sem, "newnews")) { + s_newnews = value; + } else if (!strcmp(sem, "msglink")) { + s_msglink = value; + } else if (!strcmp(sem, "reqindex")) { + s_reqindex = value; + } else { + rc = FALSE; + } + return rc; +} + + + +char *sem_status(char *data) +{ + char *cnt, *sem; + static char buf[40]; + int value; + + buf[0] = '\0'; + sprintf(buf, "200:1,16;"); + cnt = strtok(data, ","); + sem = strtok(NULL, ";"); + + if (!strcmp(sem, "scanout")) { + value = s_scanout; + } else if (!strcmp(sem, "mailout")) { + value = s_mailout; + } else if (!strcmp(sem, "mailin")) { + value = s_mailin; + } else if (!strcmp(sem, "mbindex")) { + value = s_index; + } else if (!strcmp(sem, "newnews")) { + value = s_newnews; + } else if (!strcmp(sem, "msglink")) { + value = s_msglink; + } else if (!strcmp(sem, "reqindex")) { + value = s_reqindex; + } else if (!strcmp(sem, "upsalarm")) { + value = UPSalarm; + } else { + tasklog('s', "sem_status(%s) buf=%s", sem, buf); + return buf; + } + + sprintf(buf, "100:1,%s;", value ? "1":"0"); + tasklog('s', "sem_status(%s) = %d buf=%s", sem, value, buf); + return buf; +} + + + +char *sem_create(char *data) +{ + static char buf[40]; + char *cnt, *sem; + + cnt = strtok(data, ","); + sem = strtok(NULL, ";"); + buf[0] = '\0'; + sprintf(buf, "200:1,16;"); + + if (sem_set(sem, TRUE)) + sprintf(buf, "100:0;"); + + return buf; +} + + + +char *sem_remove(char *data) +{ + static char buf[40]; + char *cnt, *sem; + + cnt = strtok(data, ","); + sem = strtok(NULL, ";"); + buf[0] = '\0'; + sprintf(buf, "200:1,16;"); + + if (sem_set(sem, FALSE)) + sprintf(buf, "100:0;"); + + return buf; +} + + diff --git a/mbtask/taskstat.h b/mbtask/taskstat.h new file mode 100644 index 00000000..bc2e84e8 --- /dev/null +++ b/mbtask/taskstat.h @@ -0,0 +1,20 @@ +#ifndef _TASKSTAT_H +#define _TASKSTAT_H + +void status_init(void); /* Initialize status module */ +void stat_inc_clients(void); /* Increase connected clients */ +void stat_dec_clients(void); /* Decrease connected clients */ +void stat_set_open(int); /* Set BBS open status */ +void stat_inc_serr(void); /* Increase syntax error */ +void stat_inc_cerr(void); /* Increase comms error */ +char *stat_status(void); /* Return status record */ +int stat_bbs_stat(void); /* Get BBS open status */ +char *getseq(void); /* Get next sequence number */ +int get_zmh(void); /* Check Zone Mail Hour */ +int sem_set(char *, int); /* Set/Reset semafore */ +char *sem_status(char *); /* Get semafore status */ +char *sem_create(char *); /* Create semafore */ +char *sem_remove(char *); /* Remove semafore */ + +#endif + diff --git a/mbtask/taskutil.c b/mbtask/taskutil.c new file mode 100644 index 00000000..1b3d8725 --- /dev/null +++ b/mbtask/taskutil.c @@ -0,0 +1,439 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskutil.c + * Purpose ...............: MBSE BBS Task Manager, utilities + * Last modification date : 06-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute 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. + * + * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "signame.h" +#include "scanout.h" +#include "taskutil.h" + + + +pid_t mypid; /* Original parent pid if child */ +int oserr; /* Last OS error number */ +extern struct sysconfig CFG; +extern struct _fidonethdr fidonethdr; +extern struct _fidonet fidonet; +extern struct taskrec TCFG; + + + +static char *mon[] = { + (char *)"Jan",(char *)"Feb",(char *)"Mar", + (char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep", + (char *)"Oct",(char *)"Nov",(char *)"Dec" +}; + + + +/************************************************************************ + * + * Loging procedures. + */ + + +char *date(void); +char *date(void) +{ + struct tm ptm; + time_t now; + static char buf[20]; + + now = time(NULL); + ptm = *localtime(&now); + sprintf(buf,"%02d-%s-%04d %02d:%02d:%02d", ptm.tm_mday, mon[ptm.tm_mon], ptm.tm_year+1900, + ptm.tm_hour, ptm.tm_min, ptm.tm_sec); + return(buf); +} + + + +/* + * general log for this server + */ +void tasklog(int grade, const char *format, ...) +{ + va_list va_ptr; + char outstr[1024]; + int oldmask; + FILE *logfile; + char *logname; + + if (grade == '+' || grade == '-' || grade == '!' || grade == '?' || grade == ' ' || TCFG.debug) { + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + + logname = calloc(PATH_MAX, sizeof(char)); + oldmask=umask(066); + sprintf(logname, "%s/log/mbtask.log", getenv("MBSE_ROOT")); + logfile = fopen(logname, "a"); + umask(oldmask); + if (logfile == NULL) { + printf("Cannot open logfile \"%s\"\n", logname); + free(logname); + return; + } + + fprintf(logfile, "%c %s mbtask[%d] ", grade, date(), getpid()); + fprintf(logfile, *outstr == '$' ? outstr+1 : outstr); + if (*outstr == '$') + fprintf(logfile, ": %s\n", strerror(errno)); + else + fprintf(logfile, "\n"); + + fflush(logfile); + if (fclose(logfile) != 0) + printf("Cannot close logfile \"%s\"\n", logname); + + free(logname); + } + return; +} + + + +/* + * user log process + */ +int ulog(char *fn, char *grade, char *prname, char *prpid, char *format) +{ + int oldmask; + FILE *log; + + oldmask = umask(066); + log = fopen(fn, "a"); + umask(oldmask); + if (log == NULL) { + oserr = errno; + tasklog('!', "$Cannot open user logfile %s", fn); + return -1; + } + + fprintf(log, "%s %s %s[%s] ", grade, date(), prname, prpid); + fwrite(format, strlen(format), 1, log); + fprintf(log, "\n"); + + fflush(log); + if (fclose(log) != 0) { + oserr = errno; + tasklog('!', "$Cannot close user logfile %s", fn); + return -1; + } + return 0; +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = malloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = malloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + + + +void CreateSema(char *sem) +{ + char temp[PATH_MAX]; + int fd; + + sprintf(temp, "%s/sema/%s", getenv("MBSE_ROOT"), sem); + if (access(temp, F_OK) == 0) + return; + if ((fd = open(temp, O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) >= 0) + close(fd); + else + tasklog('?', "Can't create semafore %s", temp); +} + + + +void TouchSema(char *sem) +{ + char temp[PATH_MAX]; + int fd; + + sprintf(temp, "%s/sema/%s", getenv("MBSE_ROOT"), sem); + if ((fd = open(temp, O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) >= 0) { + close(fd); + } else + tasklog('?', "Can't touch semafore %s", temp); +} + + + +void RemoveSema(char *sem) +{ + char temp[PATH_MAX]; + + sprintf(temp, "%s/sema/%s", getenv("MBSE_ROOT"), sem); + if (access(temp, F_OK)) + return; + if (unlink(temp) == -1) + tasklog('?', "Can't remove semafore %s", temp); +} + + + +int IsSema(char *sem) +{ + char temp[PATH_MAX]; + + sprintf(temp, "%s/sema/%s", getenv("MBSE_ROOT"), sem); + return (access(temp, F_OK) == 0); +} + + + +/* + * Test if the given file exists. The second option is: + * R_OK - test for Read rights + * W_OK - test for Write rights + * X_OK - test for eXecute rights + * F_OK - test file presence only + */ +int file_exist(char *path, int mode) +{ + if (access(path, mode) != 0) + return errno; + + return 0; +} + + +/* + * Make directory tree, the name must end with a / + */ +int mkdirs(char *name) +{ + char buf[PATH_MAX], *p, *q; + int rc, last = 0, oldmask; + + memset(&buf, 0, sizeof(buf)); + strncpy(buf, name, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + + p = buf+1; + + oldmask = umask(000); + while ((q = strchr(p, '/'))) { + *q = '\0'; + rc = mkdir(buf, 0775); + last = errno; + *q = '/'; + p = q+1; + } + + umask(oldmask); + + if ((last == 0) || (last == EEXIST)) { + return TRUE; + } else { + tasklog('?', "$mkdirs(%s)", name); + return FALSE; + } +} + + + +/* + * Return size of file, or -1 if file doesn't exist + */ +long file_size(char *path) +{ + static struct stat sb; + + if (stat(path, &sb) == -1) + return -1; + + return sb.st_size; +} + + + +/* + * Return time of file, or -1 if file doen't exist, which is + * the same as 1 second before 1 jan 1970. You may test the + * result on -1 since time_t is actualy a long integer. + */ +time_t file_time(char *path) +{ + static struct stat sb; + + if (stat(path, &sb) == -1) + return -1; + + return sb.st_mtime; +} + + +/* + * Return ASCII string for node, the bits in 'fl' set the + * output format. + */ +char *ascfnode(faddr *a, int fl) +{ + static char buf[128]; + + if (a == NULL) { + strcpy(buf, ""); + return buf; + } + + buf[0] = '\0'; + if ((fl & 0x40) && (a->name)) + sprintf(buf+strlen(buf),"%s of ",a->name); + if ((fl & 0x08) && (a->zone)) + sprintf(buf+strlen(buf),"%u:",a->zone); + if (fl & 0x04) + sprintf(buf+strlen(buf),"%u/",a->net); + if (fl & 0x02) + sprintf(buf+strlen(buf),"%u",a->node); + if ((fl & 0x01) && (a->point)) + sprintf(buf+strlen(buf),".%u",a->point); + if ((fl & 0x10) && (a->domain)) + sprintf(buf+strlen(buf),"@%s",a->domain); + return buf; +} + + + +char *Dos2Unix(char *dosname) +{ + char buf[PATH_MAX]; + static char buf2[PATH_MAX]; + char *p, *q; + + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + sprintf(buf, "%s", dosname); + p = buf; + + if (strlen(CFG.dospath)) { + if (strncasecmp(p, CFG.dospath, strlen(CFG.dospath)) == 0) { + strcpy((char *)buf2, CFG.uxpath); + for (p+=strlen(CFG.dospath), q = buf2 + strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } else { + if (strncasecmp(p, CFG.uxpath, strlen(CFG.uxpath)) == 0) { + for (p+=strlen(CFG.uxpath), q = buf2 + strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } + } + } + return buf2; +} + + + +static char *dow[] = {(char *)"su", (char *)"mo", (char *)"tu", (char *)"we", + (char *)"th", (char *)"fr", (char *)"sa"}; + +char *dayname(void) +{ + time_t tt; + struct tm *ptm; + static char buf[3]; + + (void)time(&tt); + ptm = localtime(&tt); + sprintf(buf, "%s", dow[ptm->tm_wday]); + + return buf; +} + + + +void InitFidonet(void) +{ + memset(&fidonet, 0, sizeof(fidonet)); +} + + + +int SearchFidonet(unsigned short zone) +{ + FILE *fil; + char fidonet_fil[PATH_MAX]; + int i; + + sprintf(fidonet_fil, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fil = fopen(fidonet_fil, "r")) == NULL) { + return FALSE; + } + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + + while (fread(&fidonet, fidonethdr.recsize, 1, fil) == 1) { + for (i = 0; i < 6; i++) { + if (zone == fidonet.zone[i]) { + fclose(fil); + return TRUE; + } + } + } + fclose(fil); + return FALSE; +} + + diff --git a/mbtask/taskutil.h b/mbtask/taskutil.h new file mode 100644 index 00000000..d79d2e5a --- /dev/null +++ b/mbtask/taskutil.h @@ -0,0 +1,42 @@ +#ifndef _TASKUTIL_H +#define _TASKUTIL_H + + +#define TRUE 1 +#define FALSE 0 +#define SS_BUFSIZE 1024 /* Socket buffersize */ +#define MBSE_SS(x) (x)?(x):"(null)" + + +typedef struct _srv_auth { + struct _srv_auth *next; + char *hostname; + char *authcode; +} srv_auth; + + + +/* + * Function prototypes + */ +void tasklog(int, const char *, ...); +int ulog(char *, char *, char *, char *, char*); +char *xstrcpy(char *); +char *xstrcat(char *, char *); +void CreateSema(char *); +void TouchSema(char *); +void RemoveSema(char *); +int IsSema(char *); +int file_exist(char *, int); +int mkdirs(char *); +long file_size(char *); +time_t file_time(char *); +char *ascfnode(faddr *, int); +char *Dos2Unix(char *); +char *dayname(void); +void InitFidonet(void); +int SearchFidonet(unsigned short); + + +#endif + diff --git a/missing b/missing new file mode 100755 index 00000000..7789652e --- /dev/null +++ b/missing @@ -0,0 +1,190 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 00000000..6b3b5fc5 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id$ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/script/Makefile.am b/script/Makefile.am new file mode 100644 index 00000000..1be3c7f6 --- /dev/null +++ b/script/Makefile.am @@ -0,0 +1,29 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + @if [ ! -x $(sysconfdir)/maint ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 maint $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 maint $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/midnight ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 midnight $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 midnight $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/weekly ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 weekly $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 weekly $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/monthly ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 monthly $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 monthly $(sysconfdir)" ; \ + fi + @./installinit + +EXTRA_DIST = README maint midnight weekly monthly installinit rc rc.shutdown mbse.start mbse.stop + + diff --git a/script/Makefile.in b/script/Makefile.in new file mode 100644 index 00000000..1d668e34 --- /dev/null +++ b/script/Makefile.in @@ -0,0 +1,306 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = README maint midnight weekly monthly installinit rc rc.shutdown mbse.start mbse.stop +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps script/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = script + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + @if [ ! -x $(sysconfdir)/maint ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 maint $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 maint $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/midnight ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 midnight $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 midnight $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/weekly ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 weekly $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 weekly $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/monthly ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 monthly $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 monthly $(sysconfdir)" ; \ + fi + @./installinit + +# 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/script/README b/script/README new file mode 100644 index 00000000..c34b6ca6 --- /dev/null +++ b/script/README @@ -0,0 +1,7 @@ + MBSE BBS Script files. + +If you want to make any changes to the scripts, do it here and not in the +~/etc and ~/bin directories. After making the changes do a 'make install' +as root and the scripts are in place with the right permissions and owners. + + Michiel diff --git a/script/installinit b/script/installinit new file mode 100755 index 00000000..f2e2cc6d --- /dev/null +++ b/script/installinit @@ -0,0 +1,556 @@ +#!/bin/sh +# +# Installation script to install bootscripts. +# +# (C) Michiel Broek, v0.21 27-May-2001 +# +PATH=/bin:/sbin:/usr/bin:/usr/sbin:$MBSE_ROOT/bin +DISTNAME= +DISTVERS= +DISTINIT= +SU="su" + +#------------------------------------------------------------------------ +# +# Logging procedure, needs two parameters. +# +log() { + /bin/echo `date +%d-%b-%y\ %X ` $1 $2 >> installinit.log +} + + + +# Check one subdirectory +# +checkdir() { + if [ ! -d $1 ]; then + mkdir $1 + log "+" "[$?] created directory $1" + fi +} + + + +# Check /etc/rc.d subdirs +# +checkrcdir() { + checkdir "/etc/rc.d/init.d" + checkdir "/etc/rc.d/rc0.d" + checkdir "/etc/rc.d/rc1.d" + checkdir "/etc/rc.d/rc2.d" + checkdir "/etc/rc.d/rc3.d" + checkdir "/etc/rc.d/rc4.d" + checkdir "/etc/rc.d/rc5.d" + checkdir "/etc/rc.d/rc6.d" +} + + +#------------------------------------------------------------------------ +# + +log "+" "installinit started" + +# Basic checks. +if [ `whoami` != "root" ]; then +cat << EOF +*** Run $0 as root only! *** + + Because some of the system files must be changed, you must be root + to use this script. + +*** SETUP aborted *** +EOF + log "!" "Aborted, not root" + exit 2 +fi + +if [ "$MBSE_ROOT" = "" ]; then + echo "*** The MBSE_ROOT doesn't exist ***" + log "!" "Aborted, MBSE_ROOT variable doesn't exist" + exit 2 +fi + + +# First do various tests to see which Linux distribution this is. +# +if [ -f /etc/slackware-version ]; then + # Slackware 7.0 and later + DISTNAME="Slackware" + DISTVERS=`cat /etc/slackware-version` +else + if [ -f /etc/debian_version ]; then + # Debian, at least since version 2.2 + DISTNAME="Debian" + DISTVERS=`cat /etc/debian_version` + else + if [ -f /etc/SuSE-release ]; then + DISTNAME="SuSE" + DISTVERS=`cat /etc/SuSE-release | grep VERSION | awk '{ print $3 }'` + else + if [ -f /etc/redhat-release ]; then + DISTNAME="RedHat" + DISTVERS=`cat /etc/redhat-release | awk '{ print $5 }'` + else + if [ -f /etc/mandrake-release ]; then + DISTNAME="Mandrake" + # Format: Linux Mandrake release 8.0 (Cooker) for i586 + DISTVERS=`cat /etc/mandrake-release | awk '{ print $4 }'` + else + if [ -f /etc/rc.d/rc.0 ] && [ -f /etc/rc.d/rc.local ]; then + # If Slackware wasn't detected yet it is version 4.0 or older. + DISTNAME="Slackware" + DISTVERS="Old" + else + DISTNAME="Unknown" + log "!" "unknown distribution, collecting data" + log "-" "`uname -a`" + log "-" "`ls -la /etc`" + echo "Failed to install bootscripts, unknown Linux distribution." + echo "Please mail the file `pwd`/script/installinit.log to mbroek@users.sourceforge.net" + echo "or send it as file attach to Michiel Broek at 2:280/2802@Fidonet." + echo "Add information about the distribution you use in the message." + exit 1; + fi + fi + fi + fi + fi +fi + + +log "+" "Distribution $DISTNAME $DISTVERS" + + +#-------------------------------------------------------------------------- +# +# Adding scripts for SuSE +# +if [ "$DISTNAME" = "SuSE" ]; then + DISTINIT="/sbin/init.d/mbsed" + echo "Installing SystemV init scripts for SuSE" + log "+" "Installing SystemV init scripts for SuSE" + echo "Adding $DISTINIT" + +cat << EOF >$DISTINIT +#!/bin/bash +# Copyright (c) 2001 Michiel Broek +# +# Author: Michiel Broek , 23-May-2001 +# +# $DISTINIT for SuSE +# + +# Find the MBSE_ROOT from the /etc/passwd file. +MBSE_ROOT=\`cat /etc/passwd | grep mbse: | awk -F ':' '{ print \$6}'\` + +if [ "\$MBSE_ROOT" = "" ] +then + echo "MBSE BBS: No 'mbse' user in the password file." + exit 1 +fi + +if [ ! -d \$MBSE_ROOT ] +then + echo "MBSE BBS: Home directory '\$MBSE_ROOT' not found." + exit 1 +fi + +export MBSE_ROOT + +case "\$1" in + start|reload) + echo -n "MBSE BBS starting:" + rm -f \$MBSE_ROOT/sema/* + rm -f \$MBSE_ROOT/var/*.LCK + $SU mbse -c '\$MBSE_ROOT/bin/mbtask' >/dev/null + echo -n " mbtask" + if [ -f \$MBSE_ROOT/etc/config.data ]; then + $SU mbse -c '\$MBSE_ROOT/bin/mbstat open -quiet' + echo " and opened the bbs." + else + echo "" + fi + ;; + stop) + echo -n "MBSE BBS shutdown:" + if [ -f \$MBSE_ROOT/etc/config.data ]; then + echo -n " logoff users " + $SU mbse -c '\$MBSE_ROOT/bin/mbstat close wait -quiet' >/dev/null + echo -n "done," + fi + echo -n " stopping mbtask " + killproc \$MBSE_ROOT/bin/mbtask -15 + echo "done." + ;; + restart) + echo "Restarting MBSE BBS: just kidding!" + ;; + status) + echo -n "MBSE BBS status: " + if [ "\`/sbin/pidof mbtask\`" = "" ]; then + echo "mbtask is NOT running" + else + echo "mbtask Ok" + fi + ;; + *) + echo "Usage: \$0 {start|stop|status|reload|restart}" + exit 1 +esac +exit 0 +EOF + + chmod 755 /etc/rc.d/init.d/mbsed + echo "Making links for start/stop in runlevel 2" + ln -s ../mbsed /sbin/init.d/rc2.d/K05mbsed + ln -s ../mbsed /sbin/init.d/rc2.d/S99mbsed + echo "Making links for start/stop in runlevel 3" + ln -s ../mbsed /sbin/init.d/rc3.d/K05mbsed + ln -s ../mbsed /sbin/init.d/rc3.d/S99mbsed + echo "SuSE SystemV init configured" + log "+" "SuSE SystemV init configured" +fi + + + +#-------------------------------------------------------------------------- +# +# Adding scripts for Slackware +# +if [ "$DISTNAME" = "Slackware" ]; then + if [ "$DISTVERS" = "Old" ] || [ "$DISTVERS" = "7.0.0" ]; then + # + # Slackware before version 7.1 + # + DISTINIT="$MBSE_ROOT/etc/rc" + echo "Adding old style Slackware MBSE BBS start/stop scripts" + log "+" "Adding old style Slackware MBSE BBS start/stop scripts" + if [ "`grep MBSE /etc/rc.d/rc.local`" = "" ]; then + log "+" "Adding $MBSE_ROOT/etc/rc to /etc/rc.d/rc.local" + mv /etc/rc.d/rc.local /etc/rc.d/rc.local.mbse + cat /etc/rc.d/rc.local.mbse >/etc/rc.d/rc.local + echo "# Start MBSE BBS" >>/etc/rc.d/rc.local + echo "$MBSE_ROOT/etc/rc" >>/etc/rc.d/rc.local + chmod 755 /etc/rc.d/rc.local + echo " Added $MBSE_ROOT/etc/rc to /etc/rc.d/rc.local" + echo " /etc/rc.d/rc.local.mbse is a backup file." + echo "" + echo " You must manualy insert the lines '$MBSE_ROOT/etc/rc.shutdown'" + echo " into /etc/rc.d/rc.0 and /etc/rc.d/rc.K If you don't do it" + echo " everything will work also, but MBSE BBS isn't proper closed" + echo " if you halt or reboot your system." + fi + cp mbse.start $MBSE_ROOT/bin + cp mbse.stop $MBSE_ROOT/bin + cp rc $MBSE_ROOT/etc + cp rc.shutdown $MBSE_ROOT/etc + chown mbse.bbs $MBSE_ROOT/bin/mbse.start $MBSE_ROOT/bin/mbse.stop + chmod 755 $MBSE_ROOT/bin/mbse.start $MBSE_ROOT/bin/mbse.stop + chown root.root $MBSE_ROOT/etc/rc $MBSE_ROOT/etc/rc.shutdown + chmod 744 $MBSE_ROOT/etc/rc $MBSE_ROOT/etc/rc.shutdown + else + DISTINIT="/etc/rc.d/init.d/mbsed" + echo "Adding SystemV Slackware MBSE BBS start/stop scripts" + log "+" "Adding SystemV Slackware MBSE BBS start/stop scripts" + checkrcdir + +cat << EOF >$DISTINIT +#!/bin/sh +# +# Author: Michiel Broek , 23-May-2001 +# +# $DISTINIT for Slackware +# + +# Find the MBSE_ROOT from the /etc/passwd file. +MBSE_ROOT=\`cat /etc/passwd | grep mbse: | awk -F ':' '{ print \$6}'\` + +if [ "\$MBSE_ROOT" = "" ] +then + echo "MBSE BBS: No 'mbse' user in the password file." + exit 1 +fi + +if [ ! -d \$MBSE_ROOT ] +then + echo "MBSE BBS: Home directory '\$MBSE_ROOT' not found." + exit 1 +fi + +export MBSE_ROOT + +# See how we were called. +case "\$1" in + start) + echo -n "MBSE BBS starting:" + rm -f \$MBSE_ROOT/sema/* + rm -f \$MBSE_ROOT/var/*.LCK + $SU mbse -c '\$MBSE_ROOT/bin/mbtask' >/dev/null + echo -n " mbtask" + if [ -f \$MBSE_ROOT/etc/config.data ]; then + $SU mbse -c '\$MBSE_ROOT/bin/mbstat open -quiet' + echo " and opened the bbs." + fi + ;; + stop) + echo -n "MBSE BBS shutdown:" + if [ -f \$MBSE_ROOT/etc/config.data ]; then + echo -n " logoff users " + $SU mbse -c '\$MBSE_ROOT/bin/mbstat close wait -quiet' >/dev/null + echo -n "done," + fi + echo -n " stopping mbtask " + kill -15 \`pidof \$MBSE_ROOT/bin/mbtask\` + echo "done." + ;; + status) + echo -n "MBSE BBS status: " + if [ "\`/sbin/pidof mbtask\`" = "" ]; then + echo "mbtask is NOT running" + else + echo "mbtask Ok" + fi + ;; + restart) + echo "Restarting MBSE BBS: just kidding!" + ;; + *) + echo "Usage: mbsed {start|stop|restart|status}" + exit 1 +esac + +exit 0 +EOF + chmod 755 $DISTINIT + if [ -f $MBSE_ROOT/bin/mbse.start ]; then + echo "Removing old startup scripts" + rm $MBSE_ROOT/bin/mbse.start $MBSE_ROOT/bin/mbse.stop $MBSE_ROOT/etc/rc $MBSE_ROOT/etc/rc.shutdown + fi + echo "Making links for start/stop in runlevel 3" + if [ -f /etc/rc.d/rc3.d/K05mbsed ]; then + rm /etc/rc.d/rc3.d/K05mbsed + fi + ln -s ../init.d/mbsed /etc/rc.d/rc3.d/K05mbsed + if [ -f /etc/rc.d/rc3.d/S95mbsed ]; then + rm /etc/rc.d/rc3.d/S95mbsed + fi + ln -s ../init.d/mbsed /etc/rc.d/rc3.d/S95mbsed + echo "Making links for start/stop in runlevel 4" + if [ -f /etc/rc.d/rc4.d/K05mbsed ]; then + rm /etc/rc.d/rc4.d/K05mbsed + fi + ln -s ../init.d/mbsed /etc/rc.d/rc4.d/K05mbsed + if [ -f /etc/rc.d/rc4.d/S95mbsed ]; then + rm /etc/rc.d/rc4.d/S95mbsed + fi + ln -s ../init.d/mbsed /etc/rc.d/rc4.d/S95mbsed + echo "Slackware SystemV init configured" + log "+" "Slackware SystemV init configured" + fi +fi + + + +#-------------------------------------------------------------------------- +# +# Adding scripts for RedHat and Mandrake +# FIXME: some details unknown about Mandrake +# +if [ "$DISTNAME" = "RedHat" ] || [ "$DISTNAME" = "Mandrake" ]; then + + log "+" "Adding RedHat/Mandrake SystemV init scripts" + DISTINIT="/etc/rc.d/init.d/mbsed" + SU="su" + # + # From RedHat version 6.1 and up the behaviour of "su" has changed. + # For Mandrake we follow the same behaviour. + # + if [ -f /etc/redhat-release ]; then + RHR=`cat /etc/redhat-release | awk '{ print $5 }' | tr -d .` + if [ $RHR -gt 60 ]; then + echo "You are running RedHat v6.1 or newer" + SU="su -" + else + echo "You are running RedHat v6.0 or older" + fi + else + if [ -f /etc/mandrake-release ]; then + RHR=`cat /etc/mandrake-release | awk '{ print $4 }' | tr -d .` + if [ $RHR -gt 60 ]; then + echo "You are running Mandrake v6.1 or newer" + SU="su -" + else + echo "You are running Mandrake v6.0 or older" + fi + else + echo "You are in big trouble." + fi + fi + echo "Adding startup file $DISTINIT" + +cat << EOF >$DISTINIT +#!/bin/sh +# +# chkconfig: 345 99 05 +# description: Starts and stops MBSE BBS. +# +# For RedHat and Mandrake SYSV init style. +# 23-May-2001 M. Broek +# +# Source function library. +. /etc/rc.d/init.d/functions + +# Source networking configuration. +. /etc/sysconfig/network + +# Check that networking is up. +[ \${NETWORKING} = "no" ] && exit 1 + +# Find the MBSE_ROOT from the /etc/passwd file. +MBSE_ROOT=\`cat /etc/passwd | grep mbse: | awk -F ':' '{ print \$6}'\` + +if [ "\$MBSE_ROOT" = "" ] +then + echo "MBSE BBS: No 'mbse' user in the password file." + exit 1 +fi + +if [ ! -d \$MBSE_ROOT ] +then + echo "MBSE BBS: Home directory '\$MBSE_ROOT' not found." + exit 1 +fi + +export MBSE_ROOT + +# See how we were called. +case "\$1" in + start) + echo -n "Starting MBSE BBS: " + rm -f \$MBSE_ROOT/sema/* + rm -f \$MBSE_ROOT/var/*.LCK + $SU mbse -c '\$MBSE_ROOT/bin/mbtask' >/dev/null + echo -n "mbtask " + if [ -f \$MBSE_ROOT/etc/config.data ]; then + $SU mbse -c '\$MBSE_ROOT/bin/mbstat open -quiet' + echo "opened" + fi + touch /var/lock/subsys/mbsed + ;; + stop) + echo -n "Shutting down MBSE BBS: " + if [ -f \$MBSE_ROOT/etc/config.data ]; then + echo -n "logoff users " + $SU mbse -c '\$MBSE_ROOT/bin/mbstat close wait -quiet' >/dev/null + echo -n "done, " + fi + echo -n "stop mbtask: " + killproc mbtask -15 + rm -f /var/lock/subsys/mbsed + echo "done." + ;; + status) + status mbsed + ;; + restart) + echo "Restarting MBSE BBS: just kidding!" + ;; + *) + echo "Usage: mbsed {start|stop|restart|status}" + exit 1 +esac + +exit 0 +EOF + chmod 755 $DISTINIT + echo "With the runlevel editor, 'tksysv' if you are running X," + echo "or 'ntsysv' if you are running virtual consoles, you must" + echo "now add 'mbsed' start to the default runlevel, and 'mbsed'" + echo "stop to runlevels 0 and 6" +fi + + + +#-------------------------------------------------------------------------- +# +# Adding scripts for Debian +# +# +if [ "$DISTNAME" = "Debian" ]; then + echo "You are running Debian Linux $DISTVERS" + log "+" "Adding Debian SystemV init script" + DISTINIT="/etc/init.d/mbsebbs" + +cat << EOF >$DISTINIT +#!/bin/sh +# +# Note: this is not 100% Debian style, at least it works for now. +# 23-May-2001 Michiel Broek. +# +# description: Starts and stops the MBSE BBS. + +# For Debian SYSV init style. + +# Find the MBSE_ROOT from the /etc/passwd file. +MBSE_ROOT=\`cat /etc/passwd | grep mbse: | awk -F ':' '{ print \$6}'\` + +if [ "\$MBSE_ROOT" = "" ]; then + echo "MBSE BBS: No 'mbse' user in the password file." + exit 1 +fi + +if [ ! -d \$MBSE_ROOT ]; then + echo "MBSE BBS: Home directory '\$MBSE_ROOT' not found." + exit 1 +fi + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:\$MBSE_ROOT/bin +DAEMON=\$MBSE_ROOT/bin/mbtask +NAME=mbsebbs +DESC="MBSE BBS" + +export MBSE_ROOT + +# See how we were called. +case "\$1" in + start) + echo -n "Starting \$DESC: " + rm -f \$MBSE_ROOT/sema/* + rm -f \$MBSE_ROOT/var/*.LCK + su mbse -c '\$MBSE_ROOT/bin/mbtask' >/dev/null + echo -n "mbtask " + if [ -f \$MBSE_ROOT/etc/config.data ]; then + su mbse -c '\$MBSE_ROOT/bin/mbstat open -quiet' + echo -n "opened " + fi + echo "done." + ;; + stop) + echo -n "Stopping \$DESC: " + if [ -f \$MBSE_ROOT/etc/config.data ]; then + echo -n "logoff users " + su mbse -c '\$MBSE_ROOT/bin/mbstat close wait -quiet' >/dev/null + fi + start-stop-daemon --stop --signal 15 --user mbtask + echo "\$NAME done." + ;; + force-reload|restart) + echo "Restarting \$DESC: is not possible, done." + ;; + *) + N=/etc/init.d/\$NAME + echo "Usage: \$N {start|stop|restart|force-reload}" >&2 + exit 1 +esac + +exit 0 +EOF + chmod 755 $DISTINIT + update-rc.d mbsebbs defaults + echo "Debian install ready." + log "+" "Debian SystemV init script installed" +fi + +echo +echo "Please note, your MBSE BBS startup file is \"$DISTINIT\"" +echo diff --git a/script/maint b/script/maint new file mode 100644 index 00000000..aa75a31b --- /dev/null +++ b/script/maint @@ -0,0 +1,26 @@ +#!/bin/sh +# +# MBSE BBS Maintenance - Should be run from cron. +# +# 18-Mar-2000 MB. + +if [ -z "$MBSE_ROOT" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +# Don't do maintenance if running on UPS battery power. +# +if [ -f $MBSE_ROOT/sema/upsalarm ]; then + exit 0 +fi + +$MBSE_ROOT/bin/mbuser pack kill 180 50 -quiet +$MBSE_ROOT/bin/mbmsg kill pack link -quiet +$MBSE_ROOT/bin/mbfile kill check pack index -quiet +# $MBSE_ROOT/bin/mbfile kill check pack index web -quiet +$MBSE_ROOT/bin/mbtoberep >$MBSE_ROOT/doc/toberep.doc +$MBSE_ROOT/bin/mbaff announce filefind -quiet + +cd $MBSE_ROOT/tmp +$MBSE_ROOT/bin/mball list index -zip -quiet + diff --git a/script/mbse.start b/script/mbse.start new file mode 100644 index 00000000..0c2f01bd --- /dev/null +++ b/script/mbse.start @@ -0,0 +1,32 @@ +# +# ~/bin/mbse.start +# BBS Startup script, should be run as BBS owner. +# Note: This is only used on Slackware systems until 7.0.0 +# +# 27-May-2001 MB. + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + + +# If installed, start the BBS. +# +if [ -f $MBSE_ROOT/bin/mbtask ]; then + echo -n "Starting MBSE BBS: " + rm -f $MBSE_ROOT/sema/* + rm -f $MBSE_ROOT/var/*.LCK + rm -f $MBSE_ROOT/tmp/mb* + cd $MBSE_ROOT + $MBSE_ROOT/bin/mbtask >/dev/null + echo -n "mbtask " + if [ -f $MBSE_ROOT/etc/config.data ]; then + $MBSE_ROOT/bin/mbstat open -quiet + echo -n "opened " + fi + echo "done" +else + echo "mbtask not available!" + exit 1 +fi + diff --git a/script/mbse.stop b/script/mbse.stop new file mode 100644 index 00000000..67f03a82 --- /dev/null +++ b/script/mbse.stop @@ -0,0 +1,38 @@ +# +# ~/bin/mbse.start +# BBS Shutdown script, should be run as BBS owner. +# Note: this is only used on Slackware systems. +# +# 27-May-2001 MB. + +export PATH="/sbin:/usr/sbin:/bin:/usr/bin:$MBSE_ROOT/bin:" + + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + + +if [ -f $MBSE_ROOT/bin/mbtask ]; then + echo -n "Shutdown MBSE BBS: " + if [ -f $MBSE_ROOT/etc/config.data ]; then + echo -n "closing the bbs " + cd $MBSE_ROOT + $MBSE_ROOT/bin/mbstat close wait -quiet + echo -n "done, " + fi + # Now kill the daemons + echo -n "kill " + base=`basename mbtask` + pid=`pidof $base` + echo -n "mbtask " + if ps h $pid >/dev/null 2>&1; then + kill $pid + RC=$? + [ $RC -eq 0 ] && echo -n "ok " || echo -n "failed " + fi + echo "" +else + echo "mbtask not available!" +fi +# diff --git a/script/midnight b/script/midnight new file mode 100644 index 00000000..494c7632 --- /dev/null +++ b/script/midnight @@ -0,0 +1,28 @@ +#!/bin/sh +# +# MBSE BBS Midnight - Should be run from cron at 00:00 +# +# 26-Aug-1999 MB. + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +# While the system is on UPS battery power, don't start maintenance +# +while [ -f $MBSE_ROOT/sema/upsalarm ]; do + sleep 60 +done + +# Rollover statistic counters. +# +$MBSE_ROOT/bin/mbfido roll -quiet + +# Log "What's on Hold" +# +$MBSE_ROOT/bin/mbout stat -quiet + +# Export messages "missed" by the fast mailscan +# +$MBSE_ROOT/bin/mbfido scan -full -quiet + diff --git a/script/monthly b/script/monthly new file mode 100644 index 00000000..7eeaddcc --- /dev/null +++ b/script/monthly @@ -0,0 +1,15 @@ +#!/bin/sh +# +# MBSE BBS Monthly - Should be run at the first of the month at 00:10 +# +# 26-Aug-1999 MB. + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +# While the system is on UPS battery power, don't start maintenance +# +while [ -f $MBSE_ROOT/sema/upsalarm ]; do + sleep 60 +done diff --git a/script/rc b/script/rc new file mode 100644 index 00000000..22bf17af --- /dev/null +++ b/script/rc @@ -0,0 +1,15 @@ +#!/bin/sh +# +# $MBSE_ROOT/etc/rc: BBS Startup script for Slackware. +# +# 08-Jul-1999 + +# Remove stale tempfiles from cron. +rm -f /tmp/cron.mbse.* + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +su - mbse -c $MBSE_ROOT/bin/mbse.start + diff --git a/script/rc.shutdown b/script/rc.shutdown new file mode 100644 index 00000000..77dbe0c7 --- /dev/null +++ b/script/rc.shutdown @@ -0,0 +1,14 @@ +#!/bin/sh +# +# /mnt/prod/mbse/etc/rc.shutdown: BBS Shutdown script for Slackware +# +# 08-Jul-1998 + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + + +su mbse -c $MBSE_ROOT/bin/mbse.stop +sleep 2 +# diff --git a/script/weekly b/script/weekly new file mode 100644 index 00000000..41004a96 --- /dev/null +++ b/script/weekly @@ -0,0 +1,18 @@ +#!/bin/sh +# +# MBSE BBS Weekly - Should be run every week at sunday from cron at 00:05 +# +# 26-Aug-1999 MB. + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +# While the system is on UPS battery power, don't start maintenance +# +while [ -f $MBSE_ROOT/sema/upsalarm ]; do + sleep 60 +done + +$MBSE_ROOT/bin/mbfido notify -quiet + diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 00000000..9788f702 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp