FSC-0014=0A=
                               A Bundle Proposal=0A=
=0A=
                                Wynn Wagner III=0A=
                                 January, 1988=0A=
=0A=
=0A=
UPFRONT=0A=
-------=0A=
=0A=
What follows is a proposal for a new structure of message bundles that=0A=
are transmitted between Fidonet systems.=0A=
=0A=
Currently we deal with "packet version 2."  This is a proposed format=0A=
for packet version three.=0A=
=0A=
The version number should be recognizable by TYPE-2 programs, but the=0A=
older programs will not be able to do anything more than report an=0A=
error.  In other words, there is no direct upwards compatibility except=0A=
for the offset in the _BundleHeader (see below) of the TYPE-3 signal.=0A=
=0A=
Because of this, any conversion should be slow... possibly a year or =
more.=0A=
Interim systems would have to be able to pack and unpack both kinds=0A=
of bundles.  It would be required for the packer to know whether its=0A=
target system knows about TYPE-3 bundles or not... either by some node=0A=
list flag or by using a control file.=0A=
=0A=
I think it is important that a new structure be seriously considered,=0A=
but it is also vital that we approach such a change with a mind to=0A=
keeping it an evolutionary process rather than an overnight revolution.=0A=
It is important that TYPE-2 systems be retired using attrition instead=0A=
of compulsion.=0A=
=0A=
This proposal is described in detail... possibly too much detail.=0A=
The design looks scarier than it really is.  Code to process this=0A=
kind of a bundle is almost trivial.=0A=
=0A=
One design feature is that putting a message bundle together is =0A=
somewhat more involved than taking one apart.  The theory is that we=0A=
will be getting more and more tiny installations operating as points.=0A=
Collecting and unpacking such things as echomail will be easier even=0A=
on small/slow computers.  Heavy volume traffic with lots of packing=0A=
and unpacking is usually carried on by computers more capable of=0A=
heavy work.  Please note that the added work on the shoulders of=0A=
the packer is almost microscopic, but it exists.  This uneven =
distribution=0A=
of the work is intentional.=0A=
=0A=
=0A=
-------------------------------------------------------------------------=
-----=0A=
=0A=
PRELIMARIES: METHODS=0A=
--------------------=0A=
=0A=
        Messages are transmitted in "bundles."=0A=
=0A=
        A bundle is a sequence of "packets."  Every bundle has at=0A=
        least two packets: a header and a footer.=0A=
=0A=
        This document describes the layout and use of those=0A=
        packets as well as the general format of a bundle.=0A=
=0A=
=0A=
  =0A=
  =0A=
-------------------------------------------------------------------------=
-----=0A=
=0A=
PRELIMINARIES: DATA=0A=
-------------------=0A=
=0A=
=0A=
 #define BUNDLEVER 3=0A=
 #define EIDSIZ    (sizeof(struct _Address)+sizeof(unsigned long))=0A=
=0A=
 struct _Address {=0A=
    unsigned int      Zone;=0A=
    unsigned int      Net;=0A=
    unsigned int      Node;=0A=
    unsigned int      Point;=0A=
 };=0A=
=0A=
     DATA NOTES:=0A=
=0A=
        "WORD" is a two byte unsigned integer with the most significant=0A=
               byte first.  This storage arrangement is backwards from=0A=
               the way INTEL chips store numbers, but it is more in-line=0A=
               with the way the rest of the universe does it.  The=0A=
               conversion for MsDOS and other INTEL programmers is quite=0A=
               trivial.=0A=
=0A=
               A routine called SWAP can be used, where...=0A=
=0A=
                       unsigned int pascal SWAP(unsigned int VALUE);=0A=
=0A=
               Here's the code...=0A=
=0A=
                           SWAP Proc Near=0A=
                                mov   bx, sp=0A=
                                mov   ax, [bx+2]=0A=
                                xchg  ah, al=0A=
                                ret 2=0A=
                           SWAP EndP=0A=
=0A=
        "UNSIGNED LONG" is a four byte unsigned integer with the most=0A=
              significant word first.  Again, this storage arrangement=0A=
              conflicts with the method used by INTEL, but the trans-=0A=
              formation to "MSW first" is quite simple and it really=0A=
              makes the non-MsDOS programmers feel more comfortable.=0A=
=0A=
        "UNSIGNED CHAR" is an 8-bit datum that can have any value=0A=
              between 0 and 0xff.=0A=
