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