1589 lines
50 KiB
Plaintext
1589 lines
50 KiB
Plaintext
Fidonet Electronic Mail Protocol 8 Feb 85 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 8 Feb 85 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 operatign 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 8 Feb 85 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.
|
||
|
||
WHATA 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 8 Feb 85 Page 4
|
||
|
||
node, destination node, two zeros, cost, date strnig, "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 8 Feb 85 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 8 Feb 85 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 contrlo 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 nod ethere
|
||
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 8 Feb 85 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 8 Feb 85 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 8 Feb 85 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 8 Feb 85 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 8 Feb 85 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 8 Feb 85 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 three 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 8 Feb 85 Page 13
|
||
|
||
delay(200),
|
||
disconnect,
|
||
return.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
Fidonet Electronic Mail Protocol 8 Feb 85 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 8 Feb 85 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 8 Feb 85 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 8 Feb 85 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 8 Feb 85 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.
|
||
|
||
The kludge 'state' tells us what point we reached, for logging. */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
Fidonet Electronic Mail Protocol 8 Feb8 5 Page 19
|
||
|
||
rcv_mail() {
|
||
|
||
int i,n;
|
||
char pktname[80],*cp;
|
||
int msg_pkts,msg_blocks;
|
||
int state;
|
||
|
||
gtod(pktname);
|
||
cprintf("\r\n * Incoming Call at %s\r\n",pktname);
|
||
lprintf("\r\n * Incoming Call at %s\r\n",pktname);
|
||
|
||
/* 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;
|
||
clr_clk(); /* reset the clock, */
|
||
limit= 1; /* limit to connect, */
|
||
cd_flag= 0; /* watch Carrier Detect */
|
||
state= 0; /* nothing yet */
|
||
|
||
set_abort(0); /* trap carrier loss here, */
|
||
if (was_abort()) {
|
||
if (state == 0) {
|
||
cprintf(" * Never determined Baud Rate\r\n");
|
||
lprintf(" * Never determined Baud Rate\r\n");
|
||
|
||
} else if (state == 1) {
|
||
cprintf(" * Caller not a FidoNet\r\n");
|
||
lprintf(" * Caller not a FidoNet\r\n");
|
||
|
||
} else if (msg_pkts == 0) {
|
||
cprintf(" * Error during packet transfer\r\n");
|
||
lprintf(" * Error during packet transfer\r\n");
|
||
|
||
} else {
|
||
cprintf(" * Received packet\r\n");
|
||
lprintf(" * Received packet\r\n");
|
||
if (totl_files > 0) {
|
||
lower_dtr();
|
||
cprintf(" * eRceived %u files\r\n",totl_files);
|
||
lprintf(" * Received %u files\r\n",totl_files);
|
||
sprintf(pktname,"%u.fli",pktnum);
|
||
i= _xcreate(pktname,2);
|
||
if (i == -1) {
|
||
cprintf(" * Can't create %s\r\n",pktname);
|
||
lprintf(" * Can't create %s\r\n",pktname);
|
||
|
||
} else {
|
||
_xwrite(i,_txbuf,strlen(_txbuf));
|
||
_xclose(i);
|
||
}
|
||
raise_dtr();
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
Fidonet Electronic Mail Protocol 8 Feb 85 Page 20
|
||
|
||
}
|
||
cd_flag= 0; /* real CD, */
|
||
if (cd()) 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 ---------------------- */
|
||
|
||
/* The CRs and message must be sent all at once; the receiver is looking
|
||
for a quiet line, so any delays casued by logging, etc will foul things
|
||
up. */
|
||
|
||
cprintf(" * Determining Baud Rate\r\n");
|
||
lprintf(" * Determining Baud Rate\r\n");
|
||
connect();
|
||
state= 1; /* DETERMINED BAUD RATE */
|
||
|
||
cprintf(" * FidoNet Signon Message\r\n");
|
||
for (i= 5; i--;) modout(CR);
|
||
sprintf(_txbuf," FidoNet Node #%u Version %s\r\n",mail.node,ver);
|
||
cp= _txbuf; while (*cp) modout(*cp++);
|
||
sprintf(_txbuf," Processing mail only, call back later.\r\n");
|
||
cp= _txbuf; while (*cp) modout(*cp++);
|
||
|
||
cprintf(" * Connected at %d baud, waiting for sync\r\n",rate);
|
||
lprintf(" * Connected at %d baud, waiting for sync\r\n",rate);
|
||
for (i= 30; i--;) {
|
||
n= modin(100); /* 30 sec to get TSYNC */
|
||
if (n == TSYNC) break;
|
||
limitchk(); /* double check */
|
||
}
|
||
if (n != TSYNC) frc_abort(); /* no TSYNC */
|
||
state= 2; /* GOT TSYNC */
|
||
|
||
/* ------------------- 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\r\n");
|
||
lprintf(" %s ",pktname);
|
||
|
||
crcmode= 1; /* CRC, */
|
||
filemode= XMODEM; /* file xfer mode, */
|
||
*_txbuf= '\0'; /* received file name */
|
||
recieve(pktname); /* receive a packet, */
|
||
|
||
msg_pkts= totl_files;
|
||
msg_blocks= totl_blocks; /* number of mail packets, */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
Fidonet Electronic Mail Protocol 8 Feb 85 Page 21
|
||
|
||
totl_files= 0;
|
||
totl_blocks= 0;
|
||
if (msg_pkts == 0) { /* if nothing received */
|
||
frc_abort(); /* terminate here */
|
||
}
|
||
|
||
/* Let extra EOTs, etc settle out, then flush it so the file receive
|
||
doesnt get the extra EOTs. */
|
||
|
||
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;
|
||
*_txbuf= '\0'; /* get list of uploaded files */
|
||
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],floname[80];
|
||
int n,f;
|
||
int msg_pkts,msg_blocks;
|
||
int state;
|
||
|
||
gtod(pktname);
|
||
cprintf("\r\n * Calling Fido%u %s %s at %s\r\n",node.number,node.name,node.phone,pktname);
|
||
lprintf("\r\n * Calling Fido%u %s %s at %s\r\n",node.number,node.name,node.phone,pktname);
|
||
|
||
sprintf(floname,"%u.flo",node.number);
|
||
*_txbuf= '\0'; /* in case no file, */
|
||
f= _xopen(floname,0); /* read in file list, */
|
||
if (f != -1) {
|
||
n= _xread(f,_txbuf,_TXSIZE);
|
||
_txbuf[n]= '\0'; /* null terminate it, */
|
||
|
||
_xclose(f);
|
||
}
|
||
|
||
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;
|
||
state= 0; /* no connect yet */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
Fidonet Electronic Mail Protocol 8 Feb 85 Page 22
|
||
|
||
|
||
set_abort(0);
|
||
if (was_abort()) {
|
||
if (state > 0) {
|
||
nmap[nn].time+= (minutes * 60) + seconds;
|
||
++nmap[nn].connects;
|
||
}
|
||
|
||
if (state == 0) {
|
||
cprintf(" * No connection\r\n");
|
||
lprintf(" * No connection\r\n");
|
||
|
||
} else if (state == 1) {
|
||
cprintf(" * Disconnect before synchronization\r\n");
|
||
lprintf(" * Disconnect before synchronization\r\n");
|
||
|
||
} else if (msg_pkts == 0) {
|
||
cprintf(" * No packet(s) sent; probable non FidoNet system\r\n");
|
||
lprintf(" * No packet(s) sent; probable non FidoNet system\r\n");
|
||
|
||
} else {
|
||
cprintf(" * Sent %u packets %u files\r\n",msg_pkts,totl_files);
|
||
lprintf(" * Sent %u packets %u files\r\n",msg_pkts,totl_files);
|
||
nmap[nn].success= 1;
|
||
_xdelete(pktname); /* done with that packet */
|
||
_xdelete(floname);
|
||
}
|
||
|
||
cd_flag= 0;
|
||
if (cd()) 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= 300; /* assume 300 baud, */
|
||
if (node.rate >= 1200) rate= 1200; /* 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) {
|
||
frc_abort();
|
||
}
|
||
|
||
rate= 300; /* again for stupid hardware */
|
||
if (node.rate >= 1200) rate= 1200; /* that dials at fixed rates */
|
||
baud(rate);
|
||
cprintf(" * Connected at %d baud\r\n",rate);
|
||
lprintf(" * Connected at %d baud\r\n",rate);
|
||
state= 1; /* CONNECTION MADE */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
Fidonet Electronic Mail Protocol 8 Feb 85 Page 23
|
||
|
||
|
||
/* -------------------- One Minute to Connect and Sync --------------- */
|
||
|
||
/* Send CRs until we get a CR back, saying we detected baud correctly. */
|
||
|
||
clr_clk(); /* reset clock, */
|
||
limit= 1; /* 1 min to connect, etc */
|
||
cd_flag= 0; /* now watch carrier */
|
||
|
||
delay(300); /* let modems settle */
|
||
mflush(); /* flush buffers */
|
||
|
||
/* Extremely noisy lines never settle (Fido 79), so just delay to
|
||
let the modems connect, then flush the buffers of any garbage.
|
||
|
||
while (modin(300) != TIMEOUT) /* quiet line, */
|
||
limitchk();
|
||
*/
|
||
for (n= 10; --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) {
|
||
cprintf(" * No response to whacking CR\r\n");
|
||
lprintf(" * No response to whacking CR\r\n");
|
||
frc_abort();
|
||
}
|
||
|
||
/* 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. */
|
||
|
||
while (modin(50) != TIMEOUT) /* wait for quiet line, */
|
||
limitchk();
|
||
modout(TSYNC); /* send our sync, */
|
||
state= 2; /* TSYNC SENT */
|
||
|
||
/* -------------------- End One Minute Connect and Sync -------------- */
|
||
|
||
limit= 0; /* no limit now */
|
||
|
||
cprintf(" * Sending Packet\r\n");
|
||
lprintf(" * 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 (msg_pkts == 0) frc_abort(); /* terminate if nothing sent */
|
||
|
||
delay(100); /* delay 1 sec to let rcvr finish */
|
||
if (strlen(_txbuf) == 0) { /* if no files, just */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
Fidonet Electronic Mail Protocol 8 Feb 85 Page 24
|
||
|
||
modout(EOT); /* send EOT, */
|
||
|
||
} else {
|
||
filemode= TELINK; /* now send any files, */
|
||
transmit(_txbuf);
|
||
}
|
||
delay(400);
|
||
frc_abort(); /* do termination code */
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|