commit 40420d900a1ca0fba4042883b25c39dcadefc596
Author: Ken Bowley
+
+
+Before you compile and install MBSE BBS you must first setup the basic
+environment. If you don't do this, things will fail.
+
+
+
+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:
+
+
+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:
+
+
+
+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.
+
+
+
+Login as user mbse. While in the home directory unpack the distribution
+archives:
+
+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.
+
+
+
+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
+
+
+Now the basic environment is finished, the next thing is to install
+the scripts, examples and configuration.
+
+
+Back to Index
+
+
+
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+Since SuSE 7.1 the setup scripts are working and tested. Older distro's
+might work.
+
+
+
+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.
+
+
+
+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.
+
+
+ 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 @@
+
+
+
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+ Go Back
+
+
+
+
+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.
+
+
+
+
+
+
+
+
+
+
+
+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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+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.
+
+The next step is the setup of the bbs.
+
+
+Back to Index
+
+
+
+
+ WARNING: THIS IS DIFFERENT FROM VERSION 0.33.14 AND UP
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+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
+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.
+
+
+
+See Postfix (email) configuration
+
+
+ Go Back
+
+
+
+
+There are only five official distribution sites for the mbse bbs package. They are:
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+ Go Back
+
+
+
+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.
+
+
+ Go Back
+
+
+
+There are always more bugs, but these are known....
+
+
+
+
+This is an overview of the licenses that are valid for the use of MBSE BBS or
+parts of it.
+
+
+
+
+
+
+
+
+
+
+
+
+ Menus sections:
+Global menus
+File areas
+Message areas
+User settings
+Onliners
+BBS lists
+ANSI Control Codes
+
+
+
+
+
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 27-May-2001
+MBSE BBS Basic Installation
+
+Introduction.
+Step 1: planning the filesystems.
+
+
+/opt/mbse binaries, config and user home directories.
+/var/spool/mbse In/outbound, queues, download directories.
+
+Step 2: Running the installation script.
+
+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:
+
+
+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:
+
+
+Step 3: Check the basic installation
+Step 4: Install the basic packages.
+
+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.
+Step 5: (RedHat) startup problems.
+/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.
+
+
Last update 06-Jun-2001
+Linux Distributions.
+Which distribution
+Slackware
+Redhat and Mandrake
+SuSe
+Debian
+Famous last words...
+
+
+
+
+
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 @@
+
+
+Last update 06-Jun-2001
+Running a BBS under Linux.
+Introduction
+Waiting for a call .....
+A Human is calling.
+A PPP call is detected.
+A mailer call is detected.
+There is mail in the inbound
+It's time to poll a node
+It's Zone Mail Hour, so now what
+Daily maintenane
+How about system load
+
+ Transparent Gateways to and from FidoNet
+
+ 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 @@
+
+
+
+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
+
+
+
+
+
+
+
+ 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 @@
+
+
+
+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:
+
+
+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" ---
+
+
+ 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 @@
+
+
+
+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)
+
+
+
+ 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 @@
+
+
+
+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.
+
+
+ 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 @@
+
+
+
+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:
+
+ 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 @@
+
+
+
+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
+
+ 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 @@
+
+
+
+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
+
+ 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 @@
+
+
+
+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=
+
+ 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 @@
+
+
+
+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
+
+
+
+
+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:
+
+
+ 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 @@
+
+
+
+ | 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
+
+ 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 @@
+
+
+
+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
+
+ 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 @@
+
+
+
+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
+
+ 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 @@
+
+
+
+ | 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-
+
+
+ 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 @@
+
+
+
+ | 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
+
+
+ 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 @@
+
+
+
+ | 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
+
+
+
+ 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 @@
+
+
+
+ | 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.
+
+
+
+ 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 @@
+
+
+
+ | 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 -
+
+
+ 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 @@
+
+
+
+**********************************************************************
+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:
+
+ 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 @@
+
+
+
+**********************************************************************
+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.
+
+
+**********************************************************************
+
+
+ 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 @@
+
+
+
+**********************************************************************
+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.
+
+
+**********************************************************************
+
+
+ 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 @@
+
+
+
+**********************************************************************
+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.
+
+
+**********************************************************************
+
+
+ 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 @@
+
+
+
+**********************************************************************
+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...
+
+
+**********************************************************************
+
+
+ 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 @@
+
+
+
+**********************************************************************
+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
+
+ 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 @@
+
+
+
+**********************************************************************
+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:
+
+ 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 @@
+
+
+
+**********************************************************************
+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.
+
+
+**********************************************************************
+
+
+ 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 @@
+
+
+
+**********************************************************************
+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.
+
+
+**********************************************************************
+
+
+ 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 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.
+
+**********************************************************************
+
+ 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 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.
+
+ 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 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.
+
+
+**********************************************************************
+
+
+ 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 @@
+
+
+
+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 (
+
+ 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 @@
+
+
+
+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-
+
+
+ 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 @@
+
+
+
+ | 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.
+
+
+
+ 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 @@
+
+
+
+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:
+
+
+
+ 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 @@
+
+
+
+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
+
+ 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 @@
+
+
+
+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
+
+ 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 @@
+
+
+
+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.
+
+
+
+ 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 @@
+
+
+
+**********************************************************************
+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.
+
+**********************************************************************
+
+
+ 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 @@
+
+
+
+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
+
+
+ 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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+Last update 08-Jun-2001
+Fidonet Technical Standards
+
+Introduction
+
+FSC Documents
+
+
+
+FSP Documents
+
+
+
+
+FTA Documents
+
+
+
+FTS Documents
+
+
+
+
+
+Back to Index
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+Last update 10-Apr-2001
+MBSE BBS - Internet Gateway - INN.
+SETUP INND
+
+
+
+
+## $Revision$
+## inn.conf -- inn configuration data
+## Format:
+##
+
+
+
+## $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,!
+
+
+## $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:::*
+
+
+
+Go back
+Go to main
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+MBSE BBS System Guide v0.33.17
+
+
+Last update 07-Jul-2001
Introduction
+
+
+Release Notes
+
+
+
+MBSE BBS Reference Manual
+
+
+
+
+
+
+
+ Other Notes
+
+
+
+
+Back
+Top
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+Last update 03-Jul-2001
+Installing the BBS.
+
+
+Installing the 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.
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+Last update 26-Apr-2001
+MBSE BBS - Internet Gateway.
+Introduction.
+Setup a newsgate node with inn.
+Setup a newsgate with rnews.
+Setup a newsgate via UUCP.
+/var/spool/uucp/xs4all
and the UUCP node to
+xs4all
. Your own nodename will be your system's hostname without
+the domain part.
+Setup a email gate.
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+Last update 28-Jan-2001
+Introduction to MBSE BBS.
+Distribution.
+
+
+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.
+Is it Y2K ready?
+Future plans.
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+Last update 06-Jun-2001
+Starting and Stopping the BBS.
+
+
Last update 28-Jan-2001
+MBSE BBS - Known bugs.
+
+
+
+ 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
+ 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.
+
+
+
+ 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 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.
+
+
+ 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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+Last update 29-Jan-2001
+Licenses.
+
+Introduction
+
+Michiel Broek.
+License Documents.
+
+
+
+Back to Index
+
+ ---------------------------------------------------------------------
+ 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.
+
+
+ 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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+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);
+
+
+
+
+
+
+Main Index
+
+Menus Index
+
+
Last update 02-Feb-2001
+MBSE BBS Menu System
+
+
+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. +
+ +
+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. +
+ +
+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. +
+ +
+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. +
+ +
+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. +
+ + +
+ +
+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 + + + 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 @@ + +
+ + + + + + +++ + + 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 @@ + + + + + + + + +Last update 02-Feb-2001
+
+ +
MBSE BBS Global Menus
+
+ ++ +
+ +- 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.
++ +
- 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.
++ +
- Return from Gosub: This will go back one + gosub level. If you are already at the top level nothing happens.
+ Optional data: None.
++ +
- 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.
++ +
- 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!
++ +
- 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. +
+ +
- 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.
++ +
- Show product information: This will show + copyright information about MBSE BBS.
+ Optional data: None.
++ +
- Display todays callers: This will display a + list of todays callers to the BBS.
+ Optional data: "/H" Show handles instead of real names.
++ +
- Display userlist: Display all users in the + users database except those that are hidden.
+ Optional data: "/H" Show handles instead of real names.
++ +
- Time statistics: Display the users time + statistics.
+ Optional data: None.
++ +
- 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. ++ +
- Terminate call: Terminale this call and + hangup.
+ Optional data: None. ++ +
- Make a log entry: This will write a line in + the logfile.
+ Optional data: The information you want in the logfile.
++ +
- 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.
++ +
- 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.
++ +
- 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.
++ +
- Send online message: Send an online message + to a user on another line. + Optional data: "/H" Use handles instead of real names.
++ +
- 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.
++ +
- 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.
++ +
- Expert mode .a?? Not of any use anymore. + This one will be removed.
+ Optional data: The name of the file without extension + to display.
++ +
- Nextuser door: This runs the message to next + user door.
+ Optional data: None.
++ +
- Timebank door: This runs the time bank door.
+ Optional data: None.
++ +
- Safe cracker door: This runs the Safe Cracker + door.
+ Optional data: None.
+
+ + Main Index + + 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 @@ + + + + + + + + +Last update 02-Feb-2001
+
+ +
MBSE BBS File Area Menus
+
+ ++ +
+ +- 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.
++ +
- 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.
++ +
- View File: Not yet implemented.
+ Optional data: None.
++ +
- 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.
++ +
- 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.
++ +
- 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.
++ +
- 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.
++ +
- 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.
++ +
- 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.
++ +
- Edit Taglist: This option is for the user to + edit the list of files he has tagged for later download.
+ Optional data: None.
++ +
- View file in homedir: Not yet implemented.
+ Optional data: None.
++ +
- Download Direct: Download a file direct.
+ Optional data: The full path and filename to the file to + download.
++ +
- 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.
++ +
- List Homedir: This option will list the files + in the users home directory.
+ Optional data: None.
++ +
- Delete in Homedir: This option will let the + user delete one or more files from his home directory.
+ Optional data: None.
++ +
- Unpack file in Homedir: Not yet implemented.
+ Optional data: None.
++ +
- Pack files in Homedir: Not yet implemented.
+ Optional data: None.
++ +
- Download Homedir: This option will let the + user download from his home directory.
+ Optional data: None.
++ +
- Upload Homedir: This option will let the user + upload files to his home directory.
+ Optional data: None.
+
+ +Main Index + +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 @@ + + + + + + + + +Last update 02-Feb-2001
+
+ +
MBSE BBS Message Area Menus
+
+ ++ +
+ +- 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.
++ +
- Post a Message: This option lets the user + post a new message.
+ Optional data: None.
++ +
- 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.
++ +
- Check for Mail: Check for new arrived mail.
+ Optional data: None.
++ +
- Quickscan Messages: Make a quick overview + list of all messages in that area.
+ Optional data: None.
++ +
- 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.
++ +
- Mail Status: This gives a complete overview + of all available mail at the bbs.
+ Optional data: None.
++ +
- OLR: Tag Area: This option lets + the user tag one or more areas to be included in his offline mail packet.
+ Optional data: None.
++ +
- 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.
++ +
- OLR: View Tags: This option lets + the user view which areas will be included in his offline mail packet.
+ Optional data: None.
++ +
- OLR: Restrict Date: Not yet + implemented.
+ Optional data: None.
++ +
- 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.
++ +
- OLR: Download BlueWave: Download mail in + BlueWave version 2 format.
+ Optional data: None.
++ +
- OLR: Download QWK: Download mail in QWK + format.
+ Optional data: None.
++ +
- OLR: Download ASCII: Download mail in flat + ASCII format. Not yet implemented.
+ Optional data: None.
++ +
- Read Email Read users private email.
+ Optional data: None.
++ +
- Write Email Post an email message.
+ Optional data: None.
++ +
- Trash Email Put email in the trashcan. + Not Yet implemented.
+ Optional data: None.
++ +
- 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.
++ +
- Quickscan Email Make a quick overview + list of all messages in the selected e-mail area.
+ Optional data: None.
++
+ +Main Index + +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 @@ + + + + + + + + +Last update 02-Feb-2001
+
+ +
MBSE BBS User Settings Menus
+
+ ++ +
+ +- Change Transfer Protocol: Let the user + select a new file transfer protocol.
+ Optional data: None.
++ +
- Change Password: Let the user change + his FidoNet password.
+ Optional data: None.
++ +
- Change Location: Let the user change + his location.
+ Optional data: None.
++ +
- Change Graphics: Let the user toggle + graphics mode on or off.
+ Optional data: None.
++ +
- Change Voicephone: Let the user change + his voice phonenumber.
+ Optional data: None.
++ +
- Change Dataphone: Let the user change + his data phonenumber.
+ Optional data: None.
++ +
- Change Expertmode: This command will be + removed.
+ Optional data: None.
++ +
- Change Scrennlength: This command will + let the user set a new screenlength, the default is 24.
+ Optional data: None.
++ +
- 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.
++ +
- Change Language: Let the user select a new + default language.
+ Optional data: None.
++ +
- Change Hotkeys: Let the user toggle the + use of Hotkeys on or off..
+ Optional data: None.
++ +
- Change Handle: Let the user select a new + handle (nickname).
+ Optional data: None.
++ +
- Change Don't Disturb: Let the user toggle + the "do not disturb" flag.
+ Optional data: None.
++ +
+ +Main Index + +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 @@ + + + + + + + + +Last update 02-Feb-2001
+
+ +
MBSE BBS Oneliner Menus
+
+ ++ +
+ +- Oneliner Add: Let the user add a new + oneliner.
+ Optional data: None.
++ +
- Oneliner List: Let the user list all the + available oneliners.
+ Optional data: None.
++ +
- Oneliner Show: Let the user show a + specific oneliner.
+ Optional data: None.
++ +
- 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.
++ +
- 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.
++ +
+ +Main Index + +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 @@ + + + + + + + + +Last update 02-Feb-2001
+
+ +
MBSE BBS BBS List Menus
+
+ ++ +
+ +- Add a BBS: Let the user add a BBS to the + BBS advertising database.
+ Optional data: None.
++ +
- List BBS'es: Show a list of BBS'es in the + BBS database.
+ Optional data: None.
++ +
- Show BBS: Show a specific BBS.
+ Optional data: None.
++ +
- 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.
++ +
- Search BBS: Search for a specific BBS.
+ Optional data: None.
++ +
+ +Main Index + +Menus Index +
++ + + 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 @@ + + + + + + + + +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. ++ + 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 @@ + + +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 +++ + Go Back +
+ 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+ + 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 @@ + + ++ - 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. +
+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+ + 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 @@ + + + + + + + + +.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. + +
++ + + 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 @@ + + + + + + + + +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. +
+ + Go Back +
++ + + 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 @@ + + +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
++
+ +- Implementation and Usage of Filefind Utilities, R.Williamson +
- Integration of IP-Nodes in the nodelist, L.Behet +
- FILE_ID.DIZ Information, R.Moller +
- How to setup an FTP server with MBSE BBS, M.Broek +
- JAM Message Base Proposal, J.Homrighausen +
- Binkley style mailer outbound for MBSE BBS, M.Broek +
- Semafore files for MBSE BBS, M.Broek +
- System load and usleep() code, M.Broek +
- BBS doors dropfiles, M. Broek +
+ +Back to Index +
+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. ++ + 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 @@ + + +
+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; //+ + 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 @@ + + + + + + + + +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.LZH NEWS. + 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 +
++ + + 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 @@ + + + + + + + + +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. + ++ + +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 @@ + + +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. ++ + Go Back +
+ 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. + ++ + 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 @@ + + + + + + + + +
++ + + 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 @@ + + + + + + + + +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:
++
+In short the steps to process the nodediff's is as follows: +- /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. +
- /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. +
- /var/spool/mbse/nodelist, this is the systems nodelist +directory defined in mbsetup, menu 1.3.4 +
+
+Next I will describe these steps in detail. +- Receive the nodediff and store it for download. +
- Apply the diff to the latest nodelist. +
- Hatch the new compressed nodelist. +
- Store the new nodelist for download. +
- Unpack the new nodelist in the nodelist compiler directory. +
- Set the compile semafore. +
- Compile the nodelists. +
+ +
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. +
+ +
+ + Go Back +
++ + + 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 @@ + + + + + + + + +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. + ++ + +Go back + Go to main +
++ + + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +Last update 06-Jun-2001
+
+ +
MBSE BBS Programs.
+ + ++
+ + + Back to Main index +- import, Import databases +
- mbaff, Announce newfiles and filefind +
- mball, Allfiles and newfiles list creator +
- mbchat, Sysop to user chat utility +
- mbcico, The Fidonet mailer ala ifcico +
- mbdiff, Nodelist difference processor +
- mbfbgen, FileBase Generator utility +
- mbfido, Fidonet mail and files procesor +
- mbfile, Files database maintenance program +
- mbindex, Nodelist index compiler +
- mblang, Language datafile compiler +
- mbmon, The monitor program +
- mbmsg, The messagebase utility program +
- mbout, The mailer outbound program +
- mbpasswd, The passwd wrapper +
- mbsebbs, The bbs program +
- mbseq, Sequence number creator +
- mbsetup, The setup program +
- mbstat, The bbs status change program +
- mbtoberep, The toberep.data lister +
- mbuser, The userbase maintenance program +
- mbuseradd, The adduser wrapper +
++ + + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +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. ++
+- Time retry code, this is the last call attempt time. This is an unsigned + long representing the number of seconds since the epoch. +
- 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. +
- 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. +++ + Back to index + 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 @@ + + + + + + + + +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 +
+ + Back to index + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +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. ++ + Back to index + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +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. +
++ + + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +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. ++ + Back to index + 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 @@ + + + + + + + + +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 +++ + Back to index + 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 @@ + + + + + + + + +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. ++ + + Back to index + 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 @@ + + + + + + + + +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;
++
+welcome. This screen can contain information about the session +the user has, his download limits, time left etc. +- filename.ans in the users favourite language directory. +
- filename.ans in the default language directory. +
- filename.asc in the users favourite language directory. +
- filename.asc in the default language directory. +
- If nothing is found, nothing is displayed. +
+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. +
+ + + Back to index + 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 @@ + + + + + + + + +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? +
+ + + Back to index + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +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. ++ + + Back to index + 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 @@ + + + + + + + + +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: +
+
+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: +- 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.
+- The UPS semafore upsalarm will be checked. This means that the system is running on + battery power and no new jobs are started. +
- 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.
+- The status of the bbs will be checked, is it open or closed. If it is closed, no + jobs will be started. +
- 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. +
- 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! +
+
+
++ +Semafore +Speed +Tasktype +Depends on +Job to run ++ mailout Fast mbfido Max. 1 mbfido task mbfido scan web -quiet + mailin Fast mbfido Max. 1 mbfido task mbfido tic toss web -quiet + newnews Fast mbfido Max. 1 mbfido task mbfido news web -quiet + mbindex Fast mbindex No other tasks mbindex -quiet and if excist: goldnode + msglink Fast mbfido No other tasks mbmsg link -quiet + reqindex Fast mbfile No other tasks mbfile index -quiet + scanout Slow call Only 1 call task mbcico -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. +
+ + Back to index + 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 @@ + + + + + + + + +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. +
+ + Back to index + 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 @@ + + + + + + + + +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. ++ + Back to index + 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 @@ + + + + + + + + +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 +++ + Back to index + Back to Main index +
++ + + 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 @@ + + + + + + + + +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:
+++ + Go Back ++ +=============================+ + | 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 | + +==============+ +
+
++ + + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +Last update 29-Jan-2001
+
+ +
MBSE BBS Setup - Edit BBS Setup.
++ +
Edit BBS Setup.
++The BBS setup is split in the following sections: +
+ +
+ + Back to index + 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 @@ + + + + + + + + +Last update 29-Jan-2001
+
+ +
MBSE BBS Setup - BBS Setup - BBS List Data.
++This is not available yet. +
+ + Back to BBS index + Back to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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: +
+
+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. +- Delete connection +
- Add new connection +
- Replace connection +
- Change connection status +
- Change days old +
- Change max. messages +
- Change security +
- Change aka to use +
- Change origin line +
- Change netmail reply +
- Delete message area +
+ + +
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 to Mail Setup + Back to index + 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 @@ + + + + + + + + +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 to Mail Setup + Back to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to File Echo's Setup + Back to index + 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 @@ + + + + + + + + +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 to index +
+ 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 @@ + + + + + + + + +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: +
+
+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. +- Delete connection +
- Add new connection +
- Replace connection +
- Change connection status +
- Change aka to use +
- Delete TIC area +
+ + + Back to File Echo's Setup + Back to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to BBS index + Back to index + 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 @@ + + + + + + + + +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+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. ++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. + + +
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: +
+
+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. + +- 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. +
+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 to index +
+ 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 @@ + + + + + + + + +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 to File Echo's Setup + Back to index + Back to main 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 @@ + + + + + + + + +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
++
+
+ +Back to index +- Edit Global configuration +
- Edit Fido networks +
- Edit Archiver programs +
- Edit Virus scanners +
- Edit Modem types +
- Edit TTY lines info +
- Edit Fidonet nodes +
- Edit BBS setup + +
- Edit Mail setup + +
- Edit File echo's setup + +
- Edit Newfiles groups +
- Edit Newfiles reports +
- Edit Filefind setup +
- Edit Files database +
- Edit BBS users +
- Edit Services +
- Edit Domains +
- Edit Task Manager +
- Show software information +
- Create site documents +
++ + + 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 @@ + + + + + + + + +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 to BBS index + Back to index + 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 @@ + + + + + + + + +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 to File Echo's Setup + Back to index + 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 @@ + + + + + + + + +Last update 29-Jan-2001
+
+ +
MBSE BBS Setup - Mail Setup.
++ +
Edit Mail Setup.
++The Mail Setup is split in the following sections: +
+ +
+ + Back to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to BBS index + Back to index + 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 @@ + + + + + + + + +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 to BBS index + Back to index + 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 @@ + + + + + + + + +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 to BBS index + Back to index + 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 @@ + + + + + + + + +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 to BBS index + Back to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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: +
+ +
+ + Back to index + 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 @@ + + + + + + + + +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 to BBS index + Back to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to index + 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 @@ + + + + + + + + +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 to index + Back to main index +
+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: + +
+
+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. +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. +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. +
+ + + 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 "FBI filename(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,"[1;37m"); + old+=t; + strncat(str,old,strlen(Word)); + strcat(str,"[0;37m"); + 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; i b[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; i num_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; i pmax=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, "\n"); + fprintf(fw, " Message group statistics Received last Sent last \n"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fg); + while ((fread(&mgroup, mgrouphdr.recsize, 1, fg)) == 1) { + if (mgroup.Active) { + fprintf(fw, " Group Comment Aka Last date week month week month \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, " %s %s %s %s %ld %ld %ld %ld \n"); + fprintf(fw, " Message areas statistics Received last Posts last \n"); + fread(&msgshdr, sizeof(msgshdr), 1, fg); + Area = 0; + while ((fread(&msgs, msgshdr.recsize, 1, fg)) == 1) { + Area++; + if (msgs.Active) { + fprintf(fw, " Nr Area Tag Group Last date week month week month \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, " %d %s %s %s %s %ld %ld %ld %ld \n"); + fprintf(fw, " TIC file group statistics Last week Last month \n"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fg); + while ((fread(&fgroup, fgrouphdr.recsize, 1, fg)) == 1) { + if (fgroup.Active) { + fprintf(fw, " Group Comment Aka Last date files KBytes files KBytes \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, " %s %s %s %s %ld %ld %ld %ld \n"); + fprintf(fw, " TIC file areas statistics Last week Last month \n"); + fread(&tichdr, sizeof(tichdr), 1, fg); + while ((fread(&tic, tichdr.recsize, 1, fg)) == 1) { + if (tic.Active) { + fprintf(fw, " Area Tag Group Last date files KBytes files KBytes \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, " %s %s %s %s %ld %ld %ld %ld \n"); + fprintf(fw, " Nodes statistics \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, " Node Sysop Status Start Date Last date Credit Debet \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, " %s %s %s %s %s %s %ld %ld \n", adate(hist.online)); + fprintf(fw, " Mailer history since %s \n"); + + for (i = Total; i > 0; i--) { + fseek(fg, i * sizeof(hist), SEEK_SET); + fread(&hist, sizeof(hist), 1, fg); + fprintf(fw, " Aka System Location Time Elapsed Sent Received Mode ", + 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, " %s %s %s %s %s %lu %lu %s \n"); + fprintf(fw, " BBS system info \n", SYSINFO.SystemCalls); + fprintf(fw, " Total calls %lu \n", SYSINFO.Pots); + fprintf(fw, " Pots calls %lu \n", SYSINFO.ISDN); + fprintf(fw, " ISDN calls %lu \n", SYSINFO.Network); + fprintf(fw, " Network calls %lu \n", SYSINFO.Local); + fprintf(fw, " Local calls %lu \n", SYSINFO.ADSL); + fprintf(fw, " ADSL calls %lu \n", adate(SYSINFO.StartDate)); + fprintf(fw, " Start date %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] Last caller %s \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 && Num 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, "\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("[2J\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("[2J\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("[2J\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("[2J\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("[2J\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("[2J\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 \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 \n", + CFG.www_url, CFG.www_icon_home, CFG.www_name_home, CFG.www_name_home); + fprintf(fa, "%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\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. Filename Date Size Downloads Description \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, " Area Description Files Total size Last added \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, " %d ", 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); + fprintf(fa, "", + CFG.www_url, CFG.www_link2ftp, + area.Path+strlen(CFG.ftp_base), file.Name, file.Name); + fprintf(fa, "", + CFG.www_url, CFG.www_link2ftp, + area.Path+strlen(CFG.ftp_base), file.Name, file.Name); + } + fprintf(fa, " %s", StrDateDMY(file.FileDate)); + fprintf(fa, " %s", file.Size / 1024); + fprintf(fa, " %lu Kb.", + file.TimesDL + file.TimesFTP + file.TimesReq); + fprintf(fa, " %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, "\n"); + else + fprintf(fm, " %d %s ", + AreaNr, CFG.www_url, CFG.www_link2ftp, area.Path+strlen(CFG.ftp_base), area.Name); + fprintf(fm, "%d ", aTotal); + if (aSize > 1048576) + fprintf(fm, "%ld Mb. ", aSize / 1048576); + else + fprintf(fm, "%ld Kb. ", aSize / 1024); + if (last == 0L) + fprintf(fm, "%s \n", StrDateDMY(last)); + } + } + } /* End of While Loop Checking for Areas Done */ + + fprintf(fm, "\n", + iTotal, iSize / 1048576); + fprintf(fm, " Total %d %ld Mb. \n"); + fprintf(fm, "%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