home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / lora299s.zip / SQUISH.CPP < prev    next >
C/C++ Source or Header  |  1998-05-12  |  41KB  |  1,354 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. #if !defined(__LINUX__)
  21. #include <errno.h>
  22. #endif
  23. #include "msgbase.h"
  24.  
  25. FILE *sh_fopen (char *filename, char *access, int shmode)
  26. {
  27.    FILE *fp;
  28. #if !defined(__LINUX__)
  29.    long t1, t2;
  30. #endif
  31.  
  32. #if defined(__LINUX__)
  33.    fp = fopen (filename, access);
  34.    shmode = shmode;
  35. #else
  36.    t1 = time (NULL);
  37.  
  38.    while (time (NULL) < t1 + 20) {
  39.       if ((fp = _fsopen (filename, access, shmode)) != NULL)
  40.          break;
  41. #if !defined(__LINUX__)
  42.       if (errno != EACCES)
  43.          break;
  44. #endif
  45.       t2 = time (NULL);
  46.       while (time (NULL) < t2 + 1)
  47.          ;
  48.    }
  49. #endif
  50.  
  51.    return (fp);
  52. }
  53.  
  54. SQUISH::SQUISH (void)
  55. {
  56.    fpDat = fpIdx = NULL;
  57.    Current = Id = 0L;
  58.    Locked = FALSE;
  59.    pSqIdx = NULL;
  60. }
  61.  
  62. SQUISH::SQUISH (PSZ pszName)
  63. {
  64.    fpDat = fpIdx = NULL;
  65.    Id = 0L;
  66.    Locked = FALSE;
  67.    pSqIdx = NULL;
  68.  
  69.    Open (pszName);
  70. }
  71.  
  72. SQUISH::~SQUISH (void)
  73. {
  74.    if (Locked == TRUE)
  75.       UnLock ();
  76.    Close ();
  77. }
  78.  
  79. USHORT SQUISH::Add (VOID)
  80. {
  81.    return (Add (Text));
  82. }
  83.  
  84. USHORT SQUISH::Add (class TMsgBase *MsgBase)
  85. {
  86.    New ();
  87.  
  88.    strcpy (From, MsgBase->From);
  89.    strcpy (To, MsgBase->To);
  90.    strcpy (Subject, MsgBase->Subject);
  91.  
  92.    strcpy (FromAddress, MsgBase->FromAddress);
  93.    strcpy (ToAddress, MsgBase->ToAddress);
  94.  
  95.    Written.Day = MsgBase->Written.Day;
  96.    Written.Month = MsgBase->Written.Month;
  97.    Written.Year = MsgBase->Written.Year;
  98.    Written.Hour = MsgBase->Written.Hour;
  99.    Written.Minute = MsgBase->Written.Minute;
  100.    Written.Second = MsgBase->Written.Second;
  101.  
  102.    Arrived.Day = MsgBase->Arrived.Day;
  103.    Arrived.Month = MsgBase->Arrived.Month;
  104.    Arrived.Year = MsgBase->Arrived.Year;
  105.    Arrived.Hour = MsgBase->Arrived.Hour;
  106.    Arrived.Minute = MsgBase->Arrived.Minute;
  107.    Arrived.Second = MsgBase->Arrived.Second;
  108.  
  109.    Original = MsgBase->Original;
  110.    Reply = MsgBase->Reply;
  111.  
  112.    Crash = MsgBase->Crash;
  113.    Direct = MsgBase->Direct;
  114.    FileAttach = MsgBase->FileAttach;
  115.    FileRequest = MsgBase->FileRequest;
  116.    Hold = MsgBase->Hold;
  117.    Immediate = MsgBase->Immediate;
  118.    Intransit = MsgBase->Intransit;
  119.    KillSent = MsgBase->KillSent;
  120.    Local = MsgBase->Local;
  121.    Private = MsgBase->Private;
  122.    ReceiptRequest = MsgBase->ReceiptRequest;
  123.    Received = MsgBase->Received;
  124.    Sent = MsgBase->Sent;
  125.  
  126.    return (Add (MsgBase->Text));
  127. }
  128.  
  129. USHORT SQUISH::Add (class TCollection &MsgText)
  130. {
  131.    CHAR File[128], NoMore;
  132.    PSZ Text, pszAddress, p;
  133.    ULONG EndFrame;
  134.    SQHDR SqHdr;
  135.    SQIDX SqIdx;
  136.    XMSG XMsg;
  137.  
  138.    if (Locked == FALSE || fpDat == NULL) {
  139.       sprintf (File, "%s.sqd", SqBase.Base);
  140.       fpDat = sh_fopen (File, "r+b", SH_DENYNO);
  141.       if (Locked == FALSE && fpDat != NULL)
  142.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  143.    }
  144.  
  145.    if (Locked == FALSE || fpIdx == NULL) {
  146.       sprintf (File, "%s.sqi", SqBase.Base);
  147.       fpIdx = sh_fopen (File, "ab", SH_DENYNO);
  148.    }
  149.  
  150.    if (fpDat != NULL) {
  151.       // Allocate a frame at the end of the file, using the 'end_frame' value.
  152.       memset (&SqHdr, 0, sizeof (SQHDR));
  153.       SqHdr.Id = SQHDRID;
  154.       SqHdr.FrameType = FRAME_NORMAL;
  155.       SqHdr.PrevFrame = SqBase.LastFrame;
  156.       SqHdr.NextFrame = 0L;
  157.  
  158.       NoMore = FALSE;
  159.       SqHdr.CLen = 1;
  160.       if ((Text = (PSZ)MsgText.First ()) != NULL)
  161.          do {
  162.             if (Text[0] == 0x01 && NoMore == FALSE)
  163.                SqHdr.CLen += strlen (Text);
  164.             else {
  165.                SqHdr.MsgLength += strlen (Text) + 1;
  166.                NoMore = TRUE;
  167.             }
  168.          } while ((Text = (PSZ)MsgText.Next ()) != NULL);
  169.  
  170.       if (SqHdr.CLen == 1)
  171.          SqHdr.CLen++;
  172.  
  173.       SqHdr.FrameLength = SqHdr.CLen + SqHdr.MsgLength + sizeof (XMSG);
  174.       SqHdr.MsgLength = SqHdr.FrameLength;
  175.  
  176.       fseek (fpDat, SqBase.EndFrame, SEEK_SET);
  177.       fwrite (&SqHdr, sizeof (SQHDR), 1, fpDat);
  178.  
  179.       // Write the XMSG header.
  180.       memset (&XMsg, 0, sizeof (XMSG));
  181.       strcpy (XMsg.From, From);
  182.       strcpy (XMsg.To, To);
  183.       strcpy (XMsg.Subject, Subject);
  184.       XMsg.MsgId = SqBase.Uid;
  185.  
  186.       pszAddress = FromAddress;
  187.       if (strchr (pszAddress, ':') != NULL) {
  188.          XMsg.Orig.Zone = (USHORT)atoi (pszAddress);
  189.          pszAddress = strchr (pszAddress, ':') + 1;
  190.       }
  191.       if (strchr (pszAddress, '/') != NULL) {
  192.          XMsg.Orig.Net = (USHORT)atoi (pszAddress);
  193.          pszAddress = strchr (pszAddress, '/') + 1;
  194.       }
  195.       XMsg.Orig.Node = (USHORT)atoi (pszAddress);
  196.       if ((p = strchr (pszAddress, '@')) != NULL)
  197.          *p++ = '\0';
  198.       if (strchr (pszAddress, '.') != NULL) {
  199.          pszAddress = strchr (pszAddress, '.') + 1;
  200.          XMsg.Orig.Point = (USHORT)atoi (pszAddress);
  201.       }
  202.  
  203.       pszAddress = ToAddress;
  204.       if (strchr (pszAddress, ':') != NULL) {
  205.          XMsg.Dest.Zone = (USHORT)atoi (pszAddress);
  206.          pszAddress = strchr (pszAddress, ':') + 1;
  207.       }
  208.       if (strchr (pszAddress, '/') != NULL) {
  209.          XMsg.Dest.Net = (USHORT)atoi (pszAddress);
  210.          pszAddress = strchr (pszAddress, '/') + 1;
  211.       }
  212.       XMsg.Dest.Node = (USHORT)atoi (pszAddress);
  213.       if ((p = strchr (pszAddress, '@')) != NULL)
  214.          *p++ = '\0';
  215.       if (strchr (pszAddress, '.') != NULL) {
  216.          pszAddress = strchr (pszAddress, '.') + 1;
  217.          XMsg.Dest.Point = (USHORT)atoi (pszAddress);
  218.       }
  219.  
  220.       XMsg.DateWritten = Written.Day & 0x1F;
  221.       XMsg.DateWritten |= Written.Month << 5;
  222.       XMsg.DateWritten |= (Written.Year - 1980) << 9;
  223.       XMsg.DateWritten |= (Written.Second / 2) << 16;
  224.       XMsg.DateWritten |= Written.Minute << 21;
  225.       XMsg.DateWritten |= Written.Hour << 27;
  226.  
  227.       XMsg.DateArrived = Arrived.Day & 0x1F;
  228.       XMsg.DateArrived |= Arrived.Month << 5;
  229.       XMsg.DateArrived |= (Arrived.Year - 1980) << 9;
  230.       XMsg.DateArrived |= (Arrived.Second / 2) << 16;
  231.       XMsg.DateArrived |= Arrived.Minute << 21;
  232.       XMsg.DateArrived |= Arrived.Hour << 27;
  233.  
  234.       XMsg.Attr = MSGUID;
  235.       XMsg.Attr |= (Crash == TRUE) ? MSGCRASH : 0;
  236.       XMsg.Attr |= (FileAttach == TRUE) ? MSGFILE : 0;
  237.       XMsg.Attr |= (FileRequest == TRUE) ? MSGFRQ : 0;
  238.       XMsg.Attr |= (Hold == TRUE) ? MSGHOLD : 0;
  239.       XMsg.Attr |= (KillSent == TRUE) ? MSGKILL : 0;
  240.       XMsg.Attr |= (Local == TRUE) ? MSGLOCAL : 0;
  241.       XMsg.Attr |= (Private == TRUE) ? MSGPRIVATE : 0;
  242.       XMsg.Attr |= (ReceiptRequest == TRUE) ? MSGRRQ : 0;
  243.       XMsg.Attr |= (Received == TRUE) ? MSGREAD : 0;
  244.       XMsg.Attr |= (Sent == TRUE) ? MSGSENT : 0;
  245.  
  246.       XMsg.ReplyTo = Original;
  247.       XMsg.Replies[0] = Reply;
  248.  
  249.       fwrite (&XMsg, sizeof (XMsg), 1, fpDat);
  250.  
  251.       // Write the message's control information and body.
  252.       if (SqHdr.CLen > 2) {
  253.          if ((Text = (PSZ)MsgText.First ()) != NULL)
  254.             do {
  255.                if (Text[0] == 0x01)
  256.                   fwrite (Text, strlen (Text), 1, fpDat);
  257.                else
  258.                   break;
  259.             } while ((Text = (PSZ)MsgText.Next ()) != NULL);
  260.       }
  261.       else if (SqHdr.CLen == 2)
  262.          fwrite ("\001", 1, 1, fpDat);
  263.       fwrite ("", 1, 1, fpDat);
  264.  
  265.       NoMore = FALSE;
  266.       if ((Text = (PSZ)MsgText.First ()) != NULL)
  267.          do {
  268.             if (Text[0] != 0x01 || NoMore == TRUE) {
  269.                fwrite (Text, strlen (Text), 1, fpDat);
  270.                fwrite ("\r", 1, 1, fpDat);
  271.                NoMore = TRUE;
  272.             }
  273.          } while ((Text = (PSZ)MsgText.Next ()) != NULL);
  274.  
  275.       fflush (fpDat);
  276.       EndFrame = ftell (fpDat);
  277.  
  278.       // Link the new SQHDR frame into the end of the message chain.
  279. //      setvbuf (fpDat, NULL, _IONBF, 0L);
  280.       if (SqBase.LastFrame != 0L) {
  281.          fseek (fpDat, SqBase.LastFrame, SEEK_SET);
  282.          fread (&SqHdr, sizeof (SQHDR), 1, fpDat);
  283.          SqHdr.NextFrame = SqBase.EndFrame;
  284.          fseek (fpDat, SqBase.LastFrame, SEEK_SET);
  285.          fwrite (&SqHdr, sizeof (SQHDR), 1, fpDat);
  286.       }
  287.       SqBase.LastFrame = SqBase.EndFrame;
  288.       SqBase.EndFrame = EndFrame;
  289.       if (SqBase.BeginFrame == 0L)
  290.          SqBase.BeginFrame = SqBase.LastFrame;
  291.  
  292.       SqBase.Uid++;
  293.       SqBase.NumMsg++;
  294.       SqBase.HighMsg++;
  295.  
  296.       if (Locked == FALSE) {
  297.          fseek (fpDat, 0L, SEEK_SET);
  298.          fwrite (&SqBase, sizeof (SQBASE), 1, fpDat);
  299.       }
  300. //      setvbuf (fpDat, NULL, _IOFBF, 4096L);
  301.    }
  302.  
  303.    if (fpIdx != NULL) {
  304.       // Write a SQIDX header for the new message.
  305.       if (Locked == FALSE) {
  306.          SqIdx.Ofs = SqBase.LastFrame;
  307.          SqIdx.MsgId = SqBase.Uid - 1L;
  308.          SqIdx.Hash = Hash (To);
  309.          fwrite (&SqIdx, sizeof (SQIDX), 1, fpIdx);
  310.       }
  311.       else {
  312.          pSqIdx[(int)(SqBase.NumMsg - 1L)].Ofs = SqBase.LastFrame;
  313.          pSqIdx[(int)(SqBase.NumMsg - 1L)].MsgId = SqBase.Uid - 1L;
  314.          pSqIdx[(int)(SqBase.NumMsg - 1L)].Hash = Hash (To);
  315.       }
  316.    }
  317.  
  318.    if (Locked == FALSE) {
  319.       if (fpDat != NULL)
  320.          fclose (fpDat);
  321.       if (fpIdx != NULL)
  322.          fclose (fpIdx);
  323.       fpDat = fpIdx = NULL;
  324.  
  325.       if (pSqIdx != NULL) {
  326.          free (pSqIdx);
  327.          pSqIdx = NULL;
  328.       }
  329.  
  330.       sprintf (File, "%s.sqd", SqBase.Base);
  331.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  332.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  333.          fclose (fpDat);
  334.          fpDat = NULL;
  335.       }
  336.  
  337.       if (SqBase.NumMsg != 0L) {
  338.          sprintf (File, "%s.sqi", SqBase.Base);
  339.          if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  340.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  341.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  342.             fclose (fpIdx);
  343.             fpIdx = NULL;
  344.          }
  345.       }
  346.    }
  347.  
  348.    return (TRUE);
  349. }
  350.  
  351. VOID SQUISH::Close (VOID)
  352. {
  353.    if (fpIdx != NULL)
  354.       fclose (fpIdx);
  355.    if (fpDat != NULL)
  356.       fclose (fpDat);
  357.    if (pSqIdx != NULL)
  358.       pSqIdx = NULL;
  359.  
  360.    fpDat = fpIdx = NULL;
  361.    Id = 0L;
  362.    Locked = FALSE;
  363.    pSqIdx = NULL;
  364. }
  365.  
  366. USHORT SQUISH::Delete (ULONG ulMsg)
  367. {
  368.    int i;
  369.    USHORT RetVal = TRUE;
  370.    CHAR File[128];
  371.    ULONG Position;
  372.    SQHDR SqHdr, SqHdrPrev, SqHdrNext;
  373.  
  374.    if (Locked == FALSE || fpDat == NULL) {
  375.       sprintf (File, "%s.sqd", SqBase.Base);
  376.       fpDat = sh_fopen (File, "r+b", SH_DENYNO);
  377.       if (Locked == FALSE && fpDat != NULL)
  378.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  379.    }
  380.  
  381.    if (Locked == FALSE) {
  382.       if (pSqIdx != NULL) {
  383.          free (pSqIdx);
  384.          pSqIdx = NULL;
  385.       }
  386.       sprintf (File, "%s.sqi", SqBase.Base);
  387.       if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  388.          if ((pSqIdx = (SQIDX *)malloc (sizeof (SQIDX) * 4500)) != NULL) {
  389.             if (SqBase.NumMsg > 0L)
  390.                fread (pSqIdx, (int)filelength (fileno (fpIdx)), 1, fpIdx);
  391.          }
  392.          fclose (fpIdx);
  393.          fpIdx = NULL;
  394.       }
  395.    }
  396.  
  397.    if (pSqIdx != NULL) {
  398.       // Cerca il messaggio da cancellare all'interno dell'indice
  399.       for (i = 0; i < SqBase.NumMsg; i++) {
  400.          if (pSqIdx[i].MsgId == ulMsg) {
  401.             Position = pSqIdx[i].Ofs;
  402.             // Se il messaggio non e' l'ultimo dell'indice, elimina il record
  403.             // spostando l'indice in memoria.
  404.             if ((i + 1) < SqBase.NumMsg)
  405.                memmove (&pSqIdx[i], &pSqIdx[i + 1], (int)((SqBase.NumMsg - i - 1) * sizeof (SQIDX)));
  406.             RetVal = TRUE;
  407.             break;
  408.          }
  409.       }
  410.    }
  411.  
  412.    if (RetVal == TRUE && fpDat != NULL) {
  413.       fseek (fpDat, Position, SEEK_SET);
  414.       fread (&SqHdr, sizeof (SqHdr), 1, fpDat);
  415.       SqHdr.FrameType = FRAME_FREE;
  416.  
  417.       if (SqHdr.PrevFrame != 0L) {
  418.          fseek (fpDat, SqHdr.PrevFrame, SEEK_SET);
  419.          fread (&SqHdrPrev, sizeof (SqHdr), 1, fpDat);
  420.          SqHdrPrev.NextFrame = SqHdr.NextFrame;
  421.          fseek (fpDat, SqHdr.PrevFrame, SEEK_SET);
  422.          fwrite (&SqHdrPrev, sizeof (SqHdr), 1, fpDat);
  423.       }
  424.       if (SqHdr.NextFrame != 0L) {
  425.          fseek (fpDat, SqHdr.NextFrame, SEEK_SET);
  426.          fread (&SqHdrNext, sizeof (SqHdr), 1, fpDat);
  427.          SqHdrNext.PrevFrame = SqHdr.PrevFrame;
  428.          fseek (fpDat, SqHdr.NextFrame, SEEK_SET);
  429.          fwrite (&SqHdrNext, sizeof (SqHdr), 1, fpDat);
  430.       }
  431.  
  432.       SqHdr.NextFrame = 0L;
  433.       fseek (fpDat, Position, SEEK_SET);
  434.       fwrite (&SqHdr, sizeof (SqHdr), 1, fpDat);
  435.  
  436. //      fseek (fpDat, 0L, SEEK_SET);
  437.       SqBase.NumMsg--;
  438.       SqBase.HighMsg--;
  439.  
  440.       if (SqBase.FreeFrame == 0L)
  441.          SqBase.FreeFrame = Position;
  442.       if (SqBase.LastFreeFrame == 0L) {
  443.          SqBase.LastFreeFrame = Position;
  444.          SqHdr.PrevFrame = 0L;
  445.       }
  446.       else {
  447.          SqHdr.PrevFrame = SqBase.LastFreeFrame;
  448.  
  449.          fseek (fpDat, SqBase.LastFreeFrame, SEEK_SET);
  450.          fread (&SqHdrNext, sizeof (SqHdr), 1, fpDat);
  451.          SqHdrNext.NextFrame = Position;
  452.          fseek (fpDat, SqBase.LastFreeFrame, SEEK_SET);
  453.          fwrite (&SqHdrNext, sizeof (SqHdr), 1, fpDat);
  454.  
  455.          SqBase.LastFreeFrame = Position;
  456.       }
  457.  
  458.       fseek (fpDat, Position, SEEK_SET);
  459.       fwrite (&SqHdr, sizeof (SqHdr), 1, fpDat);
  460.  
  461.       fseek (fpDat, 0L, SEEK_SET);
  462.       fwrite (&SqBase, sizeof (SQBASE), 1, fpDat);
  463.    }
  464.  
  465.    if (Locked == FALSE) {
  466.       sprintf (File, "%s.sqi", SqBase.Base);
  467.       if ((fpIdx = sh_fopen (File, "w+b", SH_DENYNO)) != NULL) {
  468.          if (SqBase.NumMsg > 0L)
  469.             fwrite (pSqIdx, (int)(SqBase.NumMsg * sizeof (SQIDX)), 1, fpIdx);
  470.  
  471.          free (pSqIdx);
  472.          pSqIdx = NULL;
  473.  
  474.          if (SqBase.NumMsg != 0L) {
  475.             fseek (fpIdx, 0L, SEEK_SET);
  476.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  477.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  478.          }
  479.  
  480.          fclose (fpIdx);
  481.          fpIdx = NULL;
  482.       }
  483.  
  484.       if (fpDat != NULL)
  485.          fclose (fpDat);
  486.  
  487.       fpDat = fpIdx = NULL;
  488.    }
  489.  
  490.    return (RetVal);
  491. }
  492.  
  493. USHORT SQUISH::GetHWM (ULONG &ulMsg)
  494. {
  495.    CHAR File[128];
  496.  
  497.    if (Locked == FALSE) {
  498.       sprintf (File, "%s.sqd", SqBase.Base);
  499.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  500.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  501.          fclose (fpDat);
  502.          fpDat = NULL;
  503.       }
  504.    }
  505.  
  506.    ulMsg = SqBase.HighWater;
  507.  
  508.    return (TRUE);
  509. }
  510.  
  511. ULONG SQUISH::Hash (PSZ f)
  512. {
  513.    PSZ p;
  514.    ULONG hash = 0, g;
  515.  
  516.    for (p = f; *p; p++) {
  517.       hash = (hash << 4) + (ULONG)tolower (*p);
  518.       if ((g = (hash & 0xF0000000L)) != 0L) {
  519.          hash |= g >> 24;
  520.          hash |= g;
  521.       }
  522.    }
  523.  
  524.    return (hash & 0x7FFFFFFFL);
  525. }
  526.  
  527. ULONG SQUISH::Highest (VOID)
  528. {
  529.    CHAR File[128];
  530.    ULONG RetVal = 0L;
  531.  
  532.    if (pSqIdx == NULL) {
  533.       sprintf (File, "%s.sqd", SqBase.Base);
  534.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  535.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  536.          fclose (fpDat);
  537.          fpDat = NULL;
  538.       }
  539.  
  540.       if (SqBase.NumMsg > 0L) {
  541.          sprintf (File, "%s.sqi", SqBase.Base);
  542.          if ((fpIdx = sh_fopen (File, "rb", SH_DENYNO)) != NULL) {
  543.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  544.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  545.             fclose (fpIdx);
  546.             fpIdx = NULL;
  547.          }
  548.       }
  549.    }
  550.  
  551.    if (SqBase.NumMsg != 0L && pSqIdx != NULL)
  552.       RetVal = pSqIdx[(int)(SqBase.NumMsg - 1L)].MsgId;
  553.  
  554.    return (RetVal);
  555. }
  556.  
  557. USHORT SQUISH::Lock (ULONG ulTimeout)
  558. {
  559.    CHAR File[128];
  560.  
  561.    ulTimeout = ulTimeout;
  562.  
  563.    if (Locked == TRUE) {
  564.       free (pSqIdx);
  565.       if (fpDat != NULL)
  566.          fclose (fpDat);
  567.       if (fpIdx != NULL)
  568.          fclose (fpIdx);
  569.    }
  570.  
  571.    sprintf (File, "%s.sqd", SqBase.Base);
  572.    if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  573.       fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  574.  
  575.       sprintf (File, "%s.sqi", SqBase.Base);
  576.       if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  577.          if ((pSqIdx = (SQIDX *)malloc (sizeof (SQIDX) * 4500)) != NULL) {
  578.             SqBase.NumMsg = fread (pSqIdx, sizeof (SQIDX), 4500, fpIdx);
  579.             SqBase.HighMsg = SqBase.NumMsg;
  580.          }
  581.          fseek (fpIdx, 0L, SEEK_END);
  582.          Locked = TRUE;
  583.       }
  584.    }
  585.  
  586.    return (TRUE);
  587. }
  588.  
  589. ULONG SQUISH::Lowest (VOID)
  590. {
  591.    int i;
  592.    CHAR File[128];
  593.    ULONG RetVal = 0L;
  594.  
  595.    if (pSqIdx == NULL) {
  596.       sprintf (File, "%s.sqd", SqBase.Base);
  597.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  598.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  599.          fclose (fpDat);
  600.          fpDat = NULL;
  601.       }
  602.  
  603.       if (SqBase.NumMsg > 0L) {
  604.          sprintf (File, "%s.sqi", SqBase.Base);
  605.          if ((fpIdx = sh_fopen (File, "rb", SH_DENYNO)) != NULL) {
  606.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  607.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  608.             fclose (fpIdx);
  609.             fpIdx = NULL;
  610.          }
  611.       }
  612.    }
  613.  
  614.    if (SqBase.NumMsg != 0L && pSqIdx != NULL) {
  615.       i = 0;
  616.       while (pSqIdx[i].MsgId == 0xFFFFFFFFL) {
  617.          i++;
  618.          if (i >= SqBase.NumMsg)
  619.             break;
  620.       }
  621.       if (pSqIdx[0].MsgId != 0xFFFFFFFFL)
  622.          RetVal = pSqIdx[0].MsgId;
  623.    }
  624.  
  625.    return (RetVal);
  626. }
  627.  
  628. ULONG SQUISH::MsgnToUid (ULONG ulMsg)
  629. {
  630.    ULONG RetVal = 0L;
  631.    CHAR File[128];
  632.  
  633.    if (pSqIdx == NULL) {
  634.       sprintf (File, "%s.sqd", SqBase.Base);
  635.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  636.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  637.          fclose (fpDat);
  638.          fpDat = NULL;
  639.       }
  640.  
  641.       if (SqBase.NumMsg != 0L) {
  642.          sprintf (File, "%s.sqi", SqBase.Base);
  643.          if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  644.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  645.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  646.             fclose (fpIdx);
  647.             fpIdx = NULL;
  648.          }
  649.       }
  650.    }
  651.  
  652.    if (SqBase.NumMsg != 0L && pSqIdx != NULL) {
  653.       if (ulMsg > 0L && ulMsg <= SqBase.NumMsg)
  654.          RetVal = pSqIdx[(size_t)(ulMsg - 1L)].MsgId;
  655.    }
  656.  
  657.    if (SqBase.NumMsg == 0L)
  658.       RetVal = 0L;
  659.  
  660.    return (RetVal);
  661. }
  662.  
  663. VOID SQUISH::New (VOID)
  664. {
  665.    From[0] = To[0] = Subject[0] = '\0';
  666.    Crash = Direct = FileAttach = FileRequest = Hold = Immediate = FALSE;
  667.    Intransit = KillSent = Local = Private = ReceiptRequest = Received = FALSE;
  668.    Sent = 0;
  669.    memset (&Written, 0, sizeof (Written));
  670.    memset (&Arrived, 0, sizeof (Arrived));
  671.    FromAddress[0] = ToAddress[0] = '\0';
  672.    Original = Reply = 0L;
  673.    Text.Clear ();
  674. }
  675.  
  676. USHORT SQUISH::Next (ULONG &ulMsg)
  677. {
  678.    int i;
  679.    USHORT RetVal = FALSE;
  680.    CHAR File[128];
  681.  
  682.    if (pSqIdx == NULL) {
  683.       sprintf (File, "%s.sqd", SqBase.Base);
  684.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  685.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  686.          fclose (fpDat);
  687.          fpDat = NULL;
  688.       }
  689.  
  690.       if (SqBase.NumMsg != 0L) {
  691.          sprintf (File, "%s.sqi", SqBase.Base);
  692.          if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  693.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  694.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  695.             fclose (fpIdx);
  696.             fpIdx = NULL;
  697.          }
  698.       }
  699.    }
  700.  
  701.    if (SqBase.NumMsg != 0L && pSqIdx != NULL) {
  702.       if (pSqIdx[0].MsgId != 0xFFFFFFFFL && ulMsg < pSqIdx[0].MsgId) {
  703.          ulMsg = pSqIdx[0].MsgId;
  704.          RetVal = TRUE;
  705.       }
  706.       else {
  707.          for (i = 0; i < SqBase.NumMsg; i++) {
  708.             if (pSqIdx[i].MsgId != 0xFFFFFFFFL && pSqIdx[i].MsgId >= ulMsg) {
  709.                if (pSqIdx[i].MsgId == ulMsg) {
  710.                   while (pSqIdx[i].MsgId == ulMsg && i < SqBase.NumMsg)
  711.                      i++;
  712.                }
  713.                if (i < SqBase.NumMsg) {
  714.                   ulMsg = pSqIdx[i].MsgId;
  715.                   RetVal = TRUE;
  716.                }
  717.                break;
  718.             }
  719.          }
  720.       }
  721.    }
  722.  
  723.    return (RetVal);
  724. }
  725.  
  726. ULONG SQUISH::Number (VOID)
  727. {
  728.    return (SqBase.NumMsg);
  729. }
  730.  
  731. USHORT SQUISH::Open (PSZ pszName)
  732. {
  733.    int fd;
  734.    USHORT RetVal = FALSE;
  735.    CHAR File[128];
  736. #if defined(__LINUX__)
  737.    CHAR *p;
  738. #endif
  739.  
  740.    sprintf (File, "%s.sqd", pszName);
  741. #if defined(__LINUX__)
  742.    while ((p = strchr (File, '\\')) != NULL)
  743.       *p = '/';
  744. #endif
  745.  
  746.    memset (&SqBase, 0, sizeof (SQBASE));
  747.    strcpy (SqBase.Base, pszName);
  748.  
  749.    if ((fd = sopen (strlwr (File), O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  750.       if (read (fd, &SqBase, sizeof (SQBASE)) != sizeof (SQBASE)) {
  751.          memset (&SqBase, 0, sizeof (SQBASE));
  752.          SqBase.Len = sizeof (SQBASE);
  753.          SqBase.Uid = 1;
  754.          strcpy (SqBase.Base, pszName);
  755.          SqBase.EndFrame = sizeof (SQBASE);
  756.          SqBase.SzSqhdr = sizeof (SQHDR);
  757.       }
  758.  
  759.       strcpy (SqBase.Base, pszName);
  760. #if defined(__LINUX__)
  761.       while ((p = strchr (SqBase.Base, '\\')) != NULL)
  762.          *p = '/';
  763. #endif
  764.  
  765.       lseek (fd, 0L, SEEK_SET);
  766.       write (fd, &SqBase, sizeof (SQBASE));
  767.       close (fd);
  768.    }
  769.  
  770.    sprintf (File, "%s.sqi", SqBase.Base);
  771.    if ((fd = sopen (strlwr (File), O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1)
  772.       close (fd);
  773.  
  774.    if (SqBase.NumMsg != 0L) {
  775.       sprintf (File, "%s.sqi", SqBase.Base);
  776.       if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  777.          if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  778.             fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  779.          fclose (fpIdx);
  780.          fpIdx = NULL;
  781.       }
  782.    }
  783.  
  784.    Id = 0L;
  785.  
  786.    return (RetVal);
  787. }
  788.  
  789. VOID SQUISH::Pack (VOID)
  790. {
  791.    int fdHdr, fdIdx, fdNewDat, fdNewIdx;
  792.    USHORT Read;
  793.    CHAR File[128], NewFile[128], *Buffer;
  794.    SQIDX SqIdx;
  795.    SQHDR SqHdr, SqHdr2;
  796.  
  797.    if (Locked == TRUE)
  798.       UnLock ();
  799.    if (pSqIdx != NULL) {
  800.       free (pSqIdx);
  801.       pSqIdx = NULL;
  802.    }
  803.  
  804.    sprintf (File, "%s.sqd", SqBase.Base);
  805.    fdHdr = sopen (File, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  806.    sprintf (File, "%s.sqi", SqBase.Base);
  807.    fdIdx = sopen (File, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  808.  
  809.    sprintf (File, "%s._qd", SqBase.Base);
  810.    fdNewDat = sopen (File, O_RDWR|O_BINARY|O_CREAT|O_TRUNC, SH_DENYNO, S_IREAD|S_IWRITE);
  811.    sprintf (File, "%s._qi", SqBase.Base);
  812.    fdNewIdx = sopen (File, O_RDWR|O_BINARY|O_CREAT|O_TRUNC, SH_DENYNO, S_IREAD|S_IWRITE);
  813.  
  814.    Buffer = (CHAR *)malloc (2048);
  815.  
  816.    if (fdHdr != -1 && fdIdx != -1 && fdNewDat != -1 && fdNewIdx != -1 && Buffer != NULL) {
  817.       lseek (fdHdr, 0L, SEEK_SET);
  818.       read (fdHdr, &SqBase, sizeof (SQBASE));
  819.       SqBase.NumMsg = 0L;
  820.       SqBase.HighMsg = 0L;
  821.       SqBase.BeginFrame = sizeof (SQBASE);
  822.       SqBase.LastFrame = 0L;
  823.       SqBase.FreeFrame = 0L;
  824.       SqBase.LastFreeFrame = 0L;
  825.       SqBase.EndFrame = 0L;
  826.       write (fdNewDat, &SqBase, sizeof (SQBASE));
  827.  
  828.       lseek (fdIdx, 0L, SEEK_SET);
  829.       while (read (fdIdx, &SqIdx, sizeof (SQIDX)) == sizeof (SQIDX)) {
  830.          lseek (fdHdr, SqIdx.Ofs, SEEK_SET);
  831.          read (fdHdr, &SqHdr, sizeof (SQHDR));
  832.          if (SqHdr.FrameType == FRAME_NORMAL && SqHdr.Id == SQHDRID) {
  833.             SqBase.NumMsg++;
  834.             SqBase.HighMsg++;
  835.  
  836.             SqHdr.PrevFrame = SqBase.LastFrame;
  837.             SqHdr.NextFrame = 0L;
  838.             SqHdr.FrameLength = SqHdr.MsgLength;
  839.             if (SqBase.LastFrame != 0L) {
  840.                lseek (fdNewDat, SqBase.LastFrame, SEEK_SET);
  841.                read (fdNewDat, &SqHdr2, sizeof (SQHDR));
  842.                SqHdr2.NextFrame = filelength (fdNewDat);
  843.                lseek (fdNewDat, SqBase.LastFrame, SEEK_SET);
  844.                write (fdNewDat, &SqHdr2, sizeof (SQHDR));
  845.             }
  846.             lseek (fdNewDat, 0L, SEEK_END);
  847.             SqBase.LastFrame = filelength (fdNewDat);
  848.  
  849.             SqIdx.Ofs = filelength (fdNewDat);
  850.             write (fdNewIdx, &SqIdx, sizeof (SQIDX));
  851.  
  852.             write (fdNewDat, &SqHdr, sizeof (SQHDR));
  853.  
  854.             while (SqHdr.FrameLength > 0L) {
  855.                if ((Read = 2048) > SqHdr.FrameLength)
  856.                   Read = (USHORT)SqHdr.FrameLength;
  857.                read (fdHdr, Buffer, Read);
  858.                write (fdNewDat, Buffer, Read);
  859.                SqHdr.FrameLength -= Read;
  860.             }
  861.          }
  862.       }
  863.  
  864.       lseek (fdNewDat, 0L, SEEK_SET);
  865.       SqBase.EndFrame = filelength (fdNewDat);
  866.       write (fdNewDat, &SqBase, sizeof (SQBASE));
  867.  
  868.       close (fdNewDat);
  869.       close (fdHdr);
  870.       fdHdr = fdNewDat = -1;
  871.       sprintf (File, "%s._qd", SqBase.Base);
  872.       sprintf (NewFile, "%s.sqd", SqBase.Base);
  873.       unlink (NewFile);
  874.       rename (File, NewFile);
  875.  
  876.       close (fdNewIdx);
  877.       close (fdIdx);
  878.       fdIdx = fdNewIdx = -1;
  879.       sprintf (File, "%s._qi", SqBase.Base);
  880.       sprintf (NewFile, "%s.sqi", SqBase.Base);
  881.       unlink (NewFile);
  882.       rename (File, NewFile);
  883.    }
  884.  
  885.    if (Buffer != NULL)
  886.       free (Buffer);
  887.    if (fdHdr != -1)
  888.       close (fdHdr);
  889.    if (fdNewDat != -1)
  890.       close (fdNewDat);
  891.    sprintf (File, "%s._qd", SqBase.Base);
  892.    unlink (File);
  893.    if (fdIdx != -1)
  894.       close (fdIdx);
  895.    if (fdNewIdx != -1)
  896.       close (fdNewIdx);
  897.    sprintf (File, "%s._qi", SqBase.Base);
  898.    unlink (File);
  899. }
  900.  
  901. USHORT SQUISH::Previous (ULONG &ulMsg)
  902. {
  903.    int i;
  904.    USHORT RetVal = FALSE;
  905.    CHAR File[128];
  906.  
  907.    if (pSqIdx == NULL) {
  908.       sprintf (File, "%s.sqd", SqBase.Base);
  909.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  910.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  911.          fclose (fpDat);
  912.          fpDat = NULL;
  913.       }
  914.  
  915.       if (SqBase.NumMsg != 0L) {
  916.          sprintf (File, "%s.sqi", SqBase.Base);
  917.          if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  918.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  919.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  920.             fclose (fpIdx);
  921.             fpIdx = NULL;
  922.          }
  923.       }
  924.    }
  925.  
  926.    if (SqBase.NumMsg != 0L && pSqIdx != NULL) {
  927.       if (pSqIdx[(int)(SqBase.NumMsg - 1L)].MsgId != 0xFFFFFFFFL && ulMsg > pSqIdx[(int)(SqBase.NumMsg - 1L)].MsgId) {
  928.          ulMsg = pSqIdx[(int)(SqBase.NumMsg - 1L)].MsgId;
  929.          RetVal = TRUE;
  930.       }
  931.       else {
  932.          for (i = (int)SqBase.NumMsg - 1; i >= 0; i--) {
  933.             if (pSqIdx[i].MsgId != 0xFFFFFFFFL && pSqIdx[i].MsgId <= ulMsg) {
  934.                if (pSqIdx[i].MsgId == ulMsg)
  935.                   i--;
  936.                if (i >= 0L) {
  937.                   ulMsg = pSqIdx[i].MsgId;
  938.                   RetVal = TRUE;
  939.                }
  940.                break;
  941.             }
  942.          }
  943.       }
  944.    }
  945.  
  946.    return (RetVal);
  947. }
  948.  
  949. USHORT SQUISH::ReadHeader (ULONG ulMsg)
  950. {
  951.    int i;
  952.    USHORT RetVal = FALSE;
  953.    CHAR File[128];
  954.    ULONG Position;
  955.  
  956.    New ();
  957.  
  958.    if (pSqIdx == NULL) {
  959.       sprintf (File, "%s.sqd", SqBase.Base);
  960.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  961.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  962.          fclose (fpDat);
  963.          fpDat = NULL;
  964.       }
  965.  
  966.       if (SqBase.NumMsg != 0L) {
  967.          sprintf (File, "%s.sqi", SqBase.Base);
  968.          if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  969.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  970.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  971.             fclose (fpIdx);
  972.             fpIdx = NULL;
  973.          }
  974.       }
  975.    }
  976.  
  977.    if (pSqIdx != NULL && SqBase.NumMsg > 0L) {
  978.       for (i = 0; i < SqBase.NumMsg; i++) {
  979.          if (pSqIdx[i].MsgId != 0xFFFFFFFFL && pSqIdx[i].MsgId == ulMsg) {
  980.             RetVal = TRUE;
  981.             Position = pSqIdx[i].Ofs;
  982.             memcpy (&SqIdx, &pSqIdx[i], sizeof (SqIdx));
  983.             break;
  984.          }
  985.       }
  986.    }
  987.  
  988.    if (RetVal == TRUE) {
  989.       if (Locked == FALSE || fpDat == NULL) {
  990.          sprintf (File, "%s.sqd", SqBase.Base);
  991.          fpDat = sh_fopen (File, "r+b", SH_DENYNO);
  992.       }
  993.  
  994.       if (Locked == FALSE || Position != ftell (fpDat))
  995.          fseek (fpDat, Position, SEEK_SET);
  996.       fread (&SqHdr, sizeof (SQHDR), 1, fpDat);
  997.  
  998.       if (SqHdr.Id == SQHDRID && SqHdr.FrameType == FRAME_NORMAL) {
  999.          Current = Id = ulMsg;
  1000.          fread (&XMsg, sizeof (XMSG), 1, fpDat);
  1001.          strcpy (From, XMsg.From);
  1002.          strcpy (To, XMsg.To);
  1003.          strcpy (Subject, XMsg.Subject);
  1004.  
  1005.          sprintf (FromAddress, "%u:%u/%u.%u", XMsg.Orig.Zone, XMsg.Orig.Net, XMsg.Orig.Node, XMsg.Orig.Point);
  1006.          sprintf (ToAddress, "%u:%u/%u.%u", XMsg.Dest.Zone, XMsg.Dest.Net, XMsg.Dest.Node, XMsg.Dest.Point);
  1007.  
  1008.          Written.Day = (UCHAR)(XMsg.DateWritten & 0x001FL);
  1009.          Written.Month = (UCHAR)((XMsg.DateWritten & 0x01E0L) >> 5);
  1010.          if (Written.Month < 1 || Written.Month > 12)
  1011.             Written.Month = 1;
  1012.          Written.Year = (USHORT)(((XMsg.DateWritten & 0xFE00L) >> 9) + 1980);
  1013.          Written.Second = (UCHAR)(((XMsg.DateWritten & 0x001F0000L) >> 16) * 2);
  1014.          Written.Minute = (UCHAR)((XMsg.DateWritten & 0x07E00000L) >> 21);
  1015.          Written.Hour = (UCHAR)((XMsg.DateWritten & 0xF8000000L) >> 27);
  1016.  
  1017.          Arrived.Day = (UCHAR)(XMsg.DateArrived & 0x001FL);
  1018.          Arrived.Month = (UCHAR)((XMsg.DateArrived & 0x01E0L) >> 5);
  1019.          if (Arrived.Month < 1 || Arrived.Month > 12)
  1020.             Arrived.Month = 1;
  1021.          Arrived.Year = (USHORT)(((XMsg.DateArrived & 0xFE00L) >> 9) + 1980);
  1022.          Arrived.Second = (UCHAR)(((XMsg.DateArrived & 0x001F0000L) >> 16) * 2);
  1023.          Arrived.Minute = (UCHAR)((XMsg.DateArrived & 0x07E00000L) >> 21);
  1024.          Arrived.Hour = (UCHAR)((XMsg.DateArrived & 0xF8000000L) >> 27);
  1025.  
  1026.          Original = XMsg.ReplyTo;
  1027.          Reply = XMsg.Replies[0];
  1028.  
  1029.          Crash = (UCHAR)((XMsg.Attr & MSGCRASH) ? TRUE : FALSE);
  1030.          FileAttach = (UCHAR)((XMsg.Attr & MSGFILE) ? TRUE : FALSE);
  1031.          FileRequest = (UCHAR)((XMsg.Attr & MSGFRQ) ? TRUE : FALSE);
  1032.          Hold = (UCHAR)((XMsg.Attr & MSGHOLD) ? TRUE : FALSE);
  1033.          KillSent = (UCHAR)((XMsg.Attr & MSGKILL) ? TRUE : FALSE);
  1034.          Local = (UCHAR)((XMsg.Attr & MSGLOCAL) ? TRUE : FALSE);
  1035.          Private = (UCHAR)((XMsg.Attr & MSGPRIVATE) ? TRUE : FALSE);
  1036.          ReceiptRequest = (UCHAR)((XMsg.Attr & MSGRRQ) ? TRUE : FALSE);
  1037.          Received = (UCHAR)((XMsg.Attr & MSGREAD) ? TRUE : FALSE);
  1038.          Sent = (UCHAR)((XMsg.Attr & MSGSENT) ? TRUE : FALSE);
  1039.       }
  1040.       else
  1041.          RetVal = FALSE;
  1042.  
  1043.       if (Locked == FALSE && fpDat != NULL) {
  1044.          fclose (fpDat);
  1045.          fpDat = NULL;
  1046.       }
  1047.    }
  1048.  
  1049.    return (RetVal);
  1050. }
  1051.  
  1052. USHORT SQUISH::Read (ULONG ulMsg, SHORT nWidth)
  1053. {
  1054.    return (Read (ulMsg, Text, nWidth));
  1055. }
  1056.  
  1057. USHORT SQUISH::Read (ULONG ulMsg, class TCollection &MsgText, SHORT nWidth)
  1058. {
  1059.    USHORT RetVal = FALSE, SkipNext;
  1060.    SHORT i, nReaded, nCol, nRead;
  1061.    CHAR File[128];
  1062.    LONG TxtLen;
  1063.  
  1064.    MsgText.Clear ();
  1065.  
  1066.    if (ReadHeader (ulMsg) == TRUE) {
  1067.       if (Locked == FALSE || fpDat == NULL) {
  1068.          sprintf (File, "%s.sqd", SqBase.Base);
  1069.          if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL)
  1070.             fseek (fpDat, SqIdx.Ofs + sizeof (SQHDR) + sizeof (XMSG), SEEK_SET);
  1071.       }
  1072.  
  1073.       if (SqHdr.CLen > 2 && fpDat != NULL) {
  1074.          TxtLen = (LONG)SqHdr.CLen;
  1075.          pLine = szLine;
  1076.          nCol = 0;
  1077.  
  1078.          do {
  1079.             if ((nRead = sizeof (szBuff)) > TxtLen)
  1080.                nRead = (SHORT)TxtLen;
  1081.  
  1082.             nReaded = 0;
  1083.             if (nRead > 0)
  1084.                nReaded = (SHORT)fread (szBuff, 1, nRead, fpDat);
  1085.  
  1086.             for (i = 0, pBuff = szBuff; i < nReaded; i++, pBuff++) {
  1087.                if (*pBuff == '\r' || *pBuff == '\001' || *pBuff == '\0' && pLine != szLine) {
  1088.                   *pLine = '\0';
  1089.                   if (szLine[0] == '\001')
  1090.                      MsgText.Add (szLine, (USHORT)(strlen (szLine) + 1));
  1091.                   pLine = szLine;
  1092.                   nCol = 0;
  1093.                   if (*pBuff == '\001')
  1094.                      *pLine++ = '\001';
  1095.                }
  1096.                else if (*pBuff != '\n' && *pBuff != '\r' && *pBuff != '\0') {
  1097.                   *pLine++ = *pBuff;
  1098.                   nCol++;
  1099.                   if (nCol >= nWidth) {
  1100.                      *pLine = '\0';
  1101.                      MsgText.Add (szLine, (USHORT)(strlen (szLine) + 1));
  1102.                      pLine = szLine;
  1103.                      *pLine++ = '\001';
  1104.                      nCol = 1;
  1105.                   }
  1106.                }
  1107.             }
  1108.  
  1109.             TxtLen -= nReaded;
  1110.          } while (TxtLen > 0);
  1111.       }
  1112.       else
  1113.          fread (szBuff, (size_t)SqHdr.CLen, 1, fpDat);
  1114.  
  1115.       TxtLen = (LONG)(SqHdr.MsgLength - sizeof (XMSG) - SqHdr.CLen);
  1116.       pLine = szLine;
  1117.       nCol = 0;
  1118.       SkipNext = FALSE;
  1119.       szWrp[0] = '\0';
  1120.  
  1121.       if (TxtLen > 0L && fpDat != NULL)
  1122.          do {
  1123.             if ((nRead = sizeof (szBuff)) > TxtLen)
  1124.                nRead = (SHORT)TxtLen;
  1125.  
  1126.             nReaded = 0;
  1127.             if (nRead > 0)
  1128.                nReaded = (SHORT)fread (szBuff, 1, nRead, fpDat);
  1129.  
  1130.             for (i = 0, pBuff = szBuff; i < nReaded; i++, pBuff++) {
  1131.                if (*pBuff == '\r') {
  1132.                   *pLine = '\0';
  1133.                   if (pLine > szLine && SkipNext == TRUE) {
  1134.                      pLine--;
  1135.                      while (pLine > szLine && *pLine == ' ')
  1136.                         *pLine-- = '\0';
  1137.                      if (pLine > szLine)
  1138.                         MsgText.Add (szLine, (USHORT)(strlen (szLine) + 1));
  1139.                   }
  1140.                   else if (SkipNext == FALSE)
  1141.                      MsgText.Add (szLine, (USHORT)(strlen (szLine) + 1));
  1142.                   SkipNext = FALSE;
  1143.                   pLine = szLine;
  1144.                   nCol = 0;
  1145.                }
  1146.                else if (*pBuff != '\n') {
  1147.                   *pLine++ = *pBuff;
  1148.                   nCol++;
  1149.                   if (nCol >= nWidth) {
  1150.                      *pLine = '\0';
  1151.                      if (strchr (szLine, ' ') != NULL) {
  1152.                         while (nCol > 1 && *pLine != ' ') {
  1153.                            nCol--;
  1154.                            pLine--;
  1155.                         }
  1156.                         if (nCol > 0) {
  1157.                            while (*pLine == ' ')
  1158.                               pLine++;
  1159.                            strcpy (szWrp, pLine);
  1160.                         }
  1161.                         *pLine = '\0';
  1162.                      }
  1163.                      else
  1164.                         szWrp[0] = '\0';
  1165.                      MsgText.Add (szLine, (USHORT)(strlen (szLine) + 1));
  1166.                      strcpy (szLine, szWrp);
  1167.                      pLine = strchr (szLine, '\0');
  1168.                      nCol = (SHORT)strlen (szLine);
  1169.                      SkipNext = TRUE;
  1170.                   }
  1171.                }
  1172.             }
  1173.  
  1174.             TxtLen -= nReaded;
  1175.          } while (TxtLen > 0);
  1176.  
  1177.       if (Locked == FALSE && fpDat != NULL) {
  1178.          fclose (fpDat);
  1179.          fpDat = NULL;
  1180.       }
  1181.  
  1182.       RetVal = TRUE;
  1183.    }
  1184.  
  1185.    return (RetVal);
  1186. }
  1187.  
  1188. VOID SQUISH::SetHWM (ULONG ulMsg)
  1189. {
  1190.    CHAR File[128];
  1191.  
  1192.    if (Locked == FALSE) {
  1193.       sprintf (File, "%s.sqd", SqBase.Base);
  1194.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL)
  1195.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  1196.    }
  1197.  
  1198.    SqBase.HighWater = ulMsg;
  1199.  
  1200.    if (fpDat != NULL) {
  1201.       fseek (fpDat, 0L, SEEK_SET);
  1202.       fwrite (&SqBase, sizeof (SQBASE), 1, fpDat);
  1203.  
  1204.       if (Locked == FALSE) {
  1205.          fclose (fpDat);
  1206.          fpDat = NULL;
  1207.       }
  1208.    }
  1209. }
  1210.  
  1211. ULONG SQUISH::UidToMsgn (ULONG ulMsg)
  1212. {
  1213.    int i;
  1214.    ULONG RetVal = 0L;
  1215.    CHAR File[128];
  1216.  
  1217.    if (pSqIdx == NULL) {
  1218.       sprintf (File, "%s.sqd", SqBase.Base);
  1219.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  1220.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  1221.          fclose (fpDat);
  1222.          fpDat = NULL;
  1223.       }
  1224.  
  1225.       if (SqBase.NumMsg != 0L) {
  1226.          sprintf (File, "%s.sqi", SqBase.Base);
  1227.          if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  1228.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  1229.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  1230.             fclose (fpIdx);
  1231.             fpIdx = NULL;
  1232.          }
  1233.       }
  1234.    }
  1235.  
  1236.    if (SqBase.NumMsg != 0L && pSqIdx != NULL) {
  1237.       for (i = 0; i < SqBase.NumMsg; i++) {
  1238.          if (pSqIdx[i].MsgId == ulMsg) {
  1239.             RetVal = i + 1;
  1240.             break;
  1241.          }
  1242.       }
  1243.    }
  1244.  
  1245.    if (SqBase.NumMsg == 0L)
  1246.       RetVal = 0L;
  1247.  
  1248.    return (RetVal);
  1249. }
  1250.  
  1251. VOID SQUISH::UnLock (VOID)
  1252. {
  1253.    CHAR File[128];
  1254.  
  1255.    if (Locked == TRUE && pSqIdx != NULL) {
  1256.       fclose (fpIdx);
  1257.  
  1258.       sprintf (File, "%s.sqi", SqBase.Base);
  1259.       fpIdx = sh_fopen (File, "wb", SH_DENYNO);
  1260.       if (SqBase.NumMsg > 0L)
  1261.          fwrite (pSqIdx, (int)(sizeof (SQIDX) * SqBase.NumMsg), 1, fpIdx);
  1262.       fclose (fpIdx);
  1263.  
  1264.       fseek (fpDat, 0L, SEEK_SET);
  1265.       fwrite (&SqBase, sizeof (SQBASE), 1, fpDat);
  1266.       fclose (fpDat);
  1267.  
  1268.       free (pSqIdx);
  1269.  
  1270.       pSqIdx = NULL;
  1271.       fpDat = fpIdx = NULL;
  1272.       Locked = FALSE;
  1273.    }
  1274. }
  1275.  
  1276. USHORT SQUISH::WriteHeader (ULONG ulMsg)
  1277. {
  1278.    int i;
  1279.    USHORT RetVal = FALSE;
  1280.    CHAR File[128];
  1281.    ULONG Position;
  1282.  
  1283.    if (pSqIdx == NULL) {
  1284.       sprintf (File, "%s.sqd", SqBase.Base);
  1285.       if ((fpDat = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  1286.          fread (&SqBase, sizeof (SQBASE), 1, fpDat);
  1287.          fclose (fpDat);
  1288.          fpDat = NULL;
  1289.       }
  1290.  
  1291.       if (SqBase.NumMsg != 0L) {
  1292.          sprintf (File, "%s.sqi", SqBase.Base);
  1293.          if ((fpIdx = sh_fopen (File, "r+b", SH_DENYNO)) != NULL) {
  1294.             if ((pSqIdx = (SQIDX *)malloc ((int)(sizeof (SQIDX) * SqBase.NumMsg))) != NULL)
  1295.                fread (pSqIdx, sizeof (SQIDX), (size_t)SqBase.NumMsg, fpIdx);
  1296.             fclose (fpIdx);
  1297.             fpIdx = NULL;
  1298.          }
  1299.       }
  1300.    }
  1301.  
  1302.    if (SqBase.NumMsg > 0L && pSqIdx != NULL) {
  1303.       for (i = 0; i < SqBase.NumMsg; i++) {
  1304.          if (pSqIdx[i].MsgId == ulMsg) {
  1305.             RetVal = TRUE;
  1306.             Position = pSqIdx[i].Ofs;
  1307.             break;
  1308.          }
  1309.       }
  1310.    }
  1311.  
  1312.    if (RetVal == TRUE) {
  1313.       if (Locked == FALSE || fpDat == NULL) {
  1314.          sprintf (File, "%s.sqd", SqBase.Base);
  1315.          fpDat = sh_fopen (File, "r+b", SH_DENYNO);
  1316.       }
  1317.  
  1318.       Position += sizeof (SQHDR);
  1319.       if (Locked == FALSE || Position != ftell (fpDat))
  1320.          fseek (fpDat, Position, SEEK_SET);
  1321.  
  1322.       if (SqHdr.FrameType == FRAME_NORMAL) {
  1323.          fread (&XMsg, sizeof (XMSG), 1, fpDat);
  1324.  
  1325.          XMsg.Attr = 0;
  1326.          XMsg.Attr |= (Crash == TRUE) ? MSGCRASH : 0;
  1327.          XMsg.Attr |= (FileAttach == TRUE) ? MSGFILE : 0;
  1328.          XMsg.Attr |= (FileRequest == TRUE) ? MSGFRQ : 0;
  1329.          XMsg.Attr |= (Hold == TRUE) ? MSGHOLD : 0;
  1330.          XMsg.Attr |= (KillSent == TRUE) ? MSGKILL : 0;
  1331.          XMsg.Attr |= (Local == TRUE) ? MSGLOCAL : 0;
  1332.          XMsg.Attr |= (Private == TRUE) ? MSGPRIVATE : 0;
  1333.          XMsg.Attr |= (ReceiptRequest == TRUE) ? MSGRRQ : 0;
  1334.          XMsg.Attr |= (Received == TRUE) ? MSGREAD : 0;
  1335.          XMsg.Attr |= (Sent == TRUE) ? MSGSENT : 0;
  1336.  
  1337.          XMsg.ReplyTo = Original;
  1338.          XMsg.Replies[0] = Reply;
  1339.  
  1340.          fseek (fpDat, Position, SEEK_SET);
  1341.          fwrite (&XMsg, sizeof (XMSG), 1, fpDat);
  1342.       }
  1343.  
  1344.       if (Locked == FALSE && fpDat != NULL) {
  1345.          fclose (fpDat);
  1346.          fpDat = NULL;
  1347.       }
  1348.    }
  1349.  
  1350.    return (RetVal);
  1351. }
  1352.  
  1353.  
  1354.