1519 lines
49 KiB
Plaintext
1519 lines
49 KiB
Plaintext
Fidonet Electronic Mail Protocol 20 Oct 84 Page 1
|
|
|
|
|
|
|
|
Tom Jennings
|
|
2269 Market Street #118
|
|
San Francisco CA 94114
|
|
|
|
FidoNet Node #1
|
|
415/864-1418
|
|
|
|
INTENT
|
|
|
|
This document is an attempt to describe and define
|
|
the packet protocol used to support electronic mail under
|
|
the Fido/FidoNet system.
|
|
|
|
It will not describe or define Fido/Fidonet software
|
|
operation, nor even describe what the system does; for that,
|
|
I refer you to the following Fido manuals:
|
|
|
|
Fido's Installation Manual (INSTALL.DOC)
|
|
Fido's Operating Manual (FIDO.DOC)
|
|
Fido's FidoNet Manual (FIDONET.DOC)
|
|
|
|
Only the lower layers of the protocol will be
|
|
discussed here; routing, forwarding, dialing algorithms and
|
|
such will not be covered. These are mentioned, albeit
|
|
briefly, in Fido's FidoNet Manual.
|
|
|
|
BACKGROUND
|
|
|
|
FidoNet was designed to be more or less portable
|
|
within the existing "public domain" software base, ie. any
|
|
system that can support binary transfers via XMODEM or it's
|
|
variants is in theory capable of supporting FidoNet. This
|
|
does not mean to imply that the current Fido/FidoNet
|
|
software will be/can be transported to machines not
|
|
currently supported; it means that no designed in
|
|
limitations were intended.
|
|
|
|
This document merely covers the algorithms used, and
|
|
the problems encountered, in the automatic transfer of
|
|
packets and files used by the MSDOS Fido/FidoNet system.
|
|
|
|
DESCRIPTION
|
|
|
|
FidoNet is a true electronic mail system supported
|
|
by the Fido Bulletin Board System software, under MSDOS
|
|
version 2. It's function is to transfer textual messages,
|
|
and binary files, between physically seperate computers on
|
|
an automatic, unattended basis.
|
|
|
|
BASIC ASSUMPTIONS
|
|
|
|
The basic unit of data in FidoNet, like most MSDOS
|
|
and CPM software, is the byte, which here means 8 bits. All
|
|
data transfers assume the availability of an 8 bit byte
|
|
capable channel; 7 bit ASCII is not adequate. Parity, if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 2
|
|
|
|
used, must be transparent to the software.
|
|
|
|
FidoNet is transaction oriented; a channel
|
|
(connection) is made, data transferred, the channel closed.
|
|
In all existing cases, this means a typical modem/phone line
|
|
connection; dial, connect, transfer, disconnect, though
|
|
anything that might be considered a "channel" will work.
|
|
|
|
The most basic design criteria for FidoNet is
|
|
extremely short channel connect times, since the usual
|
|
channel is a telephone line, where costs are accumulated on
|
|
a per minute basis. Lowest possible costs is the single most
|
|
important issue here. For this reason, all packets are
|
|
preassembled; no processing at all is done at packet
|
|
transfer time.
|
|
|
|
Due to the lack of real time operating systems,
|
|
FidoNet runs on an alternating basis with Fido. While Fido
|
|
is running, users enter messages, attach files and the like,
|
|
to be later processed by FidoNet. When FidoNet gains control
|
|
(at a predetermined time of day) it packetizes outgoing
|
|
messages, then makes attempts to send these packets, and may
|
|
receive packets from other nodes, all asynchronouously. When
|
|
FidoNet's time slot is over, it deletes any un-sent packets,
|
|
unpacks any packets that were received, and then passes
|
|
control back to Fido. Note that incoming packets are not
|
|
examined in any way until the FidoNet time slot is over.
|
|
|
|
A basic concept in FidoNet is the "node". A node is
|
|
any computer capable of sending or receiving FidoNet mail
|
|
packets. All discussions of packet transfers here will
|
|
assume point to point transfers.
|
|
|
|
As background information, it should be noted that
|
|
routing, forwarding, cost accounting, etc is done at a much
|
|
higher layer; routing, for instance is done even before
|
|
packets are created, and determines the destination node. It
|
|
has no effect on packet transfer.
|
|
|
|
SOFTWARE ASSUMPTIONS
|
|
|
|
Fido/FidoNet is written in 'C' (Lattice flavor) and
|
|
makes use (of course) of C style structures and strings.
|
|
Luckily, these are quite simple. Here are the following
|
|
basic components used throughout FidoNet:
|
|
|
|
CHARACTERS:
|
|
An 8 bit byte. The usual micro type "character"; all
|
|
8 bits may be signifigant. Usually 128ASCII.
|
|
|
|
STRING:
|
|
A one dimension array of 8 bit characters,
|
|
terminated by a null. (hex 0) Some are of a fixed length; in
|
|
this case, signifigant text is left justified, followed by
|
|
the null, and the rest of the string is indeterminate. In
|
|
practice, FidoNet strings vary from very few characters up
|
|
to 4000 characters or so.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 3
|
|
|
|
|
|
INTEGERS:
|
|
All integer variables are 16 bits ('C' shorts)
|
|
unsigned, and are in Intel (big endian) format; least byte
|
|
first in the byte stream.
|
|
|
|
LONGS:
|
|
A long integer is 32 bits, in Intel format.
|
|
|
|
WHAT A PACKET IS
|
|
|
|
A packet is a file that consists of a header, a
|
|
variable amount of variable size messages, and a trailer.
|
|
Each message within a packet has a header, and a single
|
|
string of plain text.
|
|
|
|
+---------------+
|
|
| |
|
|
| | Header
|
|
| |
|
|
+---------------+
|
|
| | Message #1
|
|
+---------------+
|
|
| |
|
|
/ /
|
|
/ /
|
|
| |
|
|
+---------------+
|
|
| | Message #N
|
|
+---------------+
|
|
| | Trailer
|
|
+---------------+
|
|
|
|
|
|
The header and trailer are of fixed length. All of
|
|
the messages are variable length, but have a fixed number of
|
|
fields within them.
|
|
|
|
Packets must be treated as a byte stream; for many
|
|
of the components, "type" flags determine the format of
|
|
upcoming data, therefore it is difficult to "read ahead",
|
|
except for buffering purposes.
|
|
|
|
THE HEADER:
|
|
|
|
The header is a fixed length structure, and contains
|
|
the originating and destination nodes, the date the packet
|
|
was made, a version number, and some extra space for future
|
|
expansion.
|
|
|
|
Foolishly, there is no "type" identifier in the
|
|
packet header.
|
|
|
|
A PACKET MESSAGE:
|
|
|
|
Each message contains an interger "type", followed
|
|
by the message fields. These are: attribute, originating
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 4
|
|
|
|
node, destination node, two zeros, cost, date string, "to"
|
|
string, "from" string, "Subject" string, followed by the
|
|
text string.
|
|
|
|
The type, attribute, orig and dest node numbers, the
|
|
two zeros and cost are all integers. The other are serial
|
|
byte streams, strings, of variable length.
|
|
|
|
INPORTANT NOTE:
|
|
|
|
Due to extreme shortsightedness in the original
|
|
packet design, the message type 1 did not include the
|
|
originating and destination node numbers; FidoNet inserted
|
|
the node numbers found in the packet header when the message
|
|
was unpacked and stored in the system.
|
|
|
|
Routing meant that messages for many different nodes
|
|
were packed into a single packet; needless to say this means
|
|
that the node numbers may not be the same for each message,
|
|
as was the previous assumtion.
|
|
|
|
A message type 2 (the one described above) was added
|
|
to accomodate the "extra" information. Starting in version
|
|
10, FidoNet will no longer create message type 1, though it
|
|
will continue to receive them. Other implementations may
|
|
ignore message type 1, and assume that all are message type
|
|
2.
|
|
|
|
THE TRAILER:
|
|
|
|
The trailer consists of a single integer 0. This can
|
|
be thought of as a message type 0. This ends the packet; any
|
|
data following it (as when XMODEM rounds the packet up to
|
|
the next highest 128 bytes) should be ignored.
|
|
|
|
|
|
SYSTEM ASSUMPTIONS
|
|
|
|
Fido and FidoNet were designed using some basic
|
|
software building block concepts, admittedly stolen from
|
|
Ward Christensen's MODEM program.
|
|
|
|
XMODEM with CRC error checking is used for the basic
|
|
mail packet transfer. No further discussion will be made as
|
|
to XMODEM implementation nor operation. Please refer to
|
|
other documents.
|
|
|
|
MODEM7, or more accurately, TELINK, protocol is used
|
|
to transfer any files "attached" after the message packet.
|
|
TELINK is identical to MODEM7, with the addition of an extra
|
|
data block, that passes MSDOS dependent file information
|
|
(time, date, exact file size) before the first data block.
|
|
FidoNet is still MODEM7 capable; all that is necessary is to
|
|
NAK the extra block, whose header character is ASCII SYN
|
|
instead of SOH when receiving from a TELINK based FidoNet.
|
|
For sending to TELINK based receiving FidoNets it is not
|
|
necessary to send this extra block. This protocol is also
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 5
|
|
|
|
described elsewhere.
|
|
|
|
|
|
FidoNet assumes the presence of a clock of some
|
|
sort, for failsafe monitoring of packet transfers, and for
|
|
accounting purposes, to monitor actual connect times.
|
|
Accounting is outside the scope of this document.
|
|
|
|
A clock timer, preferably interrupt driven, is
|
|
needed to monitor the initial connection process, though may
|
|
be done using polled counters, if they are "calibrated".
|
|
This is fairly important; it prevents excessive connect
|
|
times if either the sender or receiver fails at any point.
|
|
|
|
|
|
There are two basic subroutines used in the Fido
|
|
implementation of FidoNet. While these are very low level
|
|
hardware dependent routines, they are very important in
|
|
concept.
|
|
|
|
DELAY ( N )
|
|
|
|
Delay for N centiseconds. This is just a time delay,
|
|
or time waster routine. It is used for generating time
|
|
delays for accomodating the telephone companies equipment.
|
|
|
|
MODOUT ( CHARACTER )
|
|
|
|
Send a character to the modem. This is shown for
|
|
illustration purposes; it is used in the diagrams to follow.
|
|
|
|
MODIN ( N )
|
|
|
|
Receive a character from the mode, but wait no
|
|
longer than N centiseconds. If a character is received, it
|
|
is returned; if it times out, -1 is returned. Since
|
|
characters are 8 bits, -1 (16 bits) indicates that no valid
|
|
character was received. This is a very basic, very important
|
|
function, upon which all of FidoNet is based.
|
|
|
|
The centisecond timer does not need to be accurate.
|
|
10% or less error is ideal, 20% is acceptable, and Fidonet
|
|
will usually still operate at up to 100% error. However,
|
|
repeatability will suffer, and sensitivity to the "length"
|
|
of a telephone connection will increase rapidly above 25%
|
|
error.
|
|
|
|
This is implemented on MSDOS as an interrupt driver
|
|
timer; a polled timing loop is adequate if adjusted to match
|
|
the processor speed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 6
|
|
|
|
PACKET TRANSFERS
|
|
|
|
Packet transfers will be described in two ways here;
|
|
first, a prose description, lacking exact details, and a
|
|
diagram with tables, with exact timing relationships and
|
|
values.
|
|
|
|
A FidoNet session consists of the following:
|
|
|
|
- Building routing tables
|
|
|
|
- Building list of active nodes
|
|
|
|
- Creating packets
|
|
|
|
- Compiling Messages
|
|
|
|
- Compiling list of attached files
|
|
|
|
- Sending/receiving Packets
|
|
|
|
- Deleteing outgoing packets, marking sent messages
|
|
|
|
- Unpacking incoming packets
|
|
|
|
- Return control to Fido
|
|
|
|
Only the creating of packets and attached file
|
|
lists, their transmission and reception, and unpacking is
|
|
covered here. The other steps are Fido dependent, and will
|
|
vary from implementation to implementation.
|
|
|
|
|
|
CREATING PACKETS:
|
|
|
|
FidoNet makes a number of passes through all of the
|
|
messages in the system. The first pass is merely to
|
|
determine which nodes have messages destined to them. Each
|
|
node is marked in a table, for later use in making packets
|
|
and dialing.
|
|
|
|
Additional passes are made, one for each node there
|
|
is mail to. A packet file is created on disk, using the
|
|
destination node number to create a unique filename (44.out
|
|
for a packet to node 44, etc), and the packet header is
|
|
written out.
|
|
|
|
When a message to this node is found, the message is
|
|
written out to the packet file. (The messages as stored in
|
|
Fido are described later in detail)
|
|
|
|
After the last message is written to the packet, the
|
|
trailer is written out, the file closed.
|
|
|
|
This process is repeated for all nodes that have
|
|
mail to be sent.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 7
|
|
|
|
SENDING PACKETS:
|
|
RECEIVING PACKETS:
|
|
|
|
FidoNet alternates sending and receiving packets for
|
|
most of the time slot. When it is not actually sending (or
|
|
attempting to send) a packet, it is waiting for one.
|
|
|
|
If there are no incoming calls, FidoNet makes
|
|
outgoing calls at a random one or two minute interval. A
|
|
node is chosen to call from the table compiled while making
|
|
packets. A node is picked sequentially from this table,
|
|
trying each one in sucession. When the end of the table is
|
|
reached, it starts over at the beginning.
|
|
|
|
When it is time to place a call, the next node is
|
|
chosen from the table, the telephone number is dialed. If no
|
|
connection is made, FidoNet goes back into receive mode.
|
|
|
|
If a connection is made, CRs are sent, to determine
|
|
the baud rate. When the called system determines the baud
|
|
rate, it sends the "signon" message telling human callers it
|
|
is not available. This message is detected by the caller,
|
|
and terminates the baud detection. If baud is not detected
|
|
in 8 seconds, the caller disconnects.
|
|
|
|
The sender then waits for the line to clear (the
|
|
signon message to stop), then sends a character designated
|
|
as "TSYNC". This tells the receiver that it is a FidoNet
|
|
node calling, instead of a human caller. There is a 60
|
|
second limit placed on the TSYNC sequence. The receiver then
|
|
goes into XMODEM file receive, with a unique name for the
|
|
incoming packet. (0.in, 1.in ...)
|
|
|
|
After sending TSYNC, the sender transmits the packet
|
|
(N.OUT) using normal XMODEM protocol.
|
|
|
|
After the packet is sent, the receiver goes
|
|
immediately into MODEM7 mode, to receive any attached files.
|
|
|
|
If there are no attached files, the sender sends an
|
|
EOT, which when received by the receiver in MODEM7, tells it
|
|
"no more files". If there are attached files, the sender
|
|
sends all of the files in the attached file list, using
|
|
MODEM7.
|
|
|
|
After either sending the attached files, or after
|
|
sending the EOT meaning no attached files, the sender delays
|
|
five seconds, then disconnects. After receiving the last
|
|
attached file (or the EOT) the receiver delays two seconds
|
|
and disconnects. The delay is to accomodate the telephone
|
|
systems peculiarity of keeping connect information on a
|
|
seperate, faster, channel that the data itself; without the
|
|
delay, it is possible for the "disconnect" to get there
|
|
before the character does.
|
|
|
|
If the packet was sent sucessfully, the sender
|
|
deletes the outgoing packet, the attached file list, and
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 8
|
|
|
|
marks the node table as "sucessful", and then returns to the
|
|
receive and wait mode.
|
|
|
|
UNPACKING PACKETS:
|
|
|
|
When FidoNet mail time is over, any unsent outgoing
|
|
packets are deleted, and all messages that were sent
|
|
sucessfully are marked as SENT.
|
|
|
|
Each incoming packet (0.in, 1.in ...) is unpacked
|
|
and deleted. First, the destination node number is compared
|
|
to the nodes actual number. If it does not match (this
|
|
packet not really meant for this node) the packet is deleted
|
|
without further unpacking. If it matches, the messages are
|
|
unpacked and placed in the message area.
|
|
|
|
The packet is read as a byte stream, and interpreted
|
|
as read. When a message type is found, FidoNet assembles the
|
|
message as it goes.
|
|
|
|
Note that it is possible to receive part of a
|
|
packet; Fidonet will unpack all complete messages and store
|
|
them in the message area. It may find an error, such as an
|
|
incomplete packet. This is not a necessary feature; since
|
|
the packet was aborted, it will be sent again the next
|
|
night.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 9
|
|
|
|
FIDONET DIALING AND PACKET TRANSFER
|
|
|
|
This is the final, detailed, description of the
|
|
actual packet transfer. Some shorthand notation will be used
|
|
here; "clock" means a general purpose timer for monitoring
|
|
elapsed time, and is set and read during many parts of the
|
|
packet protocol. The two subroutines described above are
|
|
also used through out.
|
|
|
|
The descriptions her are in a C like "pseudo code",
|
|
for simplicity. Function or subroutine calls are shown as:
|
|
|
|
function(parameter);
|
|
|
|
Where function() is the subroutine, and "parameter"
|
|
is a parameter passed to the function. Parameters here may
|
|
be numeric values or strings, which can be determined from
|
|
context. Functions without parameters are shown as
|
|
function(). Functions may return a value, so that:
|
|
|
|
x= function()
|
|
|
|
Sets variable X to the value returned by function().
|
|
|
|
IMPORTANT NOTE:
|
|
|
|
Ther is one extremely important construct that does
|
|
not, and cannot show up in these diagrams. This is a
|
|
mechanism to monitor Carrier Detect on the modem, and return
|
|
directly to a high level subroutine for error handling. This
|
|
is important due to the huge number of place where carrier
|
|
loss would have to be checked for, with the corresponding
|
|
high number of error return checks.
|
|
|
|
This can be implemented with a C like "set_jmp",
|
|
which stores the stack pointer and a return address, and
|
|
jumps to the return address if carrier is lost.
|
|
|
|
Also, in the Fido implementation, this error exit is
|
|
taken when the clock goes over the set limit. This frees the
|
|
high level code from having to watch the clock constantly.
|
|
|
|
The actual high level packet receive and send C
|
|
source is included at the end of this document to hopefully
|
|
make this a bit clearer.
|
|
|
|
|
|
All mnemonics are standard ASCII control characters,
|
|
with the exception of "TSYNC", described below.
|
|
|
|
Control Character Definitions
|
|
|
|
Char Hex Dec
|
|
---- --- ---
|
|
CR 0d 13
|
|
EOT 04 4
|
|
TSYNC ae 174
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 10
|
|
|
|
|
|
|
|
PACKET TRANSMISSION:
|
|
|
|
send_packet:
|
|
|
|
Attempt to place the call. If no connection, just return,
|
|
where FidoNet will wait for an incoming call, or delay one
|
|
or two minutes to place the next outgoing call.
|
|
|
|
set baud rate from node list
|
|
dial phone number,
|
|
if no connection, return
|
|
|
|
A connection has been made. Determine the baud rate first.
|
|
This "whacks return" up to eight times; if no message
|
|
appears from whacking, it stops and calls it an error. The
|
|
"double whack" (sic) seems to work better than a single CR.
|
|
When the receiver determines the baud rate, it sends 4 CRs,
|
|
and the signon message, which also contains CRs. The sender
|
|
notices this and stops sending its CRs.
|
|
|
|
for (i= 1 to 8) {
|
|
send CR, delay(20), send CR;
|
|
if (modin(100) == CR) break out of loop;
|
|
}
|
|
|
|
if (no CR received above) {
|
|
mark table as one "connect",
|
|
disconnect,
|
|
return.
|
|
}
|
|
|
|
Baud rate is now detected. Set the failsafe timer, wait
|
|
until the line clears (the signon message stops coming),
|
|
then send TSYNC. If one minute elapses, disconnect and
|
|
return.
|
|
|
|
print ("Connected");
|
|
|
|
set clock to zero;
|
|
while (clock is less than one minute) {
|
|
if (modin(50) == -1) break out of loop;
|
|
}
|
|
if clock == one minute {
|
|
disconnect,
|
|
return.
|
|
}
|
|
|
|
send (TSYNC);
|
|
disable clock;
|
|
print ("Sent TSYNC");
|
|
|
|
Presumably, all connected now. Start sending the packet via
|
|
XMODEM. XMODEM will timeout after so many tries, so that
|
|
this will not hang if the other end fails or is not a
|
|
FidoNet.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 11
|
|
|
|
|
|
print "Sending Packet"
|
|
xmodem send (packet);
|
|
|
|
Packet transmission complete. Mark the in memory table as
|
|
"succesful". If there are attached files, send them now,
|
|
otherwise just send an EOT.
|
|
|
|
success= 1;
|
|
|
|
if (attached files)
|
|
modem7 send attached files
|
|
|
|
else send EOT.
|
|
|
|
All sent, delay 5 seconds to let things settle down.
|
|
|
|
delay(500)
|
|
disconnect,
|
|
return.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 12
|
|
|
|
PACKET RECEPTION:
|
|
|
|
Carrier was detected while waiting to place a call or
|
|
waiting for an incoming call. Determine baud rate first,
|
|
display the signon message, then wait for TSYNC. There is a
|
|
one minute limit waiting for TSYNC. Note that connect()
|
|
watches the clock while waiting for CRs, and will take a
|
|
fatal error abort if it goes over the set limit. This
|
|
example therefore assumes that it will not timeout.
|
|
|
|
receive_packet:
|
|
|
|
reset clock,
|
|
connect() determine baud rate
|
|
|
|
print to modem:
|
|
"FidoNet Version x.x
|
|
FidoNet Node #N
|
|
Processing mail Only"
|
|
|
|
while (clock less than one minute) {
|
|
if modin(100) == TSYNC break out of loop;
|
|
}
|
|
|
|
if (over one minute) {
|
|
disconnect,
|
|
return;
|
|
}
|
|
|
|
All connected, received TSYNC. Wait for the incoming packet.
|
|
Each incoming packet is named sequentially, starting at 0;
|
|
0.in, 1.in, 2.in, etc. If no packet was received, quite now;
|
|
no sense in trying to get attached files if no packet
|
|
received.
|
|
|
|
xmodem receive packet
|
|
if no files received {
|
|
disconnect,
|
|
return.
|
|
}
|
|
|
|
Since it may have taken a few seconds to close up and write
|
|
out the packet file, the sender may have sent extra EOTs
|
|
from the end of the XMODEM packet transfer. Delay a bit, and
|
|
flush out the modem.
|
|
|
|
delay(200),
|
|
flush modem,
|
|
|
|
Now just go right into MODEM7 receive, for any attached
|
|
files. If there are none, the sender will send us an EOT,
|
|
which tells MODEM7 there are no more files. It can also just
|
|
hang up at this point, since the packet has already been
|
|
received. After the last, if any, file(s) received, delay 2
|
|
seconds and disconnect.
|
|
|
|
receive modem7 *.*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 13
|
|
|
|
delay(200),
|
|
disconnect,
|
|
return.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 14
|
|
|
|
IMPLEMENTATION NOTES:
|
|
|
|
These are some suggestions on implementing FidoNet
|
|
on all systems. They are merely suggestions; obviously you
|
|
can do what you want.
|
|
|
|
|
|
LOW LEVEL FUNCTIONS:
|
|
|
|
As mentioned before, there are some low level
|
|
functions that at least some of which are probably
|
|
universal. The ideas below may make it easier to implement a
|
|
"bullet proof" FidoNet.
|
|
|
|
ELAPSED TIME CLOCK:
|
|
|
|
This is a necessity, in one form or another. It's
|
|
accuracy does not need to be high. In Fido, it is
|
|
implemented as a timer tick interrupt, that increments in
|
|
memory variables: 'millisecs', 'seconds', 'minutes', and a
|
|
function to clear the clock, ie. set the above counters to
|
|
zero. (millisec is almost never actuall milliseconds; on the
|
|
IBM PC, for instance, the clock tick is at 55.55 mS; 55 is
|
|
added to 'millisec' every clock tick.)
|
|
|
|
There is an additional variable called 'limit', that
|
|
is the time limit to enforce for a particular routine.
|
|
Setting it to zero effectively disables the limit.
|
|
|
|
Thirdly, there is a function called limitchk(), that
|
|
does two things:
|
|
|
|
1. Watches the set time limit vs. the minute counter
|
|
|
|
2. Watches the carrier detect line from the modem
|
|
|
|
If either one of these events happens, it takes the
|
|
fatal error trap, and returns directly, instead of returning
|
|
normally.
|
|
|
|
|
|
limitchk() {
|
|
|
|
if (limit > 0) {
|
|
if (minutes >= limit) frc_abort();
|
|
}
|
|
if ! dsr()) frc_abort();
|
|
}
|
|
|
|
frc_abort() is the fatal error jump, back to the
|
|
caller directly. dsr() is a function that returns false (0)
|
|
if carrier is lost. If no fatal errors, limitchk() just
|
|
returns.
|
|
|
|
|
|
MODIN(N)
|
|
MODOUT()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 15
|
|
|
|
|
|
These two are the lowest level character IO in Fido.
|
|
modin(N) returns either a character from the modem, or -1
|
|
(TIMEOUT) if no character was available within N
|
|
centiseconds. This avoids hanging forever waiting for a
|
|
character that may never come.
|
|
|
|
modout() merely sends a character to the modem.
|
|
|
|
Both of these functions check for errors by calling
|
|
limitchk() while waiting for input or output ready.
|
|
|
|
modin(n)
|
|
int n;
|
|
{
|
|
millisec= 0L;
|
|
while (millisec < (10 * n) ) {
|
|
if (character ready) return(modem char);
|
|
limitchk();
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
modout(c)
|
|
char c;
|
|
{
|
|
while (output not ready) {
|
|
limitchk();
|
|
}
|
|
send char to modem
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 16
|
|
|
|
MESSAGES
|
|
|
|
While the message format is very Fido dependent, it
|
|
may be illustrative to show the correspondence between a
|
|
"normal" Fido message and one that has been installed in a
|
|
packet.
|
|
|
|
This is the format of a Fido message, as contained
|
|
in any Fido Message Area.
|
|
|
|
|
|
/* Message header structure. The message text is just a long
|
|
string. */
|
|
|
|
struct _msg {
|
|
char from[36]; /* who from, */
|
|
char to[36]; /* who to, */
|
|
char subj[72]; /* message subject, */
|
|
char date[20]; /* creation date, */
|
|
int times; /* number of times read, */
|
|
int dest; /* destination node, */
|
|
int orig; /* originating node */
|
|
int cost; /* actual cost of msg */
|
|
int caca[6]; /* extra space, */
|
|
unsigned reply; /* thread to previous */
|
|
int attr; /* message type, */
|
|
int up; /* thread to next */
|
|
};
|
|
|
|
/* The message text starts at the byte following the end
|
|
of the structure, and is terminated by a single null. */
|
|
|
|
/* Bit values for msg.attr */
|
|
|
|
#define MSGPRIVATE 1 /* private message, */
|
|
#define MSGREAD 4 /* read by addressee */
|
|
#define MSGSENT 8 /* sent OK (remote) */
|
|
#define MSGFILE 16 /* file attached to msg */
|
|
#define MSGFWD 32 /* being forwarded */
|
|
#define MSGORPHAN 64 /* unknown dest node */
|
|
#define MSGKILL 128 /* kill after mailing */
|
|
|
|
|
|
A Fido message is 191 bytes minimum; 190 bytes of
|
|
header, above, and a variable amount of message text, null
|
|
terminated. A fairly large klunky thing to pass around. When
|
|
compacted into a packet, it is much smaller. As an example,
|
|
assume the following message:
|
|
|
|
From: Tom Jennings On Fido 1
|
|
To: John Madill On Fido 2
|
|
Subject: Test message
|
|
This is text in the test message.
|
|
|
|
A hex dump of this test message follows. Note that
|
|
the null terminated strings are followed by garbage; please
|
|
ignore it.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 17
|
|
|
|
|
|
54 6F 6D 20 4A 65 6E 6E-69 6E 67 73 00 00 8E 36 Tom Jennings...6
|
|
00 00 00 FE FF 06 00 00-00 00 96 36 31 00 F3 21 ...~.......61.s!
|
|
0A 00 00 00 4A 6F 68 6E-20 4D 61 64 69 6C 6C 00 ....John Madill.
|
|
86 99 F8 27 86 99 02 28-00 00 91 36 57 61 69 74 ..x'...(...6Wait
|
|
20 2E A0 99 AE 16 68 21-74 65 73 74 20 6D 65 73 . ...h!test mes
|
|
73 61 67 65 00 00 65 00-FF 00 FC FF 00 00 B8 99 sage..e...|...8.
|
|
40 00 AF 06 AF 06 65 06-40 00 65 00 65 00 FC FF @././.e.@.e.e.|.
|
|
00 00 AF 06 0D 06 40 00-65 00 FF 00 FC FF 00 00 ../...@.e...|...
|
|
DA 99 65 00 AF 06 7E 60-1D 1A 83 F2 99 36 BC 27 Z.e./.~`...r.6<'
|
|
32 33 20 4F 63 74 20 38-34 20 20 31 36 3A 31 39 23 Oct 84 16:19
|
|
3A 34 38 00 01 00 02 00-01 00 1B 00 00 00 00 00 :48.............
|
|
00 00 00 00 00 00 00 00-00 00 81 00 00 00 20 20 ..............
|
|
54 68 69 73 20 69 73 20-74 65 78 74 20 69 6E 20 This is text in
|
|
74 68 65 20 74 65 73 74-20 6D 65 73 73 61 67 65 the test message
|
|
2E 0D 0A 0D 0A 00 ......
|
|
|
|
When the message is packetized, it becomes much
|
|
smaller; an entire packet, header, the above message and
|
|
trailer, is only 164 bytes. The extra space and most of the
|
|
Fido dependent items are removed.
|
|
|
|
01 00 02 00 C0 07 09 00-02 00 10 00 19 00 0E 00 ....@...........
|
|
00 00 01 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
|
|
00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
|
|
00 00 00 00 00 00 00 00-00 00 01 00 01 00 1B 00 ................
|
|
32 33 20 4F 63 74 20 38-34 20 20 31 36 3A 31 39 23 Oct 84 16:19
|
|
3A 34 38 00 4A 6F 68 6E-20 4D 61 64 69 6C 6C 00 :48.John Madill.
|
|
54 6F 6D 20 4A 65 6E 6E-69 6E 67 73 00 74 65 73 Tom Jennings.tes
|
|
74 20 6D 65 73 73 61 67-65 00 20 20 54 68 69 73 t message. This
|
|
20 69 73 20 74 65 78 74-20 69 6E 20 74 68 65 20 is text in the
|
|
74 65 73 74 20 6D 65 73-73 61 67 65 2E 0D 0A 0D test message....
|
|
0A 00 00 00 ....
|
|
|
|
The packet header format is as follows. It is
|
|
possible to follow, and hand disassemble, the message
|
|
packet.
|
|
|
|
struct _hdr {
|
|
int orig; /* originating Node # */
|
|
int dest; /* destination node */
|
|
int year,month,day,hour,minute,second;
|
|
int rate; /* baud rate */
|
|
int ver; /* packet version */
|
|
int extra[19];
|
|
} pkthdr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 18
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <bbs.h>
|
|
#include <xfbuf.h>
|
|
#include <ascii.h>
|
|
#include <xtelink.h>
|
|
|
|
#define TSYNC 0xae
|
|
|
|
extern char ver[];
|
|
|
|
extern unsigned crcmode; /* 1 if CRC mode, */
|
|
extern unsigned filemode; /* transfer type; XMODEM, MODEM7, TELINK */
|
|
|
|
/* Statistics on file transmission. */
|
|
|
|
extern unsigned totl_files; /* total files sent/rec'd */
|
|
extern unsigned totl_failures; /* how many failed, */
|
|
extern unsigned totl_errors; /* error count, soft errors incl */
|
|
extern unsigned totl_blocks; /* number blocks sent, */
|
|
|
|
extern int minutes,seconds;
|
|
extern int pktnum; /* incoming packet number */
|
|
|
|
extern struct _route route[ROUTE_SIZE]; /* routing table */
|
|
extern int maxnode; /* number of nodes in route table */
|
|
|
|
extern struct _sched sched[SCHEDS]; /* scheduled events */
|
|
extern char tag; /* handy local copy of the tag */
|
|
extern int event; /* handy local copy of the current event */
|
|
|
|
extern struct _nmap nmap[MAXNODES]; /* working node table */
|
|
extern int nn; /* current node, */
|
|
extern int nodetotal; /* number of nodes in the table */
|
|
|
|
extern struct _pkthdr pkthdr; /* FidoNet packet header */
|
|
extern struct _mail mail; /* MAIL.SYS */
|
|
extern struct _node node; /* in memory node descriptor */
|
|
extern struct _sys sys;
|
|
|
|
extern char *_txbuf; /* message display buff, ASCII upload */
|
|
|
|
extern int sysfiles; /* total system files, */
|
|
|
|
extern int overwrite; /* 1 == allow overwriting files */
|
|
extern int xferdisp; /* 1 == display up/dn load status */
|
|
|
|
extern int rate; /* baud rate */
|
|
extern int cd_flag;
|
|
extern int limit;
|
|
|
|
/* Carrier detected. Determine the baud rate, display a message to
|
|
tell humans what were doing, then get in sync with the sender. Once
|
|
in sync, receive the mail packet. */
|
|
|
|
rcv_mail() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 19
|
|
|
|
int i,n;
|
|
char pktname[80];
|
|
int msg_pkts,msg_blocks;
|
|
|
|
gtod(pktname);
|
|
lprintf("Call in @ %s\r\n",pktname); /* log the call, */
|
|
|
|
cprintf(" * Incoming Call\r\n");
|
|
clr_clk(); /* reset the clock, */
|
|
limit= 1; /* limit to connect, */
|
|
cd_flag= 0; /* watch Carrier Detect */
|
|
|
|
/* We get an abort if: timeout, no sync (human caller), actual file transfer
|
|
error, or packet received and sender hangs up. Totl_files is 0 if no
|
|
packets transferred. */
|
|
|
|
totl_blocks= 0;
|
|
totl_files= 0;
|
|
msg_pkts= 0;
|
|
msg_blocks= 0;
|
|
set_abort(0); /* trap carrier loss here, */
|
|
if (was_abort()) {
|
|
if (msg_pkts == 0) {
|
|
cprintf(" Receiving Mail Packet Aborted\r\n");
|
|
lprintf("\r\n*Aborted\r\n");
|
|
|
|
} else {
|
|
cprintf(" * Received %u packets\r\n",msg_pkts);
|
|
lprintf(" %u pkts %u blks OK\r\n",msg_pkts,msg_blocks);
|
|
if (totl_files > 0) {
|
|
cprintf(" Received %u files\r\n",totl_files);
|
|
lprintf("Recv'd Files\r\n");
|
|
}
|
|
}
|
|
cd_flag= 0; /* real CD, */
|
|
if (dsr()) discon(); /* hang up, delay for telco */
|
|
else delay(200); /* delay for telco */
|
|
|
|
return(msg_pkts);
|
|
}
|
|
|
|
/* The sender whacks CR until it gets a CR back. It then waits for the
|
|
message to stop, sends a TSYNC, and starts the transfer. */
|
|
|
|
/* -------------------- One Minute to Complete This ---------------------- */
|
|
|
|
cprintf(" * Determining Baud Rate\r\n");
|
|
connect(); /* determine baud rate, */
|
|
modout(CR); /* tell Tx we got baud right */
|
|
|
|
mprintf("\r\r\r\r\n FidoNet Version %s\r\n",ver);
|
|
mprintf(" FidoNet Node #%u\r\n",mail.node);
|
|
mprintf(" Processing mail only.\r\n");
|
|
mcrlf();
|
|
|
|
cprintf(" * Waiting for Sync\r\n");
|
|
while (modin(100) != TSYNC)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 20
|
|
|
|
limitchk();
|
|
|
|
/* ------------------- End One Minute to Complete -------------------- */
|
|
|
|
/* All connected. Transfer the mail packet. No time limit, but the
|
|
file receive will abort if there is an error. */
|
|
|
|
limit= 0; /* no time limit */
|
|
|
|
sprintf(pktname,"%u.in",pktnum++); /* pick a new name, */
|
|
cprintf(" * Waiting for Mail Packet (%s)\r\n",pktname);
|
|
lprintf(" %s ",pktname);
|
|
|
|
crcmode= 1; /* CRC, */
|
|
filemode= XMODEM; /* file xfer mode, */
|
|
recieve(pktname); /* receive a packet, */
|
|
|
|
msg_pkts= totl_files;
|
|
msg_blocks= totl_blocks; /* number of mail packets, */
|
|
totl_files= 0;
|
|
totl_blocks= 0;
|
|
|
|
/* Let extra EOTs, etc settle out, then flush it so the file receive
|
|
doesnt get the extra EOTs. */
|
|
|
|
delay(200); /* delay for last char */
|
|
while (modin(10) != TIMEOUT);
|
|
|
|
/* Wait for any incoming files. If there areent any, then the caller
|
|
will just hang up if an older version, or will send EOT if no files. */
|
|
|
|
filemode= TELINK;
|
|
recieve(mail.filepath); /* get any files, */
|
|
delay(200);
|
|
frc_abort(); /* error trap exit */
|
|
}
|
|
|
|
/* Send a mail packet to the remote. Dial the number, if error, return 0 to
|
|
indicate no connection. Also, 'minutes' upon return reflects the actual
|
|
connection time. */
|
|
|
|
send_mail() {
|
|
|
|
char pktname[80],fllname[80];
|
|
int n,f;
|
|
int msg_pkts,msg_blocks;
|
|
int online;
|
|
|
|
cprintf(" * Calling Fido%u %s %s\r\n",node.number,node.name,node.phone);
|
|
online= 0; /* no connect yet */
|
|
*_txbuf= '\0'; /* in case no file, */
|
|
sprintf(fllname,"%u.fll",node.number);
|
|
f= _xopen(fllname,0); /* read in file list, */
|
|
n= _xread(f,_txbuf,_TXSIZE);
|
|
_txbuf[n]= '\0'; /* null terminate it, */
|
|
_xclose(f);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 21
|
|
|
|
gtod(pktname);
|
|
lprintf("Call out Fido%u @ %s\r\n",node.number,pktname);
|
|
|
|
sprintf(pktname,"%u.out",node.number); /* local packet to send */
|
|
++nmap[nn].tries; /* log another try, */
|
|
|
|
/* We get an abort if (1) it times out dialing, (2) we fail to connect
|
|
or (3) transmission sucessful, and receiver hung up. totl_files tells
|
|
us what happened. */
|
|
|
|
totl_blocks= 0;
|
|
totl_files= 0;
|
|
msg_pkts= 0;
|
|
msg_blocks= 0;
|
|
set_abort(0);
|
|
if (was_abort()) {
|
|
if (online) {
|
|
nmap[nn].time+= (minutes * 60) + seconds;
|
|
++nmap[nn].connects;
|
|
}
|
|
|
|
if (msg_pkts == 0) {
|
|
cprintf(" Packet Transmission Aborted\r\n");
|
|
lprintf("*Nothing sent\r\n");
|
|
|
|
} else {
|
|
cprintf(" * Sent %u packets %u files\r\n",
|
|
msg_pkts,totl_files);
|
|
|
|
lprintf(" Sent %u pkts %u files\r\n",msg_pkts,totl_files);
|
|
nmap[nn].success= 1;
|
|
_xdelete(pktname); /* done with that packet */
|
|
_xdelete(fllname);
|
|
}
|
|
|
|
cd_flag= 0;
|
|
if (dsr()) discon();
|
|
|
|
return(msg_pkts);
|
|
}
|
|
|
|
/* Set the baud rate from the node list, and dial the number. Dialing is
|
|
aborted if either a no-connect from the modem, or a timeout if no modem
|
|
is connected. */
|
|
|
|
rate= 0; /* assume 300 baud, */
|
|
if (node.rate >= 1200) rate= 1; /* unless higher */
|
|
baud(rate);
|
|
cd_flag= 1; /* dont bomb on no carrier */
|
|
|
|
/* -------------------- One Minute to Dial ---------------------- */
|
|
|
|
limit= 1; /* 1 min to dial, */
|
|
clr_clk(); /* reset the clock, */
|
|
if (dial(node.phone) == 0) {
|
|
cprintf(" * No connection\r\n");
|
|
lprintf("*No connection\r\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 22
|
|
|
|
frc_abort(); /* do abort handler */
|
|
}
|
|
|
|
rate= 0; /* again for stupid hardware */
|
|
if (node.rate >= 1200) rate= 1; /* that dials at fixed rates */
|
|
baud(rate);
|
|
|
|
cd_flag= 0; /* now watch carrier */
|
|
cprintf(" * Connected at %u baud\r\n",node.rate);
|
|
lprintf(" Connect @ %u\r\n",node.rate);
|
|
|
|
/* -------------------- One Minute to Connect and Sync --------------- */
|
|
|
|
/* Send CRs until we get a CR back, saying we detected baud correctly. */
|
|
|
|
online= 1; /* connected now */
|
|
clr_clk(); /* reset clock, */
|
|
limit= 1; /* 1 min to connect, etc */
|
|
|
|
/*300*/ while (modin(100) != TIMEOUT) /* quiet line, */
|
|
limitchk();
|
|
|
|
for (n= 8; --n;) { /* limited tries for baud test */
|
|
modout(CR); /* send CR CR until we */
|
|
/**/ delay(20); /* get one back, */
|
|
/**/ modout(CR);
|
|
if (modin(100) == CR) break;
|
|
}
|
|
if (n == 0) {
|
|
lprintf("*autobaud failed\r\n");
|
|
frc_abort(); /* give up if no response */
|
|
}
|
|
|
|
/* We got a CR from the receiver. Baud rate detected. Now, wait for the
|
|
prompt junk to go away, then send our sync character to say we're ready
|
|
to send. */
|
|
|
|
/*100*/ while (modin(50) != TIMEOUT) /* wait for quiet line, */
|
|
limitchk();
|
|
modout(TSYNC); /* send our sync, */
|
|
lprintf(" Sent TSYNC\r\n");
|
|
|
|
/* -------------------- End One Minute Connect and Sync -------------- */
|
|
|
|
limit= 0; /* no limit now */
|
|
|
|
cprintf(" * Sending Packet\r\n");
|
|
|
|
filemode= XMODEM;
|
|
crcmode= 1;
|
|
transmit(pktname);
|
|
msg_pkts= totl_files;
|
|
msg_blocks= totl_blocks;
|
|
|
|
totl_files= 0;
|
|
totl_blocks= 0;
|
|
if (strlen(_txbuf) == 0) { /* if no files, just */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fidonet Electronic Mail Protocol 20 Oct 84 Page 23
|
|
|
|
modout(EOT); /* send EOT, */
|
|
|
|
} else {
|
|
filemode= TELINK; /* now send any files, */
|
|
transmit(_txbuf);
|
|
}
|
|
delay(500);
|
|
frc_abort(); /* do termination code */
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|