_                _   _                 ____            _     _ 	
   / \   _ __   ___ | |_| |__   ___ _ __  |  _ \ _ __ ___ (_) __| |	
  / _ \ | '_ \ / _ \| __| '_ \ / _ \ '__| | | | | '__/ _ \| |/ _\` |	
 / ___ \| | | | (_) | |_| | | |  __/ |    | |_| | | | (_) | | (_| |	
/_/   \_\_| |_|\___/ \__|_| |_|\___|_|    |____/|_|  \___/|_|\__,_|	
                                                                bbs
  XQTRs lair...
Home // Blog // NULL emag. // Files // Docs // Tutors // GitHub repo
Filename....: JAM-001
Rev.........: 001
Dated.......: 93-07-01
Status .....: Released
Subject.....: JAM message base proposal
Author......: Joaquim Homrighausen
Co-Authors..: Andrew Milner, Mats Birch, Mats Wallin

    ---------------------------------------------------------------------
                                  JAM(mbp)
                The Joaquim-Andrew-Mats Message Base Proposal
    ---------------------------------------------------------------------
            Copyright 1993 Joaquim Homrighausen, Andrew Milner,
                           Mats Birch, Mats Wallin.
                             ALL RIGHTS RESERVED.
    ---------------------------------------------------------------------

    =====================================================================
    Restrictions
    ---------------------------------------------------------------------
    JAM may be used by any developer as long as these specifications are
    followed exactly. JAM may be used free-of-charge by any developer
    for any purpose, commercially or otherwise.

    This document may be freely copied and distributed, but must NEVER be
    distributed in a modified form. If you have an enhancement request,
    please contact the author of this document; do not change it
    yourself.

    All applications that support JAM must include one of the following
    notices in their documentation and somewhere in the product's credit
    section:

    "JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner,
                               Mats Birch, Mats Wallin.
                               ALL RIGHTS RESERVED."

    or

    "This product uses the JAM(mbp) API -
     Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch,
                    Mats Wallin. ALL RIGHTS RESERVED."

    No organization, company, person, entity, or other being may impose
    any fees for any reason for providing this document or the
    accompanying API. This document and the accompanying API may not be
    sold or otherwise transferred for personal or company gain under any
    circumstances.

    =====================================================================
    Definitions and general notes
    ---------------------------------------------------------------------
    CURRENTREV                1

    JAM                       The JAM message base format.

    CRC                       Cyclic Redundancy Check. All CRC values
                              calculated on strings must assume that the
                              data within the string has been converted
                              to lowercase (A-Z = a-z).

    CRC-32                    32-bit CRC (as used in the Zmodem file
                              transfer protocol) value. The polynom for
                              a CRC-32 is edb88320H and the CRC-32 seed
                              is -1L (ffffffffH).

    uchar                     Unsigned 8-bit value

    ushort                    Unsigned 16-bit value

    ulong                     Unsigned 32-bit value

    UNIX date                 An ulong representing the number of seconds
                              since midnight, January 1, 1970. UNIX-style
                              dates is the only form of time stamps used
                              in JAM (1).

    Message #                 The physical record number within the index
                              file is used as a message number. The
                              lowest message number is one (1) and the
                              highest message number is 4294967295
                              (ffffffffH).

    FTN                       FidoNet Technology Network

    FTS                       FidoNet Technical Standard

    (1) All timestamps created locally (i.e. those not imported from
        other systems) are stored in local time.

    =====================================================================
    Files
    ---------------------------------------------------------------------
    Each conference is made up from four files. How and where these files
    are stored and named is implementation dependant. The only file with
    a fixed minimum size is the .JHR (header data) file. It has a 1024-
    byte block used to hold information about a specific message area as
    described later.

    filename.JHR - Message header data
    filename.JDT - Message text data
    filename.JDX - Message index
    filename.JLR - Lastread information

    A future revision of JAM may also include a file that holds the
    following three items:

      - The highest assigned user number
      - The last generated message ID
      - A global conference list with the conference name, description,
        and physical location of the message base.

    =====================================================================
    .JHR file header
    ---------------------------------------------------------------------
    Below is the format of the 1024-byte record at the beginning of all
    .JHR files. The first actual message header starts at offset 1024 in
    the .JHR file.

    FixedHeaderInfoStruct:
        ulong   Signature;       //  followed by 
        ulong   datecreated;     // Creation date
        ulong   modcounter;      // Update counter
        ulong   activemsgs;      // Number of active (not deleted) msgs
        ulong   passwordcrc;     // CRC-32 of password to access
        ulong   basemsgnum;      // Lowest message number in index file
        uchar   RESERVED[1000];  // Reserved space
    end;

    MODCOUNTER must be incremented and updated on disk each time an
    application modifies the contents of the message base. When it
    reaches ffffffffH, it wraps to zero.

    ---------------------------------------------------------------------
    BaseMsgNum                        Lowest message number in index file
    ---------------------------------------------------------------------
    This field determines the lowest message number in the index file.
    The value for this field is one (1) when a message area is first
    created. By using this field, a message area can be packed (deleted
    messages are removed) without renumbering it. If BaseMsgNum contains
    500, the first index record points to message number 500.

    BaseMsgNum has to be taken into account when an application
    calculates the next available message number (for creating new
    messages) as well as the highest and lowest message number in a
    message area.

    ---------------------------------------------------------------------
    ????????.JHR                                          Message headers
    ---------------------------------------------------------------------
    The .JHR file contains none or more Header records. Each record
    define one message and contains information about the message and its
    text (if any). The Header record is of variable length. The layout of
    the Header record follows.

    MessageHeader:
        MessageFixedHeader:
            ulong  Signature;    //  followed by 
            ushort Revision;     // Revision level of header          (1)
            ushort ReservedWord; // Reserved for future use
            ulong  SubfieldLen;  // Length of subfields               (2)
            ulong  TimesRead;    // Number of times message read
            ulong  MSGIDcrc;     // CRC-32 of MSGID line              (3)
            ulong  REPLYcrc;     // CRC-32 of REPLY line              (3)
            ulong  ReplyTo;      // This msg is a reply to..
            ulong  Reply1st;     // First reply to this msg
            ulong  Replynext;    // Next msg in reply chain
            ulong  DateWritten;  // When msg was written
            ulong  DateReceived; // When msg was read by recipient
            ulong  DateProcessed;// When msg was processed by tosser/
                                 // scanner
            ulong  MessageNumber;// Message number (1-based)
            ulong  Attribute;    // Msg attribute, see "Msg Attributes"
            ulong  Attribute2;   // Reserved for future use
            ulong  Offset;       // Offset of text in ????????.JDT file
            ulong  TxtLen;       // Length of message text
            ulong  PasswordCRC;  // CRC-32 of password to access message
            ulong  Cost;         // Cost of message
        end;
        SubField1                // Extra fields as defined below
        .
        .
        SubFieldXX
    end;

    (1) This field is intended for future revisions of the specifications
        to allow the use of a different fixed-length binary message
        header. The current revision level is one (1).

    (2) The SubfieldLen field is set to zero (0) if the header does not
        have any subfield data. I.e. the length of the binary header is
        not included in this field.

    (3) When calculating the CRC-32 of the MSGID and REPLY lines, the
        text ^aMSGID: and ^aREPLY: should be removed as well as all
        leading and trailing white space characters.

    The SubField structure is made up of an ID, a length specifier, and
    a block of data. Zero or more subfields may follow the fixed-length
    binary header. SubFields are not stored in any specific order and
    are not terminated by any specific character unless otherwise
    specified.

    SubField:
        ushort  LoID;            // Field ID, 0-65535
        ushort  HiID;            // Reserved for future use
        ulong   datlen;          // Length of buffer that follows
        uchar   Buffer[datlen];  // DATLEN bytes of data
    end;

    ---------------------------------------------------------------------
    Defined LoID codes
    ---------------------------------------------------------------------

    ID=0, Name=OADDRESS

    A network address. This is used to specify the originating address.
    More than one OADDRESS field may exist. DATLEN must not exceed 100
    characters. For a FidoNet-style address, this field must follow the
    ZONE:NET/NODE.POINT@DOMAIN format where .POINT is excluded if zero
    and @DOMAIN is excluded if unknown.

    ID=1, Name=DADDRESS

    A network address. This is used to specify the destination address.
    More than one DADDRESS field may exist (e.g. carbon copies). DATLEN
    must not exceed 100 characters. For a FidoNet-style address, this
    field must follow the ZONE:NET/NODE.POINT@DOMAIN format where .POINT
    is excluded if zero and @DOMAIN is excluded if unknown.

    ID=2, Name=SENDERNAME

    The sender (author) of the message. DATLEN must not exceed 100
    characters.

    ID=3, Name=RECEIVERNAME

    The recipient of the message. DATLEN must not exceed 100 characters.

    ID=4, Name=MSGID

    Used to store the message identification data. All data not relevant
    to the actual ID string, including leading and trailing white space
    characters should be removed. DATLEN must not exceed 100 characters.

    ID=5, Name=REPLYID

    Used to store the message reply data. All data not relevant to the
    actual reply string, including leading and trailing white space
    characters should be removed. DATLEN must not exceed 100 characters.

    ID=6, Name=SUBJECT

    The subject of the message. DATLEN must not exceed 100 characters.
    Note that this field may not be used for FidoNet-style file attaches
    or file requests.

    ID=7, Name=PID

    Used to store the FTN PID kludge line. Only the actual PID data is
    stored and ^aPID: is stripped along with any leading and trailing
    white space characters. DATLEN must not exceed 40 characters.

    ID=8, Name=TRACE

    This is also referred to as ^aVia information in FTNs. It contains
    information about a system which the message has travelled through.
    The format of the field is  where:

       YYYY is the year (1992-9999)
         MM is the month (01-12)
         DD is the day (01-31)
         HH is the hour (00-23)
         MM is the minute (00-59)
         SS is the second (00-59)

    The timestamp is stored in ASCII (0-9) characters. The network
    address is the address of the system. It is expressed in ASCII
    notation in the native format of the forwarding system.

    ID=9, Name=ENCLOSEDFILE

    A file attached to the message. Only one filename may be specified
    per subfield. No wildcard characters are allowed. If this subfield
    is present in a message header, the ATTRIBUTE must include the
    MSG_FILEATTACH bit.

    ID=10, Name=ENCLOSEDFILEWALIAS

    Identical to ENCLOSEDFILE with the exception that the filename is
    followed by a  (00H) and an alias filename to be transmited to
    the remote system in place of the local name of the file.

    ID=11, Name=ENCLOSEDFREQ

    A request for one or more files. Only one filemask may be specified
    per subfield. If the filemask contains a complete path, it is to be
    regarded as an update file request. If this subfield is present in a
    message header, the ATTRIBUTE must include the MSG_FILEREQUEST bit.
    To indicate that a password is to be transmitted along with the
    request, a  (00H) character followed by the password is
    appended. E.g. SECRET*.*MYPASSWORD.

    ID=12, Name=ENCLOSEDFILEWCARD

    One or more files attached to the message. Only one filename may be
    specified per subfield. Wildcard characters are allowed. If this
    subfield is present in a message header, the ATTRIBUTE must include
    the MSG_FILEATTACH bit.

    ID=13, Name=ENCLOSEDINDIRECTFILE

    One or more files attached to the message. The filename points to an
    ASCII file with one filename entry per line. If alias filenames are
    to be used, they are specified after the actual filename and
    separated by a  (00H) character, e.g. C:\MYFILE.LZHNEWS.
    Wildcard characters are not allowed.

    ID=1000, Name=EMBINDAT

    Reserved for future use.

    ID=2000, Name=FTSKLUDGE

    An FTS-compliant "kludge" line not otherwise represented here. All
    data not relevant to the actual kludge line, including leading and
    trailing white space and ^A (01H) characters should be removed.
    DATLEN must not exceed 255 characters. The FTS kludges INTL, TOPT,
    and FMPT must never be stored as separate SubFields. Their data must
    be extracted and used for the address SubFields.

    ID=2001, Name=SEENBY2D

    Used to store two-dimensional (net/node) SEEN-BY information often
    used in FTN conference environments. Only the actual SEEN-BY data is
    stored and ^aSEEN-BY: or SEEN-BY: is stripped along with any leading
    and trailing white space characters.

    ID=2002, Name=PATH2D

    Used to store two-dimensional (net/node) PATH information often used
    in FTN conference environments. Only the actual PATH data is stored
    and ^aPATH: is stripped along with any leading and trailing white
    space characters.

    ID=2003, Name=FLAGS

    Used to store the FTN FLAGS kludge information. Note that all FLAG
    options that have binary representation in the JAM message header
    must be removed from the FLAGS string prior to storing it. Only
    the actual flags option string is stored and ^aFLAGS is stripped
    along with any leading and trailing white space characters.

    ID=2004, Name=TZUTCINFO

    Time zone information. This subfield consists of four mandatory
    bytes and one optional. The first character may be a plus (+) or a
    minus (-) character to indicate a location east (plus) or west
    (minus) of UTC 0000. The plus character is implied unless the first
    character is a minus character. The following four bytes must be
    digits in the range zero through nine and indicates the offset in
    hours and minutes. E.g. 0100 indicates an offset of one hour east of
    UTC.

    ---------------------------------------------------------------------
    Message attributes
    ---------------------------------------------------------------------
    MSG_LOCAL       (0x00000001L)   // Msg created locally
    MSG_INTRANSIT   (0x00000002L)   // Msg is in-transit
    MSG_PRIVATE     (0x00000004L)   // Private
    MSG_READ        (0x00000008L)   // Read by addressee
    MSG_SENT        (0x00000010L)   // Sent to remote
    MSG_KILLSENT    (0x00000020L)   // Kill when sent
    MSG_ARCHIVESENT (0x00000040L)   // Archive when sent
    MSG_HOLD        (0x00000080L)   // Hold for pick-up
    MSG_CRASH       (0x00000100L)   // Crash
    MSG_IMMEDIATE   (0x00000200L)   // Send Msg now, ignore restrictions
    MSG_DIRECT      (0x00000400L)   // Send directly to destination
    MSG_GATE        (0x00000800L)   // Send via gateway
    MSG_FILEREQUEST (0x00001000L)   // File request
    MSG_FILEATTACH  (0x00002000L)   // File(s) attached to Msg
    MSG_TRUNCFILE   (0x00004000L)   // Truncate file(s) when sent
    MSG_KILLFILE    (0x00008000L)   // Delete file(s) when sent
    MSG_RECEIPTREQ  (0x00010000L)   // Return receipt requested
    MSG_CONFIRMREQ  (0x00020000L)   // Confirmation receipt requested
    MSG_ORPHAN      (0x00040000L)   // Unknown destination
    MSG_ENCRYPT     (0x00080000L)   // Msg text is encrypted          (1)
    MSG_COMPRESS    (0x00100000L)   // Msg text is compressed         (1)
    MSG_ESCAPED     (0x00200000L)   // Msg text is seven bit ASCII    (1)
    MSG_FPU         (0x00400000L)   // Force pickup
    MSG_TYPELOCAL   (0x00800000L)   // Msg is for local use only
    MSG_TYPEECHO    (0x01000000L)   // Msg is for conference distribution
    MSG_TYPENET     (0x02000000L)   // Msg is direct network mail
    MSG_NODISP      (0x20000000L)   // Msg may not be displayed to user
    MSG_LOCKED      (0x40000000L)   // Msg is locked, no editing possible
    MSG_DELETED     (0x80000000L)   // Msg is deleted

    (1) This revision of JAM does not include compression, encryption, or
        escaping. The bits are reserved for future use.

    =====================================================================
    ????????.JDT                                             Message text
    ---------------------------------------------------------------------
    The .JDT file contains the text of messages. The text is stored as an
    stream of seven or eight bit ASCII data. Allowed characters in the
    text are 00H through ffH unless the header ATTRIBUTE field has the
    MSG_ESCAPED bit enabled, in which case the legal range of data is 20H
    through 7eH.

    An escaped character is stored as \ where  is the two digit
    hexadecimal ASCII value of the character. A single \ is stored as \\
    or \5C. The case of the hexadecimal ASCII value is irrelevant, i.e.
    5c is treated as 5C.

    =====================================================================
    ????????.JDX                                            Message index
    ---------------------------------------------------------------------
    The .JDX file is used to quickly locate messages for any given user
    name or to locate a message with a specific number. Each record in
    the file consists of two ulongs. The first ulong holds the CRC-32 of
    the recipient's name (lowercase), the second ulong holds the
    physical offset of the message header in the .JHR (header) file.

    The record number (+BaseMsgNum) within the .JDX file determines a
    message's number.

    If both ulongs are -1 (ffffffffH), there is no corresponding message
    header.

    =====================================================================
    ????????.JLR                                         Lastread storage
    ---------------------------------------------------------------------
    The .JLR file is used to maintain a user's position within a message
    area. The layout of the "lastread" record follows. One record per
    user is required.

    LastRead:
        ulong   UserCRC;         // CRC-32 of user name (lowercase)   (1)
        ulong   UserID;          // Unique UserID
        ulong   LastReadMsg;     // Last read message number
        ulong   HighReadMsg;     // Highest read message number
    end;

    (1) The functions to convert a string to lowercase characters that
        are provided in the API will only convert characters A-Z (into
        a-z). It is required that this convention is followed by all
        applications.

    The UserID field is a unique number for each user. If the "lastread"
    record is deleted, UserCRC and UserID are both set to -1
    (ffffffffH). An application may not depend on any specific order in
    the .JLR file. A user's "lastread" record may appear anywhere in the
    file and must be searched for when retrieving it and when storing an
    updated record.

    =====================================================================
    Updating message headers
    ---------------------------------------------------------------------
    If a header record grows after is has been retrieved from the .JHR
    file, it must be appended to the end of the .JHR file since it would
    overwrite the following header otherwise. The .JDX file must be
    properly updated to indicate the new location of the header record.
    The old header record must be changed to indicate that it has been
    deleted by setting the MSG_DELETED bit in the Attribute field and the
    TextLen field to zero (to prevent a maintenance program from removing
    the message text that is now pointed to by another header).

    =====================================================================
    Message base sharing and locking
    ---------------------------------------------------------------------
    To allow several programs to access the message base at any given
    time, region locking is used to protect the message base from being
    corrupted during updates.

    When an application needs to write to any of the message base files,
    it must first attempt to lock the first byte of the .JHR (header)
    file. If the lock call fails, the application must either fail or
    attempt to lock the file again. The message base files may under no
    circumstances be updated if the application cannot successfully lock
    the .JHR file.

    Note that data acquired (read) from the message base may not be used
    when writing data to the message base, unless the application has
    maintained a lock of the message base from the time the data was
    acquired or the MODCOUNTER field is the same as when the data was
    acquired.

    The application must open the files in shareable (DENYNONE) read/
    write or readonly mode. The only exception to this is an application
    that requires exclusive access to the message base, such as a message
    base maintenance utility, it should open the files in non-shareable
    (DENYALL) read/write mode.

    =====================================================================
    Reply threads and linking
    ---------------------------------------------------------------------
    JAM introduces a new reply link pointer, not commonly used today.
    This section is an attempt to describe how reply threads, reply
    linking, and this new reply link pointer is implemented in JAM.

    One of the major differences is that reply threads in JAM are not
    based on similar or identical subjects of messages since this method
    does not allow for proper reply threads.

    The method used in JAM is based on the immediate relation between any
    given message and direct replies to it. This is supported by many
    message editors by using the MSGID and REPLY FTS kludge fields. These
    are common, although expressed differently, in messages not based on
    FidoNet technology, such as RFC-822. The obvious advantages include
    allowing a program to easily find the original message to a reply,
    and to find all replies to any given message.

    The reply thread information consists of three fields: ReplyTo,
    Reply1st, and ReplyNext. The reason for three fields, as opposed to
    just two, is that with two fields, it is only possible to keep track
    of the original message of a reply (which is sufficient) and one
    reply to any given message (which is not sufficient). With three
    fields, it is possible to maintain a thread of any number of replies
    to any given message.

    In the description of the different fields below, the following
    messages and message numbers will be referred to:

      1 -> 2 -> 4 -> 5
      :    :
      :    +--> 8
      :
      +--> 3 -> 7
      :
      +--> 6

    Message number two, three, and six are replies to message number one.
    Message number four and eight are replies to message number two.
    Message number seven is a reply to message number three.
    Message number five is a reply to message number four.

    ---------------------------------------------------------------------
    ReplyTo
    ---------------------------------------------------------------------
    This field holds the number of the message that this message is a
    reply to. In the example above, the ReplyTo field would contain the
    following values:

    Message number one would contain zero; message number two, three, and
    six, would contain one; message number four and eight would contain
    two; message number seven would contain three, and message number
    five would contain four.

    ---------------------------------------------------------------------
    Reply1st
    ---------------------------------------------------------------------
    This field holds the number of the first message that is a reply to
    this message. In the example above, the Reply1st field would contain
    the following values:

    Message number one would contain two, message number three would
    contain seven, and message number four would contain five. All other
    messages would contain zero.

    ---------------------------------------------------------------------
    ReplyNext
    ---------------------------------------------------------------------
    This field is used to create the actual message thread or chain. In
    the event that there is more than one reply to any given message, it
    is necessary to maintain a thread of all the replies; this is due to
    the fact that the original message can only hold information about
    the first reply (the Reply1st field) to it.

    The first reply (which the original message's Reply1st field holds),
    has its ReplyNext field pointing to the second reply, the second
    reply's ReplyNext field poinst to the third reply, and so on.

    In the example above, the ReplyNext field would contain the following
    values:

    Message number two would contain three, message number three would
    contain six, and message number four would contain eight. All other
    messages would contain zero.

    =====================================================================
    Contacts
    ---------------------------------------------------------------------
    Joaquim Homrighausen

    Andrew Milner

    Mats Wallin

    // end of file "jam.doc"