=0A=
        CHARACTER ARRAYS are null-padded unless otherwise noted. There=0A=
              is a difference between "null-terminated" (common to=0A=
              C-language programming) and "null-padded" found here.=0A=
              Unless there is a conflicting note, insignificant bytes=0A=
              of a character array must be set to zero.=0A=
=0A=
        UNUSED DATA are always set to zero.=0A=
=0A=
     =0A=
=0A=
-------------------------------------------------------------------------=
-----=0A=
=0A=
BUNDLE HEADER=0A=
-------------=0A=
  =0A=
 struct _BundleHeader {=0A=
    struct _Address   B_Destination;    /* Address of target system    =
*/=0A=
    struct _Address   B_Origination;    /* Address where bndl started  =
*/=0A=
    unsigned int      B_Local1;         /* Used by bundler, etc        =
*/=0A=
    unsigned int      B_Version;        /* Always 3                    =
*/=0A=
    unsigned long     B_CreationTime;   /* Unix-type stamp (1970-base) =
*/=0A=
    unsigned int      B_BundlerMajor;   /* Major version of bundler    =
*/=0A=
    unsigned int      B_BundlerMinor;   /* Minor version of bundler    =
*/=0A=
    unsigned char     B_Password[9];    /* NULL-padded array           =
*/=0A=
    unsigned char     B_Local2;         /* Local use only              =
*/=0A=
    unsigned char     B_Product[4];     /* Meaningful to same product  =
*/=0A=
    unsigned char     B_FTSC[4];        /* Reserved by FTSC            =
*/=0A=
 };=0A=
=0A=
     BUNDLE HEADER NOTES:=0A=
=0A=
        The offset of B_Version coincides with the location of the=0A=
        `ver' field in type two bundle headers.=0A=
=0A=
        The B_Local1 and B_Local2 fields have no meaning during the=0A=
        actual transfer.  It is to hold such information as COST=0A=
        and/or BAUD rate of use to the sending system.=0A=
=0A=
        B_Password is a NULL-padded field that can contain uppercase=0A=
        alpha bytes or ASCII digits.  It should not contain lowercase=0A=
        characters, punctuation, control characters, etc.  This is a=0A=
        NULL-padded field... not just NULL-terminated.  A maximum of=0A=
        8 bytes are significant.=0A=
=0A=
        Note that the BUNDLER is identified by product code.  This =0A=
        does NOT necessarily have anything to do with the software=0A=
        that actually transmits the bundle.  This structure deals=0A=
        with message bundles, and the product identification shows=0A=
        which computer program was responsible for that layer of=0A=
        a netmail session.  The software providing transportation=0A=
        is more properly identified during a session-level negotiation =0A=
        (eg WaZOO's YooHoo) or in a dynamically generated structure =0A=
        (eg TeLink's block zero).  TYPE-3 tries to keep the various=0A=
        layers of the system separate and easily identifiable.  This=0A=
        document describes data, not the method by which they are=0A=
        passed from one system to another.=0A=
=0A=
=0A=
     BUNDLE BODY NOTES:=0A=
=0A=
        The bundle header packet is followed by one or more of the=0A=
        following packet types.  Each of these packets begin with =0A=
        two bytes that identify the packet version and the packet=0A=
        type.  In all cases, the version is three (0x03).=0A=
=0A=
        Packet types include=0A=
=0A=
                 END_SIGNAL        0=0A=
                 AREA_HEADER       1=0A=
                 MESSAGE_HEADER    2=0A=
                 TEXT              3=0A=
                 ECHOMAIL_INFO     4=0A=
                 MISCINFO          128-256=0A=
=0A=
        One message is built using at least two packets (MESSAGE_HEADER=0A=
        and TEXT).  Optionally, a message might also have ECHOMAIL_INFO=0A=
        and MISCINFO packets.  Packets associated with a message must=0A=
        be bundled in numerical order (by packet type)... the header=0A=
        comes first, followed by the text, possibly followed by echomail=0A=
        information, and possibly ending with some miscellaneous =
packets.=0A=
=0A=
        This arrangement of bundles allows the development of=0A=
        state machine type programs which effect efficient message=0A=
        processing even on slow or small computers.  Here's a=0A=
        quick coding example:=0A=
=0A=
              for(;;)=0A=
                switch(fgetc(BUNDLE)) {=0A=
                   default:  printf("Not Type-3 message"); return -1;=0A=
                   case 3:   switch(fgetc(BUNDLE)) {=0A=
                                case -1: printf("EOF?");   return -1;=0A=
                                case 0:  printf("Done\n"); return 0;=0A=
                                case 1:  GetMsgArea();     break;=0A=
                                case 2:  GetMessage();     break;=0A=
                                default: printf("Pkt?");   break;=0A=
                             };=0A=
                };=0A=
=0A=
                    NOTE: For those re-reading and spotting what looks=0A=
                          like a mistake... the `GetMessage()' routine=0A=
                          would also take care of TEXT and any ECHOMAIL =
