home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / MISC / SQDEV200.ZIP / SRC / SQ_WRITE.C < prev    next >
C/C++ Source or Header  |  1994-05-23  |  20KB  |  694 lines

  1. /***************************************************************************
  2.  *                                                                         *
  3.  *  Squish Developers Kit Source, Version 2.00                             *
  4.  *  Copyright 1989-1994 by SCI Communications.  All rights reserved.       *
  5.  *                                                                         *
  6.  *  USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE       *
  7.  *  SQUISH DEVELOPERS KIT LICENSING AGREEMENT IN SQDEV.PRN.  IF YOU DO NOT *
  8.  *  FIND THE TEXT OF THIS AGREEMENT IN THE AFOREMENTIONED FILE, OR IF YOU  *
  9.  *  DO NOT HAVE THIS FILE, YOU SHOULD IMMEDIATELY CONTACT THE AUTHOR AT    *
  10.  *  ONE OF THE ADDRESSES LISTED BELOW.  IN NO EVENT SHOULD YOU PROCEED TO  *
  11.  *  USE THIS FILE WITHOUT HAVING ACCEPTED THE TERMS OF THE SQUISH          *
  12.  *  DEVELOPERS KIT LICENSING AGREEMENT, OR SUCH OTHER AGREEMENT AS YOU ARE *
  13.  *  ABLE TO REACH WITH THE AUTHOR.                                         *
  14.  *                                                                         *
  15.  *  You can contact the author at one of the address listed below:         *
  16.  *                                                                         *
  17.  *  Scott Dudley       FidoNet     1:249/106                               *
  18.  *  777 Downing St.    Internet    sjd@f106.n249.z1.fidonet.org            *
  19.  *  Kingston, Ont.     CompuServe  >INTERNET:sjd@f106.n249.z1.fidonet.org  *
  20.  *  Canada  K7M 5N3    BBS         1-613-634-3058, V.32bis                 *
  21.  *                                                                         *
  22.  ***************************************************************************/
  23.  
  24. #pragma off(unreferenced)
  25. static char rcs_id[]="$Id: SQ_WRITE.C 1.5 1994/04/09 07:00:08 sjd Exp sjd $";
  26. #pragma on(unreferenced)
  27.  
  28. #define MSGAPI_HANDLERS
  29. #define MSGAPI_NO_OLD_TYPES
  30.  
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include <assert.h>
  35. #include <io.h>
  36. #include <fcntl.h>
  37. #include "prog.h"
  38. #include "msgapi.h"
  39. #include "api_sq.h"
  40. #include "apidebug.h"
  41.  
  42.  
  43.  
  44.  
  45. /* This function searches the list of free frames to find one which is      *
  46.  * large enough to hold a message of size dwLen.                            *
  47.  *                                                                          *
  48.  * This function assumes that we have exclusive access to the Squish base.  */
  49.  
  50. static unsigned near _SquishProbeFreeChain(HAREA ha, dword dwLen, FOFS *pfo,
  51.                                            SQHDR *psqh, dword *pdwFrameLen)
  52. {
  53.   FOFS foThis, foLast;
  54.  
  55.   assert(Sqd->fHaveExclusive);
  56.  
  57.  
  58.   /* Assume that we haven't found anything */
  59.  
  60.   *pfo=NULL_FRAME;
  61.   *pdwFrameLen=0L;
  62.  
  63.  
  64.   foLast=NULL_FRAME;
  65.  
  66.   /* Look through all of the entries in the free chain */
  67.  
  68.   for (foThis=Sqd->foFree;
  69.        foThis != NULL_FRAME;
  70.        foLast=foThis, foThis=psqh->next_frame)
  71.   {
  72.     /* Try to read the header at this point in the list */
  73.  
  74.     if (!_SquishReadHdr(ha, foThis, psqh))
  75.       return FALSE;
  76.  
  77.  
  78.     /* Verify that this is a valid frame and that we aren't going around    *
  79.      * in circles.                                                          */
  80.  
  81.     if (psqh->frame_type != FRAME_FREE ||
  82.         foLast != psqh->prev_frame ||
  83.         psqh->next_frame==foThis)
  84.     {
  85.       msgapierr=MERR_BADF;
  86.       return FALSE;
  87.     }
  88.  
  89.     /* If the frame is long enough, we can use it */
  90.  
  91.     if (psqh->frame_length >= dwLen)
  92.     {
  93.       *pdwFrameLen=psqh->frame_length;
  94.       *pfo=foThis;
  95.       break;
  96.     }
  97.   }
  98.  
  99.   return TRUE;
  100. }
  101.  
  102.  
  103.  
  104. /* This function removes the frame at offset 'fo' from the free chain.      *
  105.  *                                                                          *
  106.  * This function assumes that we have exclusive access to the Squish base.  */
  107.  
  108. static unsigned near _SquishRemoveFreeChain(HAREA ha, FOFS fo, SQHDR *psqh)
  109. {
  110.   assert(Sqd->fHaveExclusive);
  111.  
  112.   /* Validate that the frames which pretend to be list heads/tails are      *
  113.    * actually what they seem.                                               */
  114.  
  115.   if ((psqh->prev_frame==NULL_FRAME && fo != Sqd->foFree) ||
  116.       (psqh->next_frame==NULL_FRAME && fo != Sqd->foLastFree))
  117.   {
  118.     msgapierr=MERR_BADF;
  119.     return FALSE;
  120.   }
  121.  
  122.  
  123.   /* If there is a frame before this one, set it to skip over this frame */
  124.  
  125.   if (psqh->prev_frame)
  126.     if (!_SquishSetFrameNext(ha, psqh->prev_frame, psqh->next_frame))
  127.       return FALSE;
  128.  
  129.  
  130.   /* Do the same for the other side of the linked list */
  131.  
  132.   if (psqh->next_frame)
  133.     if (!_SquishSetFramePrev(ha, psqh->next_frame, psqh->prev_frame))
  134.       return FALSE;
  135.  
  136.  
  137.   /* Now update the head and tail pointers for the free message list */
  138.  
  139.   if (Sqd->foFree==fo)
  140.     Sqd->foFree=psqh->next_frame;
  141.  
  142.   if (Sqd->foLastFree==fo)
  143.     Sqd->foLastFree=psqh->prev_frame;
  144.  
  145.   return TRUE;
  146. }
  147.  
  148.  
  149.  
  150. /* Allocate a frame of length dwLen at end-of-file, and store result in pfo.*
  151.  *                                                                          *
  152.  * This function assumes that we have exclusive access to the Squish        *
  153.  * base.                                                                    */
  154.  
  155. static unsigned near _SquishGetFrameEOF(HAREA ha, FOFS *pfo, dword dwLen)
  156. {
  157.   char nul=0;
  158.   long ofs;
  159.  
  160.   assert(Sqd->fHaveExclusive);
  161.  
  162.   /* Find the last byte that we will have to write for this frame, to       *
  163.    * ensure that we have enough disk space to write this message.           */
  164.  
  165.   ofs=Sqd->foEnd + (long)Sqd->cbSqhdr + (long)dwLen - 1L;
  166.  
  167.   /* Now try to write it, just to make sure... */
  168.  
  169.   if (lseek(Sqd->sfd, ofs, SEEK_SET) != ofs ||
  170.       write(Sqd->sfd, &nul, 1) != 1)
  171.   {
  172.     msgapierr=MERR_NODS;
  173.     return FALSE;
  174.   }
  175.  
  176.   /* We got it!  So, update the frame offset, and modify the end-of-file    *
  177.    * offset appropriately.                                                  */
  178.  
  179.   *pfo=Sqd->foEnd;
  180.   Sqd->foEnd=ofs+1;
  181.   return TRUE;
  182. }
  183.  
  184.  
  185.  
  186. /* This function searches the free chain to find a message of at least the  *
  187.  * specified size.  If that fails, we allocate a new frame at EOF.          *
  188.  *                                                                          *
  189.  * This function assumes that we have exclusive access to the Squish base.  */
  190.  
  191. static unsigned near _SquishGetNewFrame(HMSG hmsg, dword dwLen, FOFS *pfoNew,
  192.                                         dword *pdwFrameLen)
  193. {
  194.   SQHDR sqh;
  195.   FOFS fo;
  196.  
  197.   assert(HSqd->fHaveExclusive);
  198.  
  199.   /* Assume we got a new frame */
  200.  
  201.   *pdwFrameLen=0L;
  202.  
  203.   /* Check the free chain */
  204.  
  205.   if (!_SquishProbeFreeChain(hmsg->ha, dwLen, &fo, &sqh, pdwFrameLen))
  206.     return FALSE;
  207.  
  208.   /* If we got a frame from the free chain, remove it */
  209.  
  210.   if (fo)
  211.   {
  212.     if (!_SquishRemoveFreeChain(hmsg->ha, fo, &sqh))
  213.       return FALSE;
  214.  
  215.     *pfoNew=fo;
  216.     return TRUE;
  217.   }
  218.  
  219.   /* Nothing in the free chain, so we will add a new frame at EOF, and      *
  220.    * make it as long as necessary.                                          */
  221.  
  222.   *pdwFrameLen=0;
  223.   return _SquishGetFrameEOF(hmsg->ha, pfoNew, dwLen);
  224. }
  225.  
  226.  
  227.  
  228. /* Given some blank space at offset hmsg->foWrite, we are to create a new   *
  229.  * message frame there and link it into the message chain.  If hmsg->foRead *
  230.  * is blank, just append the message to the end of the chain.  However,     *
  231.  * if foRead is NOT blank, we should set the new frame so that it will      *
  232.  * appear between hmsg->sqhRead.prev and hmsg->sqhRead.next, as we are      *
  233.  * overwriting an old message.                                              *
  234.  *                                                                          *
  235.  * At exit, the header that we just created will be left in hmsg->sqhWrite. *
  236.  *                                                                          *
  237.  * This function assumes that we have exclusive access to the Squish base.  */
  238.  
  239. static unsigned near _SquishLinkMessageFrame(HMSG hmsg, dword dwTotal,
  240.                                              dword dwCtrlLen, dword dwFrameLen)
  241. {
  242.   assert(HSqd->fHaveExclusive);
  243.   assert(dwFrameLen==0 || dwFrameLen >= dwTotal);
  244.  
  245.   /* Fill out default values for the frame header */
  246.  
  247.   hmsg->sqhWrite.id=SQHDRID;
  248.   hmsg->sqhWrite.frame_length=dwFrameLen ? dwFrameLen : dwTotal;
  249.   hmsg->sqhWrite.msg_length=dwTotal;
  250.   hmsg->sqhWrite.clen=dwCtrlLen;
  251.   hmsg->sqhWrite.frame_type=FRAME_NORMAL;
  252.   hmsg->sqhWrite.rsvd=0;
  253.  
  254.  
  255.   /* If we have to link it into the middle of the base */
  256.  
  257.   if (hmsg->foRead)
  258.   {
  259.     /* Set the links for our own frame */
  260.  
  261.     hmsg->sqhWrite.prev_frame=hmsg->sqhRead.prev_frame;
  262.     hmsg->sqhWrite.next_frame=hmsg->sqhRead.next_frame;
  263.  
  264.     /* Fix the link for the message after us, if any */
  265.  
  266.     if (hmsg->sqhWrite.next_frame != NULL_FRAME)
  267.     {
  268.       if (!_SquishSetFramePrev(hmsg->ha, hmsg->sqhWrite.next_frame,
  269.                                hmsg->foWrite))
  270.       {
  271.         return FALSE;
  272.       }
  273.     }
  274.   }
  275.   else
  276.   {
  277.     /* Append this frame at the end of the list */
  278.  
  279.     hmsg->sqhWrite.prev_frame=HSqd->foLast;
  280.     hmsg->sqhWrite.next_frame=NULL_FRAME;
  281.   }
  282.  
  283.   /* Set the links for the message before us */
  284.  
  285.   if (hmsg->sqhWrite.prev_frame != NULL_FRAME)
  286.   {
  287.     if (!_SquishSetFrameNext(hmsg->ha, hmsg->sqhWrite.prev_frame,
  288.                              hmsg->foWrite))
  289.     {
  290.       return FALSE;
  291.     }
  292.   }
  293.  
  294.  
  295.   /* If this has just become the head of this list, fix pointers... */
  296.  
  297.   if (hmsg->sqhWrite.prev_frame==NULL_FRAME)
  298.   {
  299.     /* Sanity check: if we are becoming the beginning frame, we must        *
  300.      * have either replaced the first message, or we are simply creating    *
  301.      * the first message in a Squish base.                                  */
  302.  
  303.     assert(hmsg->foRead==HSqd->foFirst || HSqd->foFirst==NULL_FRAME);
  304.     HSqd->foFirst=hmsg->foWrite;
  305.   }
  306.  
  307.  
  308.   /* If this has just become the tail of the list, fix pointers... */
  309.  
  310.   if (hmsg->sqhWrite.next_frame==NULL_FRAME)
  311.   {
  312.     /* Sanity check: if we are becoming the EOF frame, we must have         *
  313.      * either added a new message, or replaced the old end-of-file message  */
  314.  
  315.     if (hmsg->foRead)
  316.       assert(hmsg->foRead==HSqd->foLast);
  317.  
  318.     HSqd->foLast=hmsg->foWrite;
  319.   }
  320.  
  321.  
  322.   /* If we wrote the message before or after the lastread msg, update ptrs */
  323.  
  324.   if (hmsg->dwMsg==hmsg->ha->cur_msg)
  325.     HSqd->foCur=hmsg->foWrite;
  326.   else if (hmsg->dwMsg==hmsg->ha->cur_msg+1)
  327.     HSqd->foNext=hmsg->foWrite;
  328.   else if (hmsg->dwMsg==hmsg->ha->cur_msg-1)
  329.     HSqd->foPrev=hmsg->foWrite;
  330.  
  331.  
  332.   /* Now update the frame for the message that we just wrote */
  333.  
  334.   return _SquishWriteHdr(hmsg->ha, hmsg->foWrite, &hmsg->sqhWrite);
  335. }
  336.  
  337.  
  338.  
  339. /* Find a frame within the Squish file for writing this message, then       *
  340.  * allocate it.                                                             *
  341.  *                                                                          *
  342.  * This function assumes that we have exclusive access to the Squish base.  */
  343.  
  344. static unsigned near _SquishGetWriteFrame(HMSG hmsg, dword dwTxtTotal,
  345.                                           dword dwCtrlLen)
  346. {
  347.   dword dwTotal=(dword)sizeof(XMSG)+dwTxtTotal+dwCtrlLen;
  348.   dword dwFrameLen=0;
  349.  
  350.   assert(HSqd->fHaveExclusive);
  351.  
  352.   /* If we're writing over an existing message, verify that the             *
  353.    * total and control lengths are not more than what we have already.      */
  354.  
  355.   if (hmsg->wMode==MOPEN_RW || hmsg->wMode==MOPEN_WRITE)
  356.   {
  357.     if (dwTotal > hmsg->sqhRead.msg_length)
  358.     {
  359.       msgapierr=MERR_TOOBIG;
  360.       return FALSE;
  361.     }
  362.  
  363.     /* Copy the read-mode parameters, since we are now writing over this    *
  364.      * message at the specified offset.                                     */
  365.  
  366.     hmsg->foWrite=hmsg->foRead;
  367.     hmsg->sqhWrite=hmsg->sqhRead;
  368.   }
  369.   else if (hmsg->wMode==MOPEN_CREATE)
  370.   {
  371.     /* First, if we are replacing an existing message, release its frame    *
  372.      * to the free chain.                                                   */
  373.  
  374.     if (hmsg->foRead)
  375.     {
  376.       if (! _SquishInsertFreeChain(hmsg->ha, hmsg->foRead, &hmsg->sqhRead))
  377.         return FALSE;
  378.     }
  379.  
  380.     /* We are creating a new message, so we just have to find a frame       *
  381.      * big enough to hold this message.                                     */
  382.  
  383.     if (! _SquishGetNewFrame(hmsg, dwTotal, &hmsg->foWrite, &dwFrameLen))
  384.     {
  385.       /* That failed, so we can't write the message.  However, if we were   *
  386.        * trying to replace an existing message, we have added that message  *
  387.        * to the free chain, but we have NOT linked the other messages       *
  388.        * to skip over it.  The only recourse is to do the linking and       *
  389.        * remove it from the index file (effectively deleting that message)  */
  390.  
  391.  
  392.       if (hmsg->foRead)
  393.       {
  394.         /* Link the old messages over this one */
  395.  
  396.         (void)_SquishSetFrameNext(hmsg->ha, hmsg->sqhRead.prev_frame,
  397.                                   hmsg->sqhRead.next_frame);
  398.  
  399.         (void)_SquishSetFramePrev(hmsg->ha, hmsg->sqhRead.next_frame,
  400.                                   hmsg->sqhRead.prev_frame);
  401.  
  402.         /* Now remove the old one from the index */
  403.  
  404.         (void)_SquishRemoveIndexEntry(HSqd->hix, hmsg->dwMsg, NULL,
  405.                                       &hmsg->sqhRead, TRUE);
  406.       }
  407.  
  408.       hmsg->foWrite=NULL_FRAME;
  409.       return FALSE;
  410.     }
  411.  
  412.     /* Now link this new message frame into our list of messages to write */
  413.  
  414.     if (!_SquishLinkMessageFrame(hmsg, dwTotal, dwCtrlLen, dwFrameLen))
  415.     {
  416.       hmsg->foWrite=NULL_FRAME;
  417.       return FALSE;
  418.     }
  419.   }
  420.  
  421.   hmsg->dwWritePos=0L;
  422.   return TRUE;
  423. }
  424.  
  425.  
  426.  
  427. /* Write the XMSG header to the Squish file */
  428.  
  429. static unsigned near _SquishWriteXmsg(HMSG hmsg, PXMSG pxm, dword *pdwOfs)
  430. {
  431.   XMSG xmsg;
  432.   long ofs=hmsg->foWrite + HSqd->cbSqhdr;
  433.  
  434.   /* If we don't know our UMSGID, retrieve it from the index file */
  435.  
  436.   if (!hmsg->uidUs)
  437.   {
  438.     SQIDX sqi;
  439.  
  440.     /*if (_SquishReadIndexRecord(hmsg->ha, hmsg->dwMsg, &sqi))*/
  441.     if (SidxGet(HSqd->hix, hmsg->dwMsg, &sqi))
  442.       hmsg->uidUs=sqi.umsgid;
  443.   }
  444.  
  445.   /* Make local copy of XMSG struct */
  446.  
  447.   xmsg=*pxm;
  448.  
  449.   /* KLUDGE: Store the UMSGID in the message header so that SQFIX can       *
  450.    * use it to restore the index file, if necessary.  However, if the       *
  451.    * umsgid is not known, make sure that the MSGUID bit is not set.         */
  452.  
  453.   if (!hmsg->uidUs)
  454.   {
  455.     xmsg.attr &= ~MSGUID;
  456.     xmsg.umsgid=(UMSGID)0L;
  457.   }
  458.   else
  459.   {
  460.     xmsg.attr |= MSGUID;
  461.     xmsg.umsgid=hmsg->uidUs;
  462.   }
  463.  
  464.   /* Write the message to disk */
  465.  
  466.   if (ofs != (long)*pdwOfs)
  467.     if (lseek(HSqd->sfd, ofs, SEEK_SET) != ofs)
  468.     {
  469.       msgapierr=MERR_NODS;
  470.       return FALSE;
  471.     }
  472.  
  473.   if (write(HSqd->sfd, (char *)&xmsg, sizeof xmsg) != (int)sizeof xmsg)
  474.   {
  475.     msgapierr=MERR_NODS;
  476.     return FALSE;
  477.   }
  478.  
  479.   *pdwOfs = (dword)ofs + (dword)sizeof xmsg;
  480.  
  481.   return TRUE;
  482. }
  483.  
  484.  
  485.  
  486. /* Write the control information to the Squish file */
  487.  
  488. static unsigned near _SquishWriteCtrl(HMSG hmsg, byte OS2FAR *szCtrl,
  489.                                       dword dwCtrlLen, dword *pdwOfs)
  490. {
  491.   long ofs;
  492.  
  493.   /* We can only write control information on the first pass */
  494.  
  495.   if (hmsg->fWritten)
  496.     return TRUE;
  497.  
  498.  
  499.   /* Make sure that the control information is not longer than
  500.    * what we wrote the first time, if we're updating a message.
  501.    */
  502.  
  503.   if (dwCtrlLen > hmsg->sqhWrite.clen)
  504.     dwCtrlLen=hmsg->sqhWrite.clen;
  505.  
  506.  
  507.   /* Make sure that we don't try to do a write with len==0 */
  508.  
  509.   if (!dwCtrlLen)
  510.     return TRUE;
  511.  
  512.  
  513.   /* Now seek to the appropriate offset */
  514.  
  515.   ofs=hmsg->foWrite + HSqd->cbSqhdr + sizeof(XMSG);
  516.  
  517.  
  518.   /* Write the control information at the appropriate offset */
  519.  
  520.   if (ofs != (long)*pdwOfs)
  521.     if (lseek(HSqd->sfd, ofs, SEEK_SET) != ofs)
  522.     {
  523.       msgapierr=MERR_NODS;
  524.       return FALSE;
  525.     }
  526.  
  527.   if (write(HSqd->sfd, (char *)szCtrl, (unsigned)dwCtrlLen) != (int)dwCtrlLen)
  528.   {
  529.     msgapierr=MERR_NODS;
  530.     return FALSE;
  531.   }
  532.  
  533.   *pdwOfs=(dword)ofs + dwCtrlLen;
  534.  
  535.   return TRUE;
  536. }
  537.  
  538.  
  539.  
  540. /* Now write the message body, appending if necessary */
  541.  
  542. static unsigned near _SquishWriteTxt(HMSG hmsg, unsigned fAppend,
  543.                                      byte OS2FAR *szTxt, dword dwTxtLen,
  544.                                      dword *pdwOfs)
  545. {
  546.   dword dwMaxWrite;
  547.   long ofs;
  548.  
  549.   /* Figure out where to start writing text */
  550.  
  551.   ofs=hmsg->foWrite + (long)HSqd->cbSqhdr + (long)sizeof(XMSG)
  552.                     + (long)hmsg->sqhWrite.clen;
  553.  
  554.   /* Figure out how much we can write, at most */
  555.  
  556.   dwMaxWrite=hmsg->sqhWrite.msg_length - sizeof(XMSG) - hmsg->sqhWrite.clen;
  557.  
  558.   /* If we're appending to existing text, make sure that we adjust properly */
  559.  
  560.   if (fAppend)
  561.   {
  562.     ofs += (long)hmsg->dwWritePos;
  563.     dwMaxWrite -= hmsg->dwWritePos;
  564.   }
  565.  
  566.   dwMaxWrite=min(dwMaxWrite, dwTxtLen);
  567.  
  568.   /* Now seek to the right spot and write the message text */
  569.  
  570.   if (*pdwOfs != (dword)ofs)
  571.     if (lseek(HSqd->sfd, ofs, SEEK_SET) != ofs)
  572.     {
  573.       msgapierr=MERR_NODS;
  574.       return FALSE;
  575.     }
  576.  
  577.   if (write(HSqd->sfd, (char *)szTxt, (unsigned)dwMaxWrite) != (int)dwMaxWrite)
  578.   {
  579.     msgapierr=MERR_NODS;
  580.     return FALSE;
  581.   }
  582.  
  583.   *pdwOfs = (dword)ofs + dwMaxWrite;
  584.  
  585.   /* Update the pointer in case we append to this msg in the future */
  586.  
  587.   hmsg->dwWritePos += dwMaxWrite;
  588.   return TRUE;
  589. }
  590.  
  591.  
  592.  
  593. /* Update the index at offset hmsg->dwMsg with the information given in     *
  594.  * in the XMSG structure.                                                   */
  595.  
  596. static unsigned near _SquishUpdateIndex(HMSG hmsg, PXMSG pxm)
  597. {
  598.   SQIDX sqi;
  599.  
  600.   if (!SidxGet(HSqd->hix, hmsg->dwMsg, &sqi))
  601.     return FALSE;
  602.  
  603.   /* Update this with the position of the message and the contents          *
  604.    * of the 'To:' field.                                                    */
  605.  
  606.   sqi.ofs=hmsg->foWrite;
  607.   sqi.hash=SquishHash(pxm->to);
  608.  
  609.   /* If the message has been read, set the high bit of the hash */
  610.  
  611.   if (pxm->attr & MSGREAD)
  612.     sqi.hash |= IDXE_MSGREAD;
  613.  
  614.   return (unsigned)SidxPut(HSqd->hix, hmsg->dwMsg, &sqi);
  615. }
  616.  
  617.  
  618. /* Write a message to a Squish base */
  619.  
  620. sword MAPIENTRY SquishWriteMsg(HMSG hmsg, word fAppend, PXMSG pxm,
  621.                                byte OS2FAR *szTxt, dword dwTxtLen,
  622.                                dword dwTxtTotal,
  623.                                dword dwCtrlLen, byte OS2FAR *szCtrl)
  624. {
  625.   dword dwOfs=(dword)-1L;
  626.  
  627.   /* Make sure that we have appropriate access to this message */
  628.  
  629.   if (MsgInvalidHmsg(hmsg) || !_SquishWriteMode(hmsg))
  630.     return -1;
  631.  
  632.   /* Make sure that szTxt and szCtrl are consistent */
  633.  
  634.   if (!dwTxtLen)
  635.     szTxt=NULL;
  636.  
  637.   if (!dwCtrlLen)
  638.     szCtrl=NULL;
  639.  
  640.   /* If we need to get a frame offset, allocate it here... */
  641.  
  642.   if (!hmsg->foWrite)
  643.   {
  644.     unsigned rc;
  645.  
  646.     /* We need to have an XMSG on the first write to any message */
  647.  
  648.     if (!pxm)
  649.     {
  650.       msgapierr=MERR_BADA;
  651.       return -1;
  652.     }
  653.  
  654.     if (! _SquishExclusiveBegin(hmsg->ha))
  655.       return -1;
  656.  
  657.     rc=_SquishGetWriteFrame(hmsg, dwTxtTotal, dwCtrlLen);
  658.  
  659.     if (! _SquishExclusiveEnd(hmsg->ha) || !rc)
  660.       return -1;
  661.   }
  662.  
  663.   assert(hmsg->foWrite);
  664.  
  665.   /* Now write the various bits of the message */
  666.  
  667.   if (pxm)
  668.     if (!_SquishWriteXmsg(hmsg, pxm, &dwOfs))
  669.       return -1;
  670.  
  671.   if (szCtrl)
  672.     if (!_SquishWriteCtrl(hmsg, szCtrl, dwCtrlLen, &dwOfs))
  673.       return -1;
  674.  
  675.   if (szTxt)
  676.     if (!_SquishWriteTxt(hmsg, fAppend, szTxt, dwTxtLen, &dwOfs))
  677.       return -1;
  678.  
  679.   hmsg->fWritten=TRUE;
  680.  
  681.   /* If this was our first write to this message, update the index entry    *
  682.    * appropriately.                                                         */
  683.  
  684.   if (pxm)
  685.     if (! _SquishUpdateIndex(hmsg, pxm))
  686.       return -1;
  687.  
  688.   return 0;
  689. }
  690.  
  691.  
  692.  
  693.  
  694.