home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / lora299s.zip / JAM.CPP < prev    next >
C/C++ Source or Header  |  1998-05-12  |  34KB  |  1,028 lines

  1.  
  2. // LoraBBS Version 2.99 Free Edition
  3. // Copyright (C) 1987-98 Marco Maccaferri
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #include "_ldefs.h"
  20. #include "msgbase.h"
  21.  
  22. #define MAX_TEXT     2048
  23.  
  24. JAM::JAM (void)
  25. {
  26.    fdHdr = fdJdt = fdJdx = -1;
  27.    pSubfield = NULL;
  28.    Current = Id = 0L;
  29. }
  30.  
  31. JAM::JAM (PSZ pszName)
  32. {
  33.    fdHdr = fdJdt = fdJdx = -1;
  34.    pSubfield = NULL;
  35.    Current = Id = 0L;
  36.  
  37.    Open (pszName);
  38. }
  39.  
  40. JAM::~JAM (void)
  41. {
  42.    Close ();
  43. }
  44.  
  45. USHORT JAM::Add (VOID)
  46. {
  47.    return (Add (Text));
  48. }
  49.  
  50. USHORT JAM::Add (class TMsgBase *MsgBase)
  51. {
  52.    New ();
  53.  
  54.    strcpy (From, MsgBase->From);
  55.    strcpy (To, MsgBase->To);
  56.    strcpy (Subject, MsgBase->Subject);
  57.  
  58.    strcpy (FromAddress, MsgBase->FromAddress);
  59.    strcpy (ToAddress, MsgBase->ToAddress);
  60.  
  61.    Written.Day = MsgBase->Written.Day;
  62.    Written.Month = MsgBase->Written.Month;
  63.    Written.Year = MsgBase->Written.Year;
  64.    Written.Hour = MsgBase->Written.Hour;
  65.    Written.Minute = MsgBase->Written.Minute;
  66.    Written.Second = MsgBase->Written.Second;
  67.  
  68.    Arrived.Day = MsgBase->Arrived.Day;
  69.    Arrived.Month = MsgBase->Arrived.Month;
  70.    Arrived.Year = MsgBase->Arrived.Year;
  71.    Arrived.Hour = MsgBase->Arrived.Hour;
  72.    Arrived.Minute = MsgBase->Arrived.Minute;
  73.    Arrived.Second = MsgBase->Arrived.Second;
  74.  
  75.    Reply = MsgBase->Reply;
  76.    Original = MsgBase->Original;
  77.  
  78.    Crash = MsgBase->Crash;
  79.    Direct = MsgBase->Direct;
  80.    FileAttach = MsgBase->FileAttach;
  81.    FileRequest = MsgBase->FileRequest;
  82.    Hold = MsgBase->Hold;
  83.    Immediate = MsgBase->Immediate;
  84.    Intransit = MsgBase->Intransit;
  85.    KillSent = MsgBase->KillSent;
  86.    Local = MsgBase->Local;
  87.    Private = MsgBase->Private;
  88.    ReceiptRequest = MsgBase->ReceiptRequest;
  89.    Received = MsgBase->Received;
  90.    Sent = MsgBase->Sent;
  91.  
  92.    return (Add (MsgBase->Text));
  93. }
  94.  
  95. USHORT JAM::Add (class TCollection &MsgText)
  96. {
  97.    USHORT RetVal = FALSE;
  98.    ULONG ulMsg = Highest () + 1L;
  99.    PSZ pszText, pszSign = HEADERSIGNATURE;
  100.    JAMIDXREC jamIdx;
  101.    JAMSUBFIELD jamSubfield;
  102.    struct tm mktm;
  103.  
  104.    RetVal = TRUE;
  105.  
  106.    memset (&jamHdr, 0, sizeof (JAMHDR));
  107.    jamHdr.Signature[0] = pszSign[0];
  108.    jamHdr.Signature[1] = pszSign[1];
  109.    jamHdr.Signature[2] = pszSign[2];
  110.    jamHdr.Signature[3] = pszSign[3];
  111.    jamHdr.Revision = CURRENTREVLEV;
  112.    jamHdr.MsgNum = ulMsg;
  113.  
  114.    mktm.tm_year = Written.Year - 1900;
  115.    mktm.tm_mon = Written.Month - 1;
  116.    mktm.tm_mday = Written.Day;
  117.    mktm.tm_hour = Written.Hour;
  118.    mktm.tm_min = Written.Minute;
  119.    mktm.tm_sec = Written.Second;
  120.    mktm.tm_wday = 0;
  121.    mktm.tm_yday = 0;
  122.    mktm.tm_isdst = 0;
  123.    jamHdr.DateWritten = mktime (&mktm);
  124.  
  125.    mktm.tm_year = Arrived.Year - 1900;
  126.    mktm.tm_mon = Arrived.Month - 1;
  127.    mktm.tm_mday = Arrived.Day;
  128.    mktm.tm_hour = Arrived.Hour;
  129.    mktm.tm_min = Arrived.Minute;
  130.    mktm.tm_sec = Arrived.Second;
  131.    mktm.tm_wday = 0;
  132.    mktm.tm_yday = 0;
  133.    mktm.tm_isdst = 0;
  134.    jamHdr.DateProcessed = mktime (&mktm);
  135.  
  136.    jamHdr.Attribute |= (Crash == TRUE) ? MSG_CRASH : 0;
  137.    jamHdr.Attribute |= (Direct == TRUE) ? MSG_DIRECT : 0;
  138.    jamHdr.Attribute |= (FileAttach == TRUE) ? MSG_FILEATTACH : 0;
  139.    jamHdr.Attribute |= (FileRequest == TRUE) ? MSG_FILEREQUEST : 0;
  140.    jamHdr.Attribute |= (Hold == TRUE) ? MSG_HOLD : 0;
  141.    jamHdr.Attribute |= (Immediate == TRUE) ? MSG_IMMEDIATE : 0;
  142.    jamHdr.Attribute |= (Intransit == TRUE) ? MSG_INTRANSIT : 0;
  143.    jamHdr.Attribute |= (KillSent == TRUE) ? MSG_KILLSENT : 0;
  144.    jamHdr.Attribute |= (Local == TRUE) ? MSG_LOCAL : 0;
  145.    jamHdr.Attribute |= (Private == TRUE) ? MSG_PRIVATE : 0;
  146.    jamHdr.Attribute |= (ReceiptRequest == TRUE) ? MSG_RECEIPTREQ : 0;
  147.    jamHdr.Attribute |= (Received == TRUE) ? MSG_READ : 0;
  148.    jamHdr.Attribute |= (Sent == TRUE) ? MSG_SENT : 0;
  149.  
  150.    jamHdr.ReplyTo = Original;
  151.    jamHdr.ReplyNext = Reply;
  152.  
  153.    lseek (fdHdr, 0L, SEEK_END);
  154.  
  155.    jamIdx.UserCRC = 0;
  156.    jamIdx.HdrOffset = tell (fdHdr);
  157.    lseek (fdJdx, 0L, SEEK_END);
  158.    write (fdJdx, &jamIdx, sizeof (JAMIDXREC));
  159.  
  160.    write (fdHdr, &jamHdr, sizeof (JAMHDR));
  161.  
  162.    jamSubfield.HiID = 0;
  163.    jamSubfield.LoID = JAMSFLD_SENDERNAME;
  164.    jamSubfield.DatLen = strlen (From) + 1;
  165.    jamHdr.SubfieldLen += jamSubfield.DatLen + sizeof (JAMBINSUBFIELD);
  166.    write (fdHdr, &jamSubfield, sizeof (JAMBINSUBFIELD));
  167.    write (fdHdr, From, strlen (From) + 1);
  168.    if (To[0]) {
  169.       jamSubfield.LoID = JAMSFLD_RECVRNAME;
  170.       jamSubfield.DatLen = strlen (To) + 1;
  171.       jamHdr.SubfieldLen += jamSubfield.DatLen + sizeof (JAMBINSUBFIELD);
  172.       write (fdHdr, &jamSubfield, sizeof (JAMBINSUBFIELD));
  173.       write (fdHdr, To, strlen (To) + 1);
  174.    }
  175.    jamSubfield.LoID = JAMSFLD_SUBJECT;
  176.    jamSubfield.DatLen = strlen (Subject) + 1;
  177.    jamHdr.SubfieldLen += jamSubfield.DatLen + sizeof (JAMBINSUBFIELD);
  178.    write (fdHdr, &jamSubfield, sizeof (JAMBINSUBFIELD));
  179.    write (fdHdr, Subject, strlen (Subject) + 1);
  180.    if (FromAddress[0] != '\0') {
  181.       jamSubfield.LoID = JAMSFLD_OADDRESS;
  182.       jamSubfield.DatLen = strlen (FromAddress) + 1;
  183.       jamHdr.SubfieldLen += jamSubfield.DatLen + sizeof (JAMBINSUBFIELD);
  184.       write (fdHdr, &jamSubfield, sizeof (JAMBINSUBFIELD));
  185.       write (fdHdr, FromAddress, strlen (FromAddress) + 1);
  186.    }
  187.    if (ToAddress[0] != '\0') {
  188.       jamSubfield.LoID = JAMSFLD_DADDRESS;
  189.       jamSubfield.DatLen = strlen (ToAddress) + 1;
  190.       jamHdr.SubfieldLen += jamSubfield.DatLen + sizeof (JAMBINSUBFIELD);
  191.       write (fdHdr, &jamSubfield, sizeof (JAMBINSUBFIELD));
  192.       write (fdHdr, ToAddress, strlen (ToAddress) + 1);
  193.    }
  194.  
  195.    lseek (fdHdr, 0L, SEEK_SET);
  196.    read (fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO));
  197.    jamHdrInfo.ActiveMsgs++;
  198.    lseek (fdHdr, 0L, SEEK_SET);
  199.    write (fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO));
  200.  
  201.    lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  202.    write (fdHdr, &jamHdr, sizeof (JAMHDR));
  203.  
  204.    if (RetVal == TRUE) {
  205.       Id = jamHdr.MsgNum;
  206.  
  207.       lseek (fdJdt, 0L, SEEK_END);
  208.       jamHdr.TxtOffset = tell (fdJdt);
  209.       jamHdr.TxtLen = 0;
  210.  
  211.       if ((pszText = (PSZ)MsgText.First ()) != NULL)
  212.          do {
  213.             write (fdJdt, pszText, strlen (pszText));
  214.             jamHdr.TxtLen += strlen (pszText);
  215.             write (fdJdt, "\r\n", 2);
  216.             jamHdr.TxtLen += 2;
  217.          } while ((pszText = (PSZ)MsgText.Next ()) != NULL);
  218.  
  219.       lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  220.       write (fdHdr, &jamHdr, sizeof (JAMHDR));
  221.  
  222.       WriteHeader (ulMsg);
  223.    }
  224.  
  225.    return (RetVal);
  226. }
  227.  
  228. VOID JAM::Close (VOID)
  229. {
  230.    if (fdJdx != -1)
  231.       close (fdJdx);
  232.    if (fdJdt != -1)
  233.       close (fdJdt);
  234.    if (fdHdr != -1)
  235.       close (fdHdr);
  236.  
  237.    if (pSubfield != NULL)
  238.       free (pSubfield);
  239.  
  240.    fdHdr = fdJdt = fdJdx = -1;
  241.    pSubfield = NULL;
  242.    Id = 0L;
  243. }
  244.  
  245. USHORT JAM::Delete (ULONG ulMsg)
  246. {
  247.    USHORT RetVal = FALSE;
  248.    JAMIDXREC jamIdx;
  249.  
  250.    if (ReadHeader (ulMsg) == TRUE) {
  251.       jamHdr.Attribute |= MSG_DELETED;
  252.  
  253.       lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET);
  254.       if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  255.          lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  256.          write (fdHdr, &jamHdr, sizeof (JAMHDR));
  257.  
  258.          lseek (fdHdr, 0L, SEEK_SET);
  259.          read (fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO));
  260.          jamHdrInfo.ActiveMsgs--;
  261.          lseek (fdHdr, 0L, SEEK_SET);
  262.          write (fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO));
  263.          RetVal = TRUE;
  264.       }
  265.    }
  266.  
  267.    return (RetVal);
  268. }
  269.  
  270. USHORT JAM::GetHWM (ULONG &ulMsg)
  271. {
  272.    ulMsg = 0L;
  273.  
  274.    return (FALSE);
  275. }
  276.  
  277. ULONG JAM::Highest (VOID)
  278. {
  279.    ULONG RetVal = 0L;
  280.    JAMIDXREC jamIdx;
  281.  
  282.    if (jamHdrInfo.ActiveMsgs > 0L) {
  283.       lseek (fdJdx, filelength (fdJdx) - sizeof (jamIdx), SEEK_SET);
  284.       if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  285.          lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  286.          read (fdHdr, &jamHdr, sizeof (JAMHDR));
  287.          RetVal = jamHdr.MsgNum;
  288.       }
  289.    }
  290.  
  291.    Id = RetVal;
  292.  
  293.    return (RetVal);
  294. }
  295.  
  296. USHORT JAM::Lock (ULONG ulTimeout)
  297. {
  298.    ulTimeout = ulTimeout;
  299.    return (TRUE);
  300. }
  301.  
  302. ULONG JAM::Lowest (VOID)
  303. {
  304.    ULONG RetVal = 0L;
  305.    JAMIDXREC jamIdx;
  306.  
  307.    if (jamHdrInfo.ActiveMsgs > 0L) {
  308.       lseek (fdJdx, 0L, SEEK_SET);
  309.       if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  310.          lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  311.          read (fdHdr, &jamHdr, sizeof (JAMHDR));
  312.          RetVal = jamHdr.MsgNum;
  313.       }
  314.    }
  315.  
  316.    Id = RetVal;
  317.  
  318.    return (RetVal);
  319. }
  320.  
  321. ULONG JAM::MsgnToUid (ULONG ulMsg)
  322. {
  323.    ULONG i = 1L;
  324.    JAMIDXREC jamIdx;
  325.  
  326.    if (fdJdx != -1 && fdHdr != -1 && ulMsg > 0L && ulMsg <= jamHdrInfo.ActiveMsgs) {
  327.       lseek (fdJdx, 0L, SEEK_SET);
  328.       while (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  329.          lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  330.          read (fdHdr, &jamHdr, sizeof (JAMHDR));
  331.          if (!(jamHdr.Attribute & MSG_DELETED)) {
  332.             if (i == ulMsg) {
  333.                ulMsg = jamHdr.MsgNum;
  334.                break;
  335.             }
  336.             i++;
  337.          }
  338.       }
  339.    }
  340.  
  341.    if (jamHdrInfo.ActiveMsgs == 0L)
  342.       ulMsg = 0L;
  343.  
  344.    return (ulMsg);
  345. }
  346.  
  347. VOID JAM::New (VOID)
  348. {
  349.    From[0] = To[0] = Subject[0] = '\0';
  350.    Crash = Direct = FileAttach = FileRequest = Hold = Immediate = FALSE;
  351.    Intransit = KillSent = Local = Private = ReceiptRequest = Received = FALSE;
  352.    Sent = 0;
  353.    memset (&Written, 0, sizeof (Written));
  354.    memset (&Arrived, 0, sizeof (Arrived));
  355.    FromAddress[0] = ToAddress[0] = '\0';
  356.    Original = Reply = 0L;
  357.    Text.Clear ();
  358. }
  359.  
  360. USHORT JAM::Next (ULONG &ulMsg)
  361. {
  362.    USHORT RetVal = FALSE, MayBeNext = FALSE;
  363.    JAMIDXREC jamIdx;
  364.  
  365.    if (jamHdrInfo.ActiveMsgs > 0L) {
  366. // --------------------------------------------------------------------
  367. // The first attempt to retrive the next message number suppose that
  368. // the file pointers are located after the current message number.
  369. // Usually this is the 99% of the situations because the messages are
  370. // often readed sequentially.
  371. // --------------------------------------------------------------------
  372.       if (tell (fdJdx) >= sizeof (jamIdx))
  373.          lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET);
  374.       do {
  375.          if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  376.             lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  377.             read (fdHdr, &jamHdr, sizeof (JAMHDR));
  378.             if (MayBeNext == TRUE) {
  379.                if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum > ulMsg) {
  380.                   ulMsg = jamHdr.MsgNum;
  381.                   RetVal = TRUE;
  382.                }
  383.             }
  384.             if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg)
  385.                MayBeNext = TRUE;
  386.          }
  387.       } while (RetVal == FALSE && tell (fdJdx) < filelength (fdJdx));
  388.  
  389.       if (RetVal == FALSE && MayBeNext == FALSE) {
  390. // --------------------------------------------------------------------
  391. // It seems that the file pointers are not located where they should be
  392. // so our next attempt is to scan the database from the beginning to
  393. // find the next message number.
  394. // --------------------------------------------------------------------
  395.          lseek (fdJdx, 0L, SEEK_SET);
  396.          do {
  397.             if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  398.                lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  399.                read (fdHdr, &jamHdr, sizeof (JAMHDR));
  400.                if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum > ulMsg) {
  401.                   ulMsg = jamHdr.MsgNum;
  402.                   RetVal = TRUE;
  403.                }
  404.             }
  405.          } while (RetVal == FALSE && tell (fdJdx) < filelength (fdJdx));
  406.       }
  407.  
  408.       Id = 0L;
  409.       if (RetVal == TRUE)
  410.          Id = ulMsg;
  411.    }
  412.  
  413.    return (RetVal);
  414. }
  415.  
  416. ULONG JAM::Number (VOID)
  417. {
  418.    return (jamHdrInfo.ActiveMsgs);
  419. }
  420.  
  421. USHORT JAM::Open (PSZ pszName)
  422. {
  423.    USHORT RetVal = FALSE;
  424.    CHAR File[128];
  425.    PSZ Signature = HEADERSIGNATURE;
  426.  
  427.    sprintf (File, "%s%s", pszName, EXT_HDRFILE);
  428.    if ((fdHdr = sopen (File, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  429.       if (read (fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)) != sizeof (JAMHDRINFO)) {
  430.          memset (&jamHdrInfo, 0, sizeof (JAMHDRINFO));
  431.          jamHdrInfo.Signature[0] = Signature[0];
  432.          jamHdrInfo.Signature[1] = Signature[1];
  433.          jamHdrInfo.Signature[2] = Signature[2];
  434.          jamHdrInfo.Signature[3] = Signature[3];
  435.          jamHdrInfo.DateCreated = time (NULL);
  436.          jamHdrInfo.BaseMsgNum = 1;
  437.  
  438.          lseek (fdHdr, 0L, SEEK_SET);
  439.          write (fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO));
  440.       }
  441.  
  442.       if (jamHdrInfo.Signature[0] == Signature[0] && jamHdrInfo.Signature[1] == Signature[1] && jamHdrInfo.Signature[2] == Signature[2] && jamHdrInfo.Signature[3] == Signature[3]) {
  443.          sprintf (File, "%s%s", pszName, EXT_TXTFILE);
  444.          fdJdt = sopen (File, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  445.          sprintf (File, "%s%s", pszName, EXT_IDXFILE);
  446.          fdJdx = sopen (File, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  447.          RetVal = TRUE;
  448.  
  449.          strcpy (BaseName, pszName);
  450.       }
  451.       else {
  452.          close (fdHdr);
  453.          fdHdr = -1;
  454.       }
  455.    }
  456.    else
  457.       memset (&jamHdrInfo, 0, sizeof (JAMHDRINFO));
  458.  
  459.    Id = 0L;
  460.  
  461.    return (RetVal);
  462. }
  463.  
  464. VOID JAM::Pack (VOID)
  465. {
  466.    int fdnHdr, fdnJdx, fdnJdt;
  467.    USHORT ToRead, Readed;
  468.    CHAR File[128], New[128], *Subfield, *Temp;
  469.    JAMIDXREC jamIdx;
  470.  
  471.    sprintf (File, "%s%s", BaseName, ".$dr");
  472.    fdnHdr = sopen (File, O_RDWR|O_BINARY|O_CREAT|O_TRUNC, SH_DENYNO, S_IREAD|S_IWRITE);
  473.    sprintf (File, "%s%s", BaseName, ".$dt");
  474.    fdnJdt = sopen (File, O_RDWR|O_BINARY|O_CREAT|O_TRUNC, SH_DENYNO, S_IREAD|S_IWRITE);
  475.    sprintf (File, "%s%s", BaseName, ".$dx");
  476.    fdnJdx = sopen (File, O_RDWR|O_BINARY|O_CREAT|O_TRUNC, SH_DENYNO, S_IREAD|S_IWRITE);
  477.  
  478.    if (fdnHdr != -1 && fdnJdt != -1 && fdnJdx != -1) {
  479.       lseek (fdHdr, 0L, SEEK_SET);
  480.       if (read (fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)) == sizeof (JAMHDRINFO)) {
  481.          write (fdnHdr, &jamHdrInfo, sizeof (JAMHDRINFO));
  482.          while (read (fdHdr, &jamHdr, sizeof (JAMHDR)) == sizeof (JAMHDR)) {
  483.             if (jamHdr.Attribute & MSG_DELETED) {
  484.                if (jamHdr.SubfieldLen > 0L)
  485.                   lseek (fdHdr, jamHdr.SubfieldLen, SEEK_CUR);
  486.             }
  487.             else {
  488.                jamIdx.UserCRC = 0;
  489.                jamIdx.HdrOffset = tell (fdnHdr);
  490.                write (fdnJdx, &jamIdx, sizeof (JAMIDXREC));
  491.  
  492.                lseek (fdJdt, jamHdr.TxtOffset, SEEK_SET);
  493.                jamHdr.TxtOffset = tell (fdnJdt);
  494.                write (fdnHdr, &jamHdr, sizeof (JAMHDR));
  495.  
  496.                if (jamHdr.SubfieldLen > 0L) {
  497.                   if ((Subfield = (CHAR *)malloc ((size_t)(jamHdr.SubfieldLen + 1))) != NULL) {
  498.                      read (fdHdr, Subfield, (size_t)jamHdr.SubfieldLen);
  499.                      write (fdnHdr, Subfield, (size_t)jamHdr.SubfieldLen);
  500.                      free (Subfield);
  501.                   }
  502.                }
  503.  
  504.                if ((Temp = (CHAR *)malloc (MAX_TEXT)) != NULL) {
  505.                   do {
  506.                      if ((ToRead = MAX_TEXT) > jamHdr.TxtLen)
  507.                         ToRead = (USHORT)jamHdr.TxtLen;
  508.                      Readed = (USHORT)read (fdJdt, Temp, ToRead);
  509.                      write (fdnJdt, Temp, Readed);
  510.                      jamHdr.TxtLen -= Readed;
  511.                   } while (jamHdr.TxtLen > 0);
  512.                   free (Temp);
  513.                }
  514.             }
  515.          }
  516.       }
  517.  
  518.       close (fdnHdr);
  519.       close (fdnJdt);
  520.       close (fdnJdx);
  521.       fdnHdr = fdnJdt = fdnJdx = -1;
  522.  
  523.       close (fdHdr);
  524.       close (fdJdt);
  525.       close (fdJdx);
  526.       fdHdr = fdJdt = fdJdx = -1;
  527.  
  528.       sprintf (File, "%s%s", BaseName, ".$dr");
  529.       sprintf (New, "%s%s", BaseName, EXT_HDRFILE);
  530.       unlink (New);
  531.       rename (File, New);
  532.       sprintf (File, "%s%s", BaseName, ".$dt");
  533.       sprintf (New, "%s%s", BaseName, EXT_TXTFILE);
  534.       unlink (New);
  535.       rename (File, New);
  536.       sprintf (File, "%s%s", BaseName, ".$dx");
  537.       sprintf (New, "%s%s", BaseName, EXT_IDXFILE);
  538.       unlink (New);
  539.       rename (File, New);
  540.  
  541.       Open (BaseName);
  542.    }
  543.  
  544.    if (fdnHdr != -1)
  545.       close (fdnHdr);
  546.    sprintf (File, "%s%s", BaseName, ".$dr");
  547.    unlink (File);
  548.    if (fdnJdt != -1)
  549.       close (fdnJdt);
  550.    sprintf (File, "%s%s", BaseName, ".$dt");
  551.    unlink (File);
  552.    if (fdnJdx != -1)
  553.       close (fdnJdx);
  554.    sprintf (File, "%s%s", BaseName, ".$dx");
  555.    unlink (File);
  556. }
  557.  
  558. USHORT JAM::Previous (ULONG &ulMsg)
  559. {
  560.    USHORT RetVal = FALSE, MayBeNext = FALSE;
  561.    LONG Pos;
  562.    JAMIDXREC jamIdx;
  563.  
  564.    if (jamHdrInfo.ActiveMsgs > 0L) {
  565. // --------------------------------------------------------------------
  566. // The first attempt to retrive the next message number suppose that
  567. // the file pointers are located after the current message number.
  568. // Usually this is the 99% of the situations because the messages are
  569. // often readed sequentially.
  570. // --------------------------------------------------------------------
  571.       if (tell (fdJdx) >= sizeof (jamIdx)) {
  572.          Pos = tell (fdJdx) - sizeof (jamIdx);
  573.          do {
  574.             lseek (fdJdx, Pos, SEEK_SET);
  575.             if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  576.                lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  577.                read (fdHdr, &jamHdr, sizeof (JAMHDR));
  578.                if (MayBeNext == TRUE) {
  579.                   if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum < ulMsg) {
  580.                      ulMsg = jamHdr.MsgNum;
  581.                      RetVal = TRUE;
  582.                   }
  583.                }
  584.                if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg)
  585.                   MayBeNext = TRUE;
  586.             }
  587.             Pos -= sizeof (jamIdx);
  588.          } while (RetVal == FALSE && Pos >= 0L);
  589.       }
  590.  
  591.       if (RetVal == FALSE && MayBeNext == FALSE) {
  592. // --------------------------------------------------------------------
  593. // It seems that the file pointers are not located where they should be
  594. // so our next attempt is to scan the database from the end to find
  595. // the next message number.
  596. // --------------------------------------------------------------------
  597.          Pos = filelength (fdJdx) - sizeof (jamIdx);
  598.          do {
  599.             lseek (fdJdx, Pos, SEEK_SET);
  600.             if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  601.                lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  602.                read (fdHdr, &jamHdr, sizeof (JAMHDR));
  603.                if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum < ulMsg) {
  604.                   ulMsg = jamHdr.MsgNum;
  605.                   RetVal = TRUE;
  606.                }
  607.             }
  608.             Pos -= sizeof (jamIdx);
  609.          } while (RetVal == FALSE && Pos >= 0L);
  610.       }
  611.  
  612.       Id = 0L;
  613.       if (RetVal == TRUE)
  614.          Id = ulMsg;
  615.    }
  616.  
  617.    return (RetVal);
  618. }
  619.  
  620. USHORT JAM::ReadHeader (ULONG ulMsg)
  621. {
  622.    USHORT RetVal = FALSE;
  623.    UCHAR *pPos;
  624.    ULONG ulSubfieldLen;
  625.    struct tm *local;
  626.    JAMIDXREC jamIdx;
  627.    JAMBINSUBFIELD *jamSubField;
  628.  
  629.    New ();
  630.  
  631.    if (Id == ulMsg) {
  632. // --------------------------------------------------------------------
  633. // The user is requesting the header of the last message retrived
  634. // so our first attempt is to read the last index from the file and
  635. // check if this is the correct one.
  636. // --------------------------------------------------------------------
  637.       lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET);
  638.       if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  639.          lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  640.          read (fdHdr, &jamHdr, sizeof (JAMHDR));
  641.          if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg)
  642.             RetVal = TRUE;
  643.       }
  644.    }
  645.  
  646.    if (RetVal == FALSE) {
  647. // --------------------------------------------------------------------
  648. // The message request is not the last retrived or the file pointers
  649. // are not positioned where they should be, so now we attempt to
  650. // retrive the message header scanning the database from the beginning.
  651. // --------------------------------------------------------------------
  652.       Id = 0L;
  653.       lseek (fdJdx, 0L, SEEK_SET);
  654.       do {
  655.          if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  656.             lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  657.             read (fdHdr, &jamHdr, sizeof (JAMHDR));
  658.             if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg)
  659.                RetVal = TRUE;
  660.          }
  661.       } while (RetVal == FALSE && tell (fdJdx) < filelength (fdJdx));
  662.    }
  663.  
  664.    if (RetVal == TRUE) {
  665.       Current = Id = ulMsg;
  666.       Crash = (UCHAR)((jamHdr.Attribute & MSG_CRASH) ? TRUE : FALSE);
  667.       Direct = (UCHAR)((jamHdr.Attribute & MSG_DIRECT) ? TRUE : FALSE);
  668.       FileAttach = (UCHAR)((jamHdr.Attribute & MSG_FILEATTACH) ? TRUE : FALSE);
  669.       FileRequest = (UCHAR)((jamHdr.Attribute & MSG_FILEREQUEST) ? TRUE : FALSE);
  670.       Hold = (UCHAR)((jamHdr.Attribute & MSG_HOLD) ? TRUE : FALSE);
  671.       Immediate = (UCHAR)((jamHdr.Attribute & MSG_IMMEDIATE) ? TRUE : FALSE);
  672.       Intransit = (UCHAR)((jamHdr.Attribute & MSG_INTRANSIT) ? TRUE : FALSE);
  673.       KillSent = (UCHAR)((jamHdr.Attribute & MSG_KILLSENT) ? TRUE : FALSE);
  674.       Local = (UCHAR)((jamHdr.Attribute & MSG_LOCAL) ? TRUE : FALSE);
  675.       Private = (UCHAR)((jamHdr.Attribute & MSG_PRIVATE) ? TRUE : FALSE);
  676.       ReceiptRequest = (UCHAR)((jamHdr.Attribute & MSG_RECEIPTREQ) ? TRUE : FALSE);
  677.       Received = (UCHAR)((jamHdr.Attribute & MSG_READ) ? TRUE : FALSE);
  678.       Sent = (UCHAR)((jamHdr.Attribute & MSG_SENT) ? TRUE : FALSE);
  679.  
  680.       local = localtime ((const time_t *)&jamHdr.DateWritten);
  681.       Written.Day = (UCHAR)local->tm_mday;
  682.       Written.Month = (UCHAR)(local->tm_mon + 1);
  683.       if (Written.Month < 1 || Written.Month > 12)
  684.          Written.Month = 1;
  685.       Written.Year = (USHORT)(local->tm_year + 1900);
  686.       Written.Hour = (UCHAR)local->tm_hour;
  687.       Written.Minute = (UCHAR)local->tm_min;
  688.       Written.Second = (UCHAR)local->tm_sec;
  689.  
  690.       local = localtime ((const time_t *)&jamHdr.DateProcessed);
  691.       Arrived.Day = (UCHAR)local->tm_mday;
  692.       Arrived.Month = (UCHAR)(local->tm_mon + 1);
  693.       if (Arrived.Month < 1 || Arrived.Month > 12)
  694.          Arrived.Month = 1;
  695.       Arrived.Year = (USHORT)(local->tm_year + 1900);
  696.       Arrived.Hour = (UCHAR)local->tm_hour;
  697.       Arrived.Minute = (UCHAR)local->tm_min;
  698.       Arrived.Second = (UCHAR)local->tm_sec;
  699.  
  700.       Original = jamHdr.ReplyTo;
  701.       Reply = jamHdr.ReplyNext;
  702.  
  703.       if (pSubfield != NULL)
  704.          free (pSubfield);
  705.       pSubfield = NULL;
  706.  
  707.       if (jamHdr.SubfieldLen > 0L) {
  708.          ulSubfieldLen = jamHdr.SubfieldLen;
  709.          pPos = pSubfield = (UCHAR *)malloc ((size_t)(ulSubfieldLen + 1));
  710.          if (pSubfield == NULL)
  711.             return (FALSE);
  712.  
  713.          read (fdHdr, pSubfield, (size_t)jamHdr.SubfieldLen);
  714.  
  715.          while (ulSubfieldLen > 0L) {
  716.             jamSubField = (JAMBINSUBFIELD *)pPos;
  717.             pPos += sizeof (JAMBINSUBFIELD);
  718.  
  719.             switch (jamSubField->LoID) {
  720.                case JAMSFLD_SENDERNAME:
  721.                   memcpy (From, pPos, (INT)jamSubField->DatLen);
  722.                   From[(INT)jamSubField->DatLen] = '\0';
  723.                   break;
  724.  
  725.                case JAMSFLD_RECVRNAME:
  726.                   memcpy (To, pPos, (INT)jamSubField->DatLen);
  727.                   To[(INT)jamSubField->DatLen] = '\0';
  728.                   break;
  729.  
  730.                case JAMSFLD_SUBJECT:
  731.                   memcpy (Subject, pPos, (INT)jamSubField->DatLen);
  732.                   Subject[(INT)jamSubField->DatLen] = '\0';
  733.                   break;
  734.  
  735.                case JAMSFLD_OADDRESS:
  736.                   memcpy (FromAddress, pPos, (INT)jamSubField->DatLen);
  737.                   FromAddress[(INT)jamSubField->DatLen] = '\0';
  738.                   break;
  739.  
  740.                case JAMSFLD_DADDRESS:
  741.                   memcpy (ToAddress, pPos, (INT)jamSubField->DatLen);
  742.                   ToAddress[(INT)jamSubField->DatLen] = '\0';
  743.                   break;
  744.  
  745.                default:
  746.                   break;
  747.             }
  748.  
  749.             ulSubfieldLen -= sizeof (JAMBINSUBFIELD) + jamSubField->DatLen;
  750.             if (ulSubfieldLen > 0)
  751.                pPos += (USHORT)jamSubField->DatLen;
  752.          }
  753.       }
  754.    }
  755.  
  756.    return (RetVal);
  757. }
  758.  
  759. USHORT JAM::Read (ULONG ulMsg, SHORT nWidth)
  760. {
  761.    return (Read (ulMsg, Text, nWidth));
  762. }
  763.  
  764. USHORT JAM::Read (ULONG ulMsg, class TCollection &MsgText, SHORT nWidth)
  765. {
  766.    USHORT RetVal = FALSE, SkipNext;
  767.    SHORT i, nReaded, nCol, nRead;
  768.    CHAR *p;
  769.    UCHAR *pPos;
  770.    ULONG ulTxtLen, ulSubfieldLen;
  771.    JAMIDXREC jamIdx;
  772.    JAMBINSUBFIELD *jamSubField;
  773.    class TCollection Bottom;
  774.  
  775.    MsgText.Clear ();
  776.  
  777.    if ((RetVal = ReadHeader (ulMsg)) == TRUE) {
  778.       lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET);
  779.       read (fdJdx, &jamIdx, sizeof (jamIdx));
  780.       lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  781.       read (fdHdr, &jamHdr, sizeof (JAMHDR));
  782.  
  783.       if ((p = strchr (FromAddress, '.')) != NULL) {
  784.          p++;
  785.          if (atoi (p) != 0) {
  786.             sprintf (szLine, "\001FMPT %s", p);
  787.             MsgText.Add (szLine, (USHORT)(strlen (szLine) + 1));
  788.          }
  789.       }
  790.       if ((p = strchr (ToAddress, '.')) != NULL) {
  791.          p++;
  792.          if (atoi (p) != 0) {
  793.             sprintf (szLine, "\001TOPT %s", p);
  794.             MsgText.Add (szLine, (USHORT)(strlen (szLine) + 1));
  795.          }
  796.       }
  797.  
  798.       if (pSubfield != NULL)
  799.          free (pSubfield);
  800.       pSubfield = NULL;
  801.  
  802.       if (jamHdr.SubfieldLen > 0L) {
  803.          ulSubfieldLen = jamHdr.SubfieldLen;
  804.          pPos = pSubfield = (UCHAR *)malloc ((size_t)(ulSubfieldLen + 1));
  805.          if (pSubfield == NULL)
  806.             return (FALSE);
  807.  
  808.          read (fdHdr, pSubfield, (size_t)jamHdr.SubfieldLen);
  809.  
  810.          while (ulSubfieldLen > 0L) {
  811.             jamSubField = (JAMBINSUBFIELD *)pPos;
  812.             pPos += sizeof (JAMBINSUBFIELD);
  813.  
  814.             switch (jamSubField->LoID) {
  815.                case JAMSFLD_MSGID:
  816.                   memcpy (szBuff, pPos, (INT)jamSubField->DatLen);
  817.                   szBuff[(INT)jamSubField->DatLen] = '\0';
  818.                   sprintf (szLine, "\001MSGID: %s", szBuff);
  819.                   MsgText.Add (szLine);
  820.                   break;
  821.  
  822.                case JAMSFLD_REPLYID:
  823.                   memcpy (szBuff, pPos, (INT)jamSubField->DatLen);
  824.                   szBuff[(INT)jamSubField->DatLen] = '\0';
  825.                   sprintf (szLine, "\001REPLYID: %s", szBuff);
  826.                   MsgText.Add (szLine);
  827.                   break;
  828.  
  829.                case JAMSFLD_PID:
  830.                   memcpy (szBuff, pPos, (INT)jamSubField->DatLen);
  831.                   szBuff[(INT)jamSubField->DatLen] = '\0';
  832.                   sprintf (szLine, "\001PID: %s", szBuff);
  833.                   MsgText.Add (szLine);
  834.                   break;
  835.  
  836.                case JAMSFLD_SEENBY2D:
  837.                   memcpy (szBuff, pPos, (INT)jamSubField->DatLen);
  838.                   szBuff[(INT)jamSubField->DatLen] = '\0';
  839.                   sprintf (szLine, "SEEN-BY: %s", szBuff);
  840.                   Bottom.Add (szLine);
  841.                   break;
  842.  
  843.                case JAMSFLD_PATH2D:
  844.                   memcpy (szBuff, pPos, (INT)jamSubField->DatLen);
  845.                   szBuff[(INT)jamSubField->DatLen] = '\0';
  846.                   sprintf (szLine, "\001PATH: %s", szBuff);
  847.                   Bottom.Add (szLine);
  848.                   break;
  849.  
  850.                default:
  851.                   break;
  852.             }
  853.  
  854.             ulSubfieldLen -= sizeof (JAMBINSUBFIELD) + jamSubField->DatLen;
  855.             if (ulSubfieldLen > 0)
  856.                pPos += (USHORT)jamSubField->DatLen;
  857.          }
  858.       }
  859.  
  860.       lseek (fdJdt, jamHdr.TxtOffset, SEEK_SET);
  861.       ulTxtLen = jamHdr.TxtLen;
  862.       pLine = szLine;
  863.       nCol = 0;
  864.       SkipNext = FALSE;
  865.  
  866.       do {
  867.          if ((ULONG)(nRead = sizeof (szBuff)) > ulTxtLen)
  868.             nRead = (SHORT)ulTxtLen;
  869.  
  870.          nReaded = (SHORT)read (fdJdt, szBuff, nRead);
  871.  
  872.          for (i = 0, pBuff = szBuff; i < nReaded; i++, pBuff++) {
  873.             if (*pBuff == '\r') {
  874.                *pLine = '\0';
  875.                if (pLine > szLine && SkipNext == TRUE) {
  876.                   pLine--;
  877.                   while (pLine > szLine && *pLine == ' ')
  878.                      *pLine-- = '\0';
  879.                   if (pLine > szLine)
  880.                      MsgText.Add (szLine, (USHORT)(strlen (szLine) + 1));
  881.                }
  882.                else if (SkipNext == FALSE)
  883.                   MsgText.Add (szLine);
  884.                SkipNext = FALSE;
  885.                pLine = szLine;
  886.                nCol = 0;
  887.             }
  888.             else if (*pBuff != '\n') {
  889.                *pLine++ = *pBuff;
  890.                nCol++;
  891.                if (nCol >= nWidth) {
  892.                   *pLine = '\0';
  893.                   if (strchr (szLine, ' ') != NULL) {
  894.                      while (nCol > 1 && *pLine != ' ') {
  895.                         nCol--;
  896.                         pLine--;
  897.                      }
  898.                      if (nCol > 0) {
  899.                         while (*pLine == ' ')
  900.                            pLine++;
  901.                         strcpy (szWrp, pLine);
  902.                      }
  903.                      *pLine = '\0';
  904.                   }
  905.                   else
  906.                      szWrp[0] = '\0';
  907.                   MsgText.Add (szLine);
  908.                   strcpy (szLine, szWrp);
  909.                   pLine = strchr (szLine, '\0');
  910.                   nCol = (SHORT)strlen (szLine);
  911.                   SkipNext = TRUE;
  912.                }
  913.             }
  914.          }
  915.  
  916.          ulTxtLen -= nRead;
  917.       } while (ulTxtLen > 0);
  918.  
  919.       if ((p = (CHAR *)Bottom.First ()) != NULL)
  920.          do {
  921.             MsgText.Add (p);
  922.          } while ((p = (CHAR *)Bottom.Next ()) != NULL);
  923.    }
  924.  
  925.    return (RetVal);
  926. }
  927.  
  928. VOID JAM::SetHWM (ULONG ulMsg)
  929. {
  930.    ulMsg = ulMsg;
  931. }
  932.  
  933. ULONG JAM::UidToMsgn (ULONG ulMsg)
  934. {
  935.    ULONG RetVal = 0L, i = 1L;
  936.    JAMIDXREC jamIdx;
  937.  
  938.    if (fdJdx != -1 && fdHdr != -1) {
  939.       lseek (fdJdx, 0L, SEEK_SET);
  940.       while (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  941.          lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  942.          read (fdHdr, &jamHdr, sizeof (JAMHDR));
  943.          if (!(jamHdr.Attribute & MSG_DELETED)) {
  944.             if (jamHdr.MsgNum == ulMsg) {
  945.                RetVal = i;
  946.                break;
  947.             }
  948.             i++;
  949.          }
  950.       }
  951.    }
  952.  
  953.    if (jamHdrInfo.ActiveMsgs == 0L)
  954.       RetVal = 0L;
  955.  
  956.    return (RetVal);
  957. }
  958.  
  959. VOID JAM::UnLock (VOID)
  960. {
  961. }
  962.  
  963. USHORT JAM::WriteHeader (ULONG ulMsg)
  964. {
  965.    USHORT RetVal = FALSE;
  966.    JAMIDXREC jamIdx;
  967.  
  968.    if (Id == ulMsg) {
  969. // --------------------------------------------------------------------
  970. // The user is requesting to write the header of the last message
  971. // retrived so our first attempt is to read the last index from the
  972. // file and check if this is the correct one.
  973. // --------------------------------------------------------------------
  974.       lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET);
  975.       if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  976.          lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  977.          read (fdHdr, &jamHdr, sizeof (JAMHDR));
  978.          if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg)
  979.             RetVal = TRUE;
  980.       }
  981.    }
  982.  
  983.    if (RetVal == FALSE) {
  984. // --------------------------------------------------------------------
  985. // The message requested is not the last retrived or the file pointers
  986. // are not positioned where they should be, so now we attempt to
  987. // retrive the message header scanning the database from the beginning.
  988. // --------------------------------------------------------------------
  989.       Id = 0L;
  990.       lseek (fdJdx, 0L, SEEK_SET);
  991.       do {
  992.          if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) {
  993.             lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  994.             read (fdHdr, &jamHdr, sizeof (JAMHDR));
  995.             if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg)
  996.                RetVal = TRUE;
  997.          }
  998.       } while (RetVal == FALSE && tell (fdJdx) < filelength (fdJdx));
  999.    }
  1000.  
  1001.    if (RetVal == TRUE) {
  1002.       Id = jamHdr.MsgNum;
  1003.       jamHdr.Attribute &= MSG_DELETED;
  1004.       jamHdr.Attribute |= (Crash == TRUE) ? MSG_CRASH : 0;
  1005.       jamHdr.Attribute |= (Direct == TRUE) ? MSG_DIRECT : 0;
  1006.       jamHdr.Attribute |= (FileAttach == TRUE) ? MSG_FILEATTACH : 0;
  1007.       jamHdr.Attribute |= (FileRequest == TRUE) ? MSG_FILEREQUEST : 0;
  1008.       jamHdr.Attribute |= (Hold == TRUE) ? MSG_HOLD : 0;
  1009.       jamHdr.Attribute |= (Immediate == TRUE) ? MSG_IMMEDIATE : 0;
  1010.       jamHdr.Attribute |= (Intransit == TRUE) ? MSG_INTRANSIT : 0;
  1011.       jamHdr.Attribute |= (KillSent == TRUE) ? MSG_KILLSENT : 0;
  1012.       jamHdr.Attribute |= (Local == TRUE) ? MSG_LOCAL : 0;
  1013.       jamHdr.Attribute |= (Private == TRUE) ? MSG_PRIVATE : 0;
  1014.       jamHdr.Attribute |= (ReceiptRequest == TRUE) ? MSG_RECEIPTREQ : 0;
  1015.       jamHdr.Attribute |= (Received == TRUE) ? MSG_READ : 0;
  1016.       jamHdr.Attribute |= (Sent == TRUE) ? MSG_SENT : 0;
  1017.  
  1018.       jamHdr.ReplyTo = Original;
  1019.       jamHdr.ReplyNext = Reply;
  1020.  
  1021.       lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET);
  1022.       write (fdHdr, &jamHdr, sizeof (JAMHDR));
  1023.    }
  1024.  
  1025.    return (RetVal);
  1026. }
  1027.  
  1028.