Document: FTS-0001 Version: 17 Date: 06-Nov-2014 A Basic FidoNet Technical Standard Revision 17 Introduction This document defines the data structures which a FidoNet implementation must provide. 1. Basic Requirements for a FidoNet Implementation A FidoNet implementation must be able to call other nodes and transfer messages and files in both directions. This includes pickup and poll. A FidoNet implementation must be able to accept calls from other nodes and transfer messages and files in both directions. This includes pickup. 2. Data Description (* literals *) "ABC" - ASCII character string, no termination implied nnH - byte in hexadecimal (* terminals *) someName - 16-bit integer (little endian) someName[n] - field of n bytes someName[.n] - field of n bits someName(n) - Null terminated string allocated n-1 chars someName{max} - Null terminated string of up to max-1 chars (* punctuation *) a b - one 'a' followed by one 'b' ( a | b ) - either 'a' or 'b', but not both { a } - zero or more 'a's [ b ] - zero or one 'b' (* comment *) - ignored (* predeclared constant *) Null = 00H a. The message format Offset dec hex .-----------------------------------------------. 0 0 | | ~ fromUserName ~ | 36 bytes | +-----------------------+-----------------------+ 36 24 | | ~ toUserName ~ | 36 bytes | +-----------------------+-----------------------+ 72 48 | | ~ subject ~ | 72 bytes | +-----------------------+-----------------------+ 144 90 | | ~ DateTime ~ | 20 bytes | +-----------------------+-----------------------+ 164 A4 | timesRead (low order) | timesRead (high order)| +-----------------------+-----------------------+ 166 A6 | destNode (low order) | destNode (high order) | +-----------------------+-----------------------+ 168 A8 | origNode (low order) | origNode (high order) | +-----------------------+-----------------------+ 170 AA | cost (low order) | cost (high order) | +-----------------------+-----------------------+ 172 AC | origNet (low order) | origNet (high order) | +-----------------------+-----------------------+ 174 AE | destNet (low order) | destNet (high order) | +-----------------------+-----------------------+ 176 B0 | destZone (optional) | destZone (optional) | +-----------------------+-----------------------+ 178 B2 | origZone (optional) | origZone (optional) | +-----------------------+-----------------------+ 180 B4 | destPoint(optional) | destPoint(optional) | +-----------------------+-----------------------+ 182 B6 | origPoint(optional) | origPoint(optional) | +-----------------------+-----------------------+ 184 B8 | replyTo (low order) | replyTo (high order) | +-----------------------+-----------------------+ 186 BA | Attribute (low order) | Attribute (high order)| +-----------------------+-----------------------+ 188 BC | nextReply (low order) | nextReply (high order)| +-----------------------+-----------------------+ 190 BE | text | ~ unbounded ~ | null terminated | `-----------------------------------------------' Message = fromUserName(36) (* Null terminated *) toUserName(36) (* Null terminated *) subject(72) (* see FileList below *) DateTime (* last edited *) timesRead (* not used *) destNode (* of message *) origNode (* of message *) cost (* not used *) origNet (* of message *) destNet (* of message *) destZone (* of message *) origZone (* of message *) destPoint (* of message *) origPoint (* of message *) replyTo (* not used *) AttributeWord nextReply (* not used *) text(unbounded) (* Null terminated *) DateTime = (* a character string 20 characters long *) (* 01 Jan 86 02:34:56 *) DayOfMonth " " Month " " Year " " " " HH ":" MM ":" SS Null DayOfMonth = "01" | "02" | "03" | ... | "31" Month = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec" Year = "01" | "02" | .. | "85" | "86" | ... | "99" | "00" HH = "00" | .. | "23" MM = "00" | .. | "59" SS = "00" | .. | "59" AttributeWord bit meaning --- -------------------- 0 + Private 1 + s Crash 2 Recd 3 Sent 4 + FileAttached 5 InTransit 6 Orphan 7 KillSent 8 Local 9 s HoldForPickup 10 + unused 11 s FileRequest 12 + s ReturnReceiptRequest 13 + s IsReturnReceipt 14 + s AuditRequest 15 s FileUpdateReq s - need not be recognized, but it's ok + - not zeroed before packeting Bits numbers ascend with arithmetic significance of bit position. Message text is unbounded and null terminated (note exception below). A 'hard' carriage return, 0DH, marks the end of a paragraph, and must be preserved. So called 'soft' carriage returns, 8DH, may mark a previous processor's automatic line wrap, and should be ignored. All linefeeds, 0AH, should be ignored. If the first character of a physical line (e.g. the first character of the message text, or the character immediately after a hard carriage return (ignoring any linefeeds)) is a ^A (, 01H), then that line is not displayed as it contains control information. The convention for such control lines is: o They begin with ^A o They end at the end of the physical line (i.e. ignore soft s). o They begin with a keyword followed by a colon. o The keywords are uniquely assigned to applications. o They keyword/colon pair is followed by application specific data. b. File Specifications If one or more of FileAttached, FileRequest, or FileUpdateReq are asserted in an AttributeWord, the subject{72} field is interpreted as a list of file specifications which may include wildcards and other system-dependent data. This list is of the form FileList = [ FileSpec { Sep FileSpec } ] Null FileSpec = (* implementation dependent file specification. may not contain Null or any of the characters in Sep. *) Sep = ( " " | "," ) { " " } c. The Packed Message format To conserve space and eliminate fields which would be meaningless if sent (e.g. timesRead), messages are packed for transmission. As this is a data structure which is actually transferred, its definition is critical to FidoNet. A packed message has a number of fixed length fields followed by four null terminated strings. Offset dec hex .-----------------------------------------------. 0 0 | 0 | 2 | 0 | 0 | +-----------------------+-----------------------+ 2 2 | origNode (low order) | origNode (high order) | +-----------------------+-----------------------+ 4 4 | destNode (low order) | destNode (high order) | +-----------------------+-----------------------+ 6 6 | origNet (low order) | origNet (high order) | +-----------------------+-----------------------+ 8 8 | destNet (low order) | destNet (high order) | +-----------------------+-----------------------+ 10 A | Attribute (low order) | Attribute (high order)| +-----------------------+-----------------------+ 12 C | cost (low order) | cost (high order) | +-----------------------+-----------------------+ 14 E | | ~ DateTime ~ | 20 bytes | +-----------------------+-----------------------+ 34 22 | toUserName | ~ max 36 bytes ~ | null terminated | +-----------------------+-----------------------+ | fromUserName | ~ max 36 bytes ~ | null terminated | +-----------------------+-----------------------+ | subject | ~ max 72 bytes ~ | null terminated | +-----------------------+-----------------------+ | text | ~ unbounded ~ | null terminated | `-----------------------------------------------' PakdMessage = 02H 00H (* message type *) origNode (* of message *) destNode (* of message *) origNet (* of message *) destNet (* of message *) AttributeWord cost (* not used *) DateTime (* message last edited *) toUserName{36} (* Null terminated *) fromUserName{36} (* Null terminated *) subject{72} (* Null terminated *) text{unbounded} (* Null terminated *) d. The Packet Header format The packet contains messages in packed format to be transferred over the net during a connection. As this data structure is transferred, its definition is critical to FidoNet. A packet may contain zero or more packed messages. A packet without messages is often generated as a poll packet. Every packet begins with a packet header. The fields of the packet header are of fixed length. Offset dec hex .-----------------------------------------------. 0 0 | origNode (low order) | origNode (high order) | +-----------------------+-----------------------+ 2 2 | destNode (low order) | destNode (high order) | +-----------------------+-----------------------+ 4 4 | year (low order) | year (high order) | +-----------------------+-----------------------+ 6 6 | month (low order) | month (high order) | +-----------------------+-----------------------+ 8 8 | day (low order) | day (high order) | +-----------------------+-----------------------+ 10 A | hour (low order) | hour (high order) | +-----------------------+-----------------------+ 12 C | minute (low order) | minute (high order) | +-----------------------+-----------------------+ 14 E | second (low order) | second (high order) | +-----------------------+-----------------------+ 16 10 | baud (low order) | baud (high order) | +-----------------------+-----------------------+ 18 12 | 0 | 2 | 0 | 0 | +-----------------------+-----------------------+ 20 14 | origNet (low order) | origNet (high order) | +-----------------------+-----------------------+ 22 16 | destNet (low order) | destNet (high order) | +-----------------------+-----------------------+ 24 18 | prodCode | serialNo | +-----------------------+-----------------------+ 26 1A | | | password (some impls) | | eight bytes | | null padded | | | +-----------------------+-----------------------+ 34 22 | origZone (low) (opt) | origZone (high) (opt) | +-----------------------+-----------------------+ 36 24 | destZone (low) (opt) | destZone (high) (opt) | +-----------------------+-----------------------+ 38 26 | fill | ~ 20 bytes ~ | | +-----------------------+-----------------------+ 58 3A | zero or more | ~ packed ~ | messages | +-----------------------+-----------------------+ | 0 | 0 | 0 | 0 | `-----------------------+-----------------------' Packet = PacketHeader { PakdMessage } 00H 00H PacketHeader = origNode (* of packet *) destNode (* of packet *) year (* of packet creation, yyyy *) month (* of packet creation, 0-11 *) day (* of packet creation, 1-31 *) hour (* of packet creation, 0-23 *) minute (* of packet creation, 0-59 *) second (* of packet creation, 0-59 *) baud (* not used *) PacketType (* 02H 00H *) origNet (* of packet *) destNet (* of packet *) prodCode (* write to FTSC for one *) serialNo (* binary serial number (or null)*) password (* session password (or null) *) origZone (* zone of pkt sender (or null) *) destZone (* zone of pkt receiver (or null)*) fill[20] The remainder of the packet consists of packed messages. Each packed message begins with a message type word 0200H. A pseudo-message beginning with the word 0000H signifies the end of the packet.