=0A=
                          or MISCINFO packets.=0A=
=0A=
                          Also, for a little added robustness, the=0A=
                          default item that prints "Pkt?" should look=0A=
                          for a value of 0x03 (or and end of the file)=0A=
                          before returning to the processing loop.=0A=
=0A=
=0A=
=0A=
-------------------------------------------------------------------------=
-----=0A=
=0A=
BUNDLE FOOTER=0A=
-------------=0A=
=0A=
 struct _BundleEnd {=0A=
    unsigned char     M_Version;        /* Always 3                    =
*/=0A=
    unsigned char     M_PacketType;     /* Always 0                    =
*/=0A=
 };=0A=
=0A=
     =0A=
     BUNDLE END NOTES:=0A=
=0A=
        All bundles end with this packet.  It is not optional.=0A=
=0A=
=0A=
=0A=
-------------------------------------------------------------------------=
-----=0A=
=0A=
MESSAGE AREA=0A=
------------=0A=
=0A=
 struct _AreaHeader {=0A=
    unsigned char     E_Version;        /* Always 3                    =
*/=0A=
    unsigned char     E_PacketType;     /* Always 1                    =
*/=0A=
    unsigned byte     E_NameLength;     /* Actual bytes in E_Name      =
*/=0A=
    unsigned byte     E_Name[1];        /* VARIABLE-length field       =
*/=0A=
 };=0A=
=0A=
     AREA HEADER NOTES:=0A=
=0A=
        The area header packet marks the start of a sequence of=0A=
        messages destined for the same message area.=0A=
=0A=
        Often E_Name will contain the name of an echomail area.=0A=
        If the legnth and first byte of E_Name are zero, it means=0A=
        that the following messages are inter-system traffic=0A=
        (ie regular netmail).=0A=
=0A=
        The maximum value for E_NameLength is 63.=0A=
=0A=
        E_Name can contain uppercase characters, digits, and the=0A=
        following punctuation: $ . - _ & # @ !=0A=
=0A=
        Note that E_NameLength combined with E_Name make up what=0A=
        is often considered a "Pascal style string."  E_Name is=0A=
        NOT a null-terminated array (aka "ASCIIZ").=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
-------------------------------------------------------------------------=
-----=0A=
=0A=
MESSAGE HEADER=0A=
--------------=0A=
=0A=
 struct _MessageHeader {=0A=
    unsigned char     M_Version;        /* Always 3                    =
*/=0A=
    unsigned char     M_PacketType;     /* Always 2                    =
*/=0A=
    struct _Address   M_Destination;    /* FINAL Destination           =
*/=0A=
    struct _Address   M_Origination;    /* Where message was entered   =
*/=0A=
    unsigned long     M_CreationTime;   /* Unix-type stamp (1970-base) =
*/=0A=
    unsigned int      M_Attributes;     /* Standard Fidonet bitweights =
*/=0A=
    unsigned char     M_FromLength;     /* Number of bytes in FROM     =
*/=0A=
    unsigned char     M_ToLength;       /* Number of bytes in TO       =
*/=0A=
    unsigned char     M_SubjectLength;  /* Number of bytes in SUBJECT  =
*/=0A=
 };=0A=
=0A=
=0A=
     MESSAGE HEADER NOTES:=0A=
=0A=
        Every message begins with a message header packet.  This=0A=
        structure is created by the system where the message=0A=
        originated.  If there are any intermediate stops before=0A=
        it reaches its destination, it is the responsibility of=0A=
        intermediate systems to maintain all of this information=0A=
        without any modification.=0A=
=0A=
        Following this header come three char-type data: FROM, TO,=0A=
        and SUBJECT.  Using the final three fields of the header,=0A=
        a program can quickly read and process/store the the message.=0A=
=0A=
        None of the character items is null-terminated.  Their=0A=
        lengths are determined by values in the message header.=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
-------------------------------------------------------------------------=
-----=0A=
=0A=
MESSAGE TEXT/BODY=0A=
-----------------=0A=
=0A=
 struct _Text {=0A=
    unsigned char    T_Version;         /* Always 3                    =
*/=0A=
    unsigned char    T_PacketType;      /* Always 3                    =
*/=0A=
    unsigned int     T_ByteCount;       /* Number of bytes ( <0x1000)  =
*/=0A=
    unsigned int     T_Data[1];         /* VARIABLE-length field       =
*/=0A=
 };=0A=
