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