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 #include #include #include #include #include #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 */ }