=0A=
     TEXT NOTES:=0A=
=0A=
        The body of a message is contained in one or more _Text packets.=0A=
=0A=
        No _Text packet is ever more than 1000H bytes long.  That's=0A=
        4096 bytes to the terminally base-10 folks.  Of course there=0A=
        can be an infinite number of text packets, but you are=0A=
        absolutely positively guaranteed that with the TYPE-3 method,=0A=
        you will never need a buffer larger than 1000H.=0A=
=0A=
        In addition to ASCII values 20h through 7Eh (inclusive),=0A=
        the following control codes are legal for TEXT data.=0A=
        Note that <cr> and <softCR> are NOT in this list.=0A=
=0A=
           <stx>  02H  ... material from here to next <lf> is=0A=
                           a quote from the parent message=0A=
           <lf>   0Ah  ... forced <cr/lf>=0A=
           <dle>  10h  ... replicate=0A=
=0A=
        Other control characters and values 7fH and above are=0A=
        symptoms of a damaged message.=0A=
=0A=
        REPLICATE is a three byte sequence:  <dle><value><length>.=0A=
        For example, if a message contains the bytes 10h, 20h, 09h ...=0A=
        it would mean that message display programs should replicate=0A=
        the <space> character nine times.  =0A=
=0A=
        There is no minimum or maximum line length.  If there is no=0A=
        <lf> before the display program needs one, it is the display=0A=
        program's responsibility to provide the needed "line wrap."=0A=
=0A=
        One "line" can cross from one _Text packet to another.=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
-------------------------------------------------------------------------=
-----=0A=
=0A=
ECHOMAIL=0A=
--------=0A=
=0A=
 struct _EchomailInfo {=0A=
    unsigned char     EI_Version;       /* Always 3                    =
*/=0A=
    unsigned char     EI_PacketType     /* Always 4                    =
*/=0A=
    unsigned char     EI_Parent[EIDSIZ];/* "up" message thread         =
*/=0A=
    unsigned char     EI_Child[EIDSIZ]; /* "down" message thread       =
*/=0A=
    unsigned int      EI_SeenbyCount;   /* Number of SEENBY items      =
*/=0A=
    struct _Address   EI_Seenby[1];     /* VARIABLE-length field       =
*/=0A=
 };=0A=
=0A=
=0A=
     ECHOMAIL INFO NOTES:=0A=
=0A=
           The EI_Parent and EI_Child fields contain some kind of=0A=
           identification of the parent and child messages.  The size=0A=
           of the fields corresponds to the size of an _Address=0A=
           structure plus the size of a Unix-type time stamp.=0A=
=0A=
=0A=
=0A=
-------------------------------------------------------------------------=
-----=0A=
=0A=
A KLUDGE, BY ANY OTHER NAME...=0A=
------------------------------=0A=
=0A=
 struct _MiscInfo {=0A=
    unsigned char     MI_Version;       /* Always 3                    =
*/=0A=
    unsigned char     MI_PacketType;    /* 0x80-0xff, assigned by FTSC =
*/=0A=
    unsigned char     MI_ByteCount;     /* Size of miscinfo data       =
*/=0A=
    unsigned char     MI_WhoKnows;      /* Miscellaneous stuff         =
*/=0A=
 };=0A=
=0A=
=0A=
     MISCELLANEOUS INFO NOTES:=0A=
=0A=
           This is the catch-all packet type that replaces "The Dreaded=0A=
           IFNA Kludge."=0A=
=0A=
           If present, they are the last packets associated with a=0A=
           message.  _MiscInfo items are bound to a message, and it=0A=
           is the responsibility of any packer to maintain any =0A=
           _MiscInfo packets exactly as they arrived on any message=0A=
           that will be retransmitted (ie netmail and echomail).=0A=
=0A=
           Values above 0xf0 have a special meaning.  They are =0A=
           reserved for the severe case that FTSC needs to make some=0A=
           kind of change that isn't backwards compatible.  In most=0A=
           cases, unrecognized _MiscInfo packets should be preserved=0A=
           but otherwise ignored.  If the packet type is 0xf0 through=0A=
           0xff, it should be considered an error condition not to=0A=
           understand the packet.=0A=
=0A=
=0A=
                                     ###=0A=
=0A=