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 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <stdlib.h>
35 #include <assert.h>
36 #include <string.h>
37 #include <limits.h>
38 
39 #include <huskylib/compiler.h>
40 
41 #ifdef HAS_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #ifdef HAS_IO_H
45 #  include <io.h>
46 #endif
47 #ifdef HAS_SHARE_H
48 #include <share.h>
49 #endif
50 #ifdef HAS_MALLOC_H
51 #include <malloc.h>
52 #endif
53 
54 #include <huskylib/huskylib.h>
55 
56 /* Swith for build DLL */
57 #define DLLEXPORT
58 #include <huskylib/huskyext.h>
59 
60 #include "old_msg.h"
61 #include "msgapi.h"
62 #include "api_sq.h"
63 #include "api_sqp.h"
64 #include "apidebug.h"
65 
66 #define HixSqd            ((struct _sqdata *)(hix)->ha->apidata)
67 
68 
69 #ifdef __FLAT__
70   #define MORE_SPACE       256      /* Allow for up to 256 additions */
71   #define SEGMENT_SIZE    (MAX_hSINT32/(hSINT32)SQIDX_SIZE)
72   #define SHIFT_SIZE      32768
73 #else
74   #define MORE_SPACE        16      /* Allow for up to 16 additions */
75   #define SEGMENT_SIZE    (32767L/(hSINT32)SQIDX_SIZE)
76   #define SHIFT_SIZE      8192
77 #endif
78 
79 #define fmemmove memmove
80 
81 /* Open the index file and read the index for this area */
82 
_SquishOpenIndex(HAREA ha)83 HIDX _SquishOpenIndex(HAREA ha)
84 {
85   HIDX hix;
86 
87   hix=palloc(sizeof(*hix));
88   if (hix==NULL)
89   {
90     msgapierr=MERR_NOMEM;
91     return NULL;
92   }
93 
94   /* Store the current area handle */
95 
96   hix->id=ID_HIDX;
97   hix->ha=ha;
98   hix->lDeltaLo=-1;
99   hix->lDeltaHi=-1;
100   hix->cSeg=0;
101   hix->fBuffer=0;
102 
103   return hix;
104 }
105 
106 
107 /* This function returns the size of the virtual index */
108 
_SquishIndexSize(HIDX hix)109 dword _SquishIndexSize(HIDX hix)
110 {
111   dword lSize;
112   int i;
113 
114   assert(hix->id==ID_HIDX);
115 
116   if (!hix->fBuffer)
117     lSize=(dword)lseek(HixSqd->ifd, 0L, SEEK_END);
118   else
119   {
120     for (i=0, lSize=0; i < hix->cSeg; i++)
121       lSize += hix->pss[i].dwUsed * (dword)SQIDX_SIZE;
122   }
123 
124   return lSize;
125 }
126 
127 
128 
129 /* Start buffering reads/writes to the index file */
130 
_SquishBeginBuffer(HIDX hix)131 int _SquishBeginBuffer(HIDX hix)
132 {
133   dword dwMsgs;
134   int i;
135 
136   assert(hix->id==ID_HIDX);
137 
138   /* Multiple buffers are ok, but we only need to do it once */
139 
140   if (hix->fBuffer++ != 0)
141     return TRUE;
142 
143   hix->cSeg=(int)(hix->ha->num_msg / SEGMENT_SIZE) + 1;
144 
145   /* Allocate memory for the array of segments */
146 
147   hix->pss=palloc(sizeof(SQIDXSEG) * (unsigned)hix->cSeg);
148   if (hix->pss==NULL)
149   {
150     msgapierr=MERR_NOMEM;
151     hix->fBuffer=0;
152     return FALSE;
153   }
154   dwMsgs=hix->ha->num_msg;                /* Read all messages into memory */
155   /* Find out how many records are in the file */
156 
157   hix->lAllocatedRecords=lseek(HixSqd->ifd, 0L, SEEK_END);
158   if (hix->lAllocatedRecords < 0)
159   {
160     msgapierr=MERR_BADF;
161     hix->fBuffer=0;
162     return FALSE;
163   }
164   /* Find out the number of records, not the number of bytes */
165 
166   hix->lAllocatedRecords /= SQIDX_SIZE;
167 
168 
169   /* Read from head of index file */
170 
171   (void)lseek(HixSqd->ifd, 0L, SEEK_SET);
172 
173   /* Repeat for each segment in the index file */
174 
175   for (i=0; i < hix->cSeg; i++)
176   {
177     dword dwSize=min(dwMsgs+MORE_SPACE, (long)SEGMENT_SIZE);
178 
179     /* Try to allocate memory for this segment */
180 
181     hix->pss[i].psqi=farpalloc((size_t)dwSize * (size_t)sizeof(SQIDX));
182     if (hix->pss[i].psqi==NULL)
183     {
184       while (i--)
185         farpfree(hix->pss[i].psqi);
186 
187       pfree(hix->pss);
188 
189       msgapierr=MERR_NOMEM;
190       hix->fBuffer=0;
191       return FALSE;
192     }
193 
194     hix->pss[i].dwMax=dwSize;
195 
196     /* Now read in the messages for this segment */
197 
198     dwSize=min(dwMsgs, SEGMENT_SIZE);
199 
200     if (read_sqidx(HixSqd->ifd, hix->pss[i].psqi, dwSize) != 1)
201     {
202 
203       do
204       {
205         farpfree(hix->pss[i].psqi);
206       }
207       while (i--);
208 
209       pfree(hix->pss);
210 
211       msgapierr=MERR_BADF;
212       hix->fBuffer=0;
213       return FALSE;
214     }
215 
216     /* Decrement the count for msgs in the next segment, if necessary */
217 
218     if (dwSize != SEGMENT_SIZE)
219       dwMsgs=0;
220     else
221       dwMsgs -= SEGMENT_SIZE;
222 
223 
224     hix->pss[i].dwUsed=dwSize;
225   }
226 
227   /* Now we have the whole file in memory */
228 
229   return TRUE;
230 }
231 
232 
233 /* Return a pointer to the 'dwMsg'th message in the buffered index */
234 
sidx(HIDX hix,dword dwMsg)235 static SQIDX far *sidx(HIDX hix, dword dwMsg)
236 {
237   dword dwStart=1L;
238   int i;
239 
240   for (i=0; i < hix->cSeg; i++)
241   {
242     if (dwMsg >= dwStart && dwMsg < dwStart + hix->pss[i].dwUsed)
243       return hix->pss[i].psqi + (size_t)(dwMsg - dwStart);
244 
245     dwStart += hix->pss[i].dwUsed;
246   }
247 
248   return NULL;
249 }
250 
251 
252 /* Get an index from the virtual index file */
253 
SidxGet(HIDX hix,dword dwMsg,SQIDX * psqi)254 int SidxGet(HIDX hix, dword dwMsg, SQIDX *psqi)
255 {
256   SQIDX far *psqiFound;
257 
258   assert(hix->id==ID_HIDX);
259 
260   if (!hix->fBuffer)
261   {
262     (void)lseek(HixSqd->ifd, (long)(dwMsg-1) * (long)SQIDX_SIZE, SEEK_SET);
263 
264     if (read_sqidx(HixSqd->ifd, psqi, 1) != 1)
265     {
266       msgapierr=MERR_BADF;
267       return FALSE;
268     }
269 
270     return TRUE;
271   }
272 
273   psqiFound=sidx(hix, dwMsg);
274 
275   if (!psqiFound)
276     return FALSE;
277 
278   *psqi=*psqiFound;
279   return TRUE;
280 }
281 
282 
283 
284 
285 /* Add a new index record to the end of the array */
286 
_SquishAppendIndexRecord(HIDX hix,SQIDX * psqi)287 static int near _SquishAppendIndexRecord(HIDX hix, SQIDX *psqi)
288 {
289   SQIDXSEG *pss;
290 
291 
292   /* If we need to expand the index file on disk, do so now */
293 
294   if ((long)hix->ha->num_msg > hix->lAllocatedRecords)
295   {
296     long lSize;
297     SQIDX sqi;
298 
299     /* Make room for up to 64 new records */
300 
301     hix->lAllocatedRecords=hix->ha->num_msg+64;
302     lSize=(hix->lAllocatedRecords-1) * (long)SQIDX_SIZE;
303 
304     sqi.ofs=0L;
305     sqi.umsgid=(UMSGID)-1L;
306     sqi.hash=(UMSGID)-1L;
307 
308     /* Write a blank index entry at the appropriate location to fill        *
309      * up the file.                                                         */
310 
311     if (lseek(HixSqd->ifd, lSize, SEEK_SET) != lSize ||
312         write_sqidx(HixSqd->ifd, &sqi, 1) != 1)
313     {
314       msgapierr=MERR_NODS;
315       return FALSE;
316     }
317   }
318 
319   /* If we already have some segments... */
320 
321   if (hix->cSeg)
322   {
323     /* Add to an existing segment */
324 
325     pss=hix->pss + hix->cSeg-1;
326 
327     /* If the record fits within this segment, just append it. */
328 
329     if (pss->dwUsed < pss->dwMax)
330     {
331       pss->psqi[(size_t)pss->dwUsed]=*psqi;
332       pss->dwUsed++;
333       return TRUE;
334     }
335 
336     /* If we can expand this segment by reallocating memory... */
337 
338     if (pss->dwMax < SEGMENT_SIZE)
339     {
340       SQIDX far *psqiNew;
341 
342       assert(pss->dwMax >= pss->dwUsed);
343 
344       /* Don't use realloc because we cannot afford to lose the info that we  *
345        * already have!                                                        */
346 
347       psqiNew=farpalloc(((size_t)pss->dwMax + MORE_SPACE) * SQIDX_SIZE);
348       if (psqiNew==NULL)
349       {
350         msgapierr=MERR_NOMEM;
351         return FALSE;
352       }
353 
354       (void) fmemmove(psqiNew,
355                       pss->psqi,
356                       (size_t)pss->dwUsed * (size_t)SQIDX_SIZE);
357 
358       psqiNew[(size_t)pss->dwUsed]=*psqi;
359 
360       pss->dwUsed++;
361       pss->dwMax += MORE_SPACE;
362 
363       farpfree(pss->psqi);
364       pss->psqi=psqiNew;
365       return TRUE;
366     }
367   }
368 
369 
370   /* If we arrived here, we either have no segments, or all of our          *
371    * existing segments are full.  To handle this, we need to reallocate     *
372    * the array of pointers to segments and add a new one.                   */
373 
374   pss=palloc(sizeof(SQIDXSEG) * (size_t)(hix->cSeg+1));
375   if (pss==NULL)
376   {
377     msgapierr=MERR_NOMEM;
378     return FALSE;
379   }
380 
381   (void)memmove(pss, hix->pss, (size_t)hix->cSeg * sizeof(SQIDXSEG));
382   pfree(hix->pss);
383   hix->pss=pss;
384 
385   /* Allocate memory for the new segment */
386 
387   hix->pss[hix->cSeg].psqi=farpalloc(MORE_SPACE * SQIDX_SIZE);
388   if (hix->pss[hix->cSeg].psqi==NULL)
389   {
390     msgapierr=MERR_NOMEM;
391     return FALSE;
392   }
393 
394   pss=hix->pss + hix->cSeg;
395 
396   /* Add the specified record to our indices */
397 
398   pss->dwUsed=1;
399   pss->dwMax=MORE_SPACE;
400   *pss->psqi=*psqi;
401 
402   /* Increment the segment count */
403 
404   hix->cSeg++;
405   return TRUE;
406 }
407 
408 
409 /* Store an index entry in the virtual index file */
410 
SidxPut(HIDX hix,dword dwMsg,SQIDX * psqi)411 int SidxPut(HIDX hix, dword dwMsg, SQIDX *psqi)
412 {
413   SQIDX far *psqiFound;
414   int rc;
415 
416   assert(hix->id==ID_HIDX);
417 
418   if (!hix->fBuffer)
419   {
420     (void)lseek(HixSqd->ifd, (long)(dwMsg-1) * (long)SQIDX_SIZE, SEEK_SET);
421 
422     if (write_sqidx(HixSqd->ifd, psqi, 1) != 1)
423     {
424       msgapierr=MERR_NODS;
425       return FALSE;
426     }
427 
428     return TRUE;
429   }
430 
431   /* If we can't find the appropriate index record */
432 
433   psqiFound=sidx(hix, dwMsg);
434   if (psqiFound==NULL)
435   {
436     rc=FALSE;
437 
438     /* If the index is out of range, only create a new record if it's       *
439      * to be placed at EOF.                                                 */
440 
441     if (dwMsg==hix->ha->num_msg+1)
442       rc=_SquishAppendIndexRecord(hix, psqi);
443   }
444   else
445   {
446     *psqiFound=*psqi;
447     rc=TRUE;
448   }
449 
450   if (rc)
451   {
452     if (hix->lDeltaLo==-1 || hix->lDeltaLo > (long)dwMsg)
453       hix->lDeltaLo=(long)dwMsg;
454 
455     if (hix->lDeltaHi==-1 || hix->lDeltaHi < (long)dwMsg)
456       hix->lDeltaHi=(long)dwMsg;
457   }
458 
459   return rc;
460 }
461 
462 
463 /* Delete an entry from the index */
464 
_SquishRemoveIndexEntry(HIDX hix,dword dwMsg,SQIDX * psqiOut,SQHDR * psqh,int fFixPointers)465 unsigned _SquishRemoveIndexEntry(HIDX hix, dword dwMsg, SQIDX *psqiOut,
466                                  SQHDR *psqh, int fFixPointers)
467 {
468   SQIDX sqi;
469   char *pcBuf;
470   int got, i;
471 
472   assert(hix->id==ID_HIDX);
473 
474   /* Create a blank record for writing at the end */
475 
476   sqi.ofs=NULL_FRAME;
477   sqi.umsgid=(UMSGID)-1L;
478   sqi.hash=(dword)-1L;
479 
480   if (hix->fBuffer)
481   {
482     dword dwStart=1L;
483 
484     /* Find the segment containing the deleted message */
485 
486     for (i=0; i < hix->cSeg; i++)
487     {
488       /* If it's in this segment */
489 
490       if (dwMsg >= dwStart && dwMsg < dwStart + hix->pss[i].dwUsed)
491       {
492         int j=(int)(dwMsg-dwStart);
493         unsigned rc=TRUE;
494 
495         /* If caller wants copy of deleted record */
496 
497         if (psqiOut)
498           *psqiOut=hix->pss[i].psqi[j];
499 
500         /* Shift the rest of the text over this segment */
501 
502         (void)fmemmove(hix->pss[i].psqi+j, hix->pss[i].psqi+j+1,
503                        (size_t)(hix->pss[i].dwUsed - (dword)j - (dword)1)
504                           * (size_t)SQIDX_SIZE);
505 
506         hix->pss[i].dwUsed--;
507 
508         if (!_SquishAppendIndexRecord(hix, &sqi))
509           rc=FALSE;
510 
511         if (hix->lDeltaLo==-1 || hix->lDeltaLo > (long)dwMsg)
512           hix->lDeltaLo=(long)dwMsg;
513 
514         hix->lDeltaHi=(long)_SquishIndexSize(hix) / (long)SQIDX_SIZE;
515 
516         if (fFixPointers && rc)
517           return _SquishFixMemoryPointers(hix->ha, dwMsg, psqh);
518         else
519           return rc;
520       }
521 
522       dwStart += hix->pss[i].dwUsed;
523     }
524 
525     /* Huh?  Message not in index! */
526 
527     return FALSE;
528   }
529 
530 
531   /* Else if it's not buffered: */
532 
533 
534   (void)lseek(HixSqd->ifd, (long)dwMsg * (long)SQIDX_SIZE, SEEK_SET);
535 
536   pcBuf=palloc(SHIFT_SIZE);
537   if (pcBuf==NULL)
538   {
539     msgapierr=MERR_NOMEM;
540     return FALSE;
541   }
542 
543   /* Only shifting - read_sqidx() is not required */
544   while ((got=read(HixSqd->ifd, pcBuf, SHIFT_SIZE)) > 0)
545   {
546     /* Skip back to one position before this index entry */
547 
548     (void)lseek(HixSqd->ifd, -(long)got - SQIDX_SIZE, SEEK_CUR);
549 
550     if (write(HixSqd->ifd, pcBuf, (unsigned)got) != got)
551     {
552       msgapierr=MERR_BADF;
553       return FALSE;
554     }
555 
556     (void)lseek(HixSqd->ifd, (long)SQIDX_SIZE, SEEK_CUR);
557   }
558 
559   pfree(pcBuf);
560 
561   /* Now write the last entry to stomp over the index element that is at    *
562    * the end of the file.                                                   */
563 
564   (void)lseek(HixSqd->ifd, -(long)SQIDX_SIZE, SEEK_CUR);
565 
566   if (write_sqidx(HixSqd->ifd, &sqi, 1) != 1)
567   {
568     msgapierr=MERR_BADF;
569     return FALSE;
570   }
571 
572   if (fFixPointers)
573     return _SquishFixMemoryPointers(hix->ha, dwMsg, psqh);
574   else
575     return TRUE;
576 }
577 
578 
579 
580 /* Close an index file handle */
581 
_SquishCloseIndex(HIDX hix)582 unsigned _SquishCloseIndex(HIDX hix)
583 {
584   assert(hix->id==ID_HIDX);
585 
586   while (hix->fBuffer)
587     if (!_SquishEndBuffer(hix))
588       return FALSE;
589 
590   hix->id=0;
591 
592   pfree(hix);
593 
594   return TRUE;
595 }
596 
597 
598 
599 /* Dump the index file buffer */
600 
_SquishEndBuffer(HIDX hix)601 int _SquishEndBuffer(HIDX hix)
602 {
603   int i;
604   int rc=TRUE;
605   long lSize;
606 
607   assert(hix->id==ID_HIDX);
608 
609   if (hix->fBuffer==0)
610     return FALSE;
611 
612   if (--hix->fBuffer != 0)
613     return TRUE;
614 
615 
616   /* Reduce the index file to the size that it really should be */
617 
618   lSize=(long)hix->ha->num_msg * (long)SQIDX_SIZE;
619   setfsize(HixSqd->ifd, lSize);
620 
621 
622   /* If we need to rewrite the index */
623 
624   if (hix->lDeltaLo != -1 && hix->lDeltaHi != -1)
625   {
626     dword dwStart=1;
627 
628     (void) lseek(HixSqd->ifd,
629                  (hix->lDeltaLo - 1L) * (long)SQIDX_SIZE,
630                  SEEK_SET);
631 
632     for (i=0; i < hix->cSeg; i++)
633     {
634       /* If this buffer is within the "delta" range */
635 
636       if ((long)dwStart + (long)hix->pss[i].dwUsed > hix->lDeltaLo &&
637           (long)dwStart <= hix->lDeltaHi)
638       {
639         size_t j, size;
640 
641         if ((long)dwStart > hix->lDeltaLo)
642           j=0;
643         else
644           j=(size_t)(hix->lDeltaLo-(long)dwStart);
645 
646         if ((long)dwStart + (long)hix->pss[i].dwUsed > hix->lDeltaHi)
647           size = (size_t)(hix->lDeltaHi - (long)dwStart + 1L);
648         else
649           size = (size_t)(hix->pss[i].dwUsed);
650 
651         size -= j;
652 
653         if (rc)
654         {
655           if (write_sqidx(HixSqd->ifd, (hix->pss[i].psqi+j), size)
656                  != 1)
657 
658           {
659             msgapierr=MERR_NODS;
660             rc=FALSE;
661           }
662         }
663       }
664 
665       dwStart += hix->pss[i].dwUsed;
666     }
667   }
668 
669 
670   /* Free the memory used by these segments */
671 
672   for (i=0; i < hix->cSeg; i++)
673     farpfree(hix->pss[i].psqi);
674 
675   pfree(hix->pss);
676   hix->cSeg=0;
677 
678   return rc;
679 }
680 
681 /* Free the index file buffer */
682 
_SquishFreeBuffer(HIDX hix)683 int _SquishFreeBuffer(HIDX hix)
684 {
685   int i;
686   int rc=TRUE;
687 
688   assert(hix->id==ID_HIDX);
689 
690   if (hix->fBuffer==0)
691     return FALSE;
692 
693   if (--hix->fBuffer != 0)
694     return TRUE;
695 
696 
697   /* Free the memory used by these segments */
698 
699   for (i=0; i < hix->cSeg; i++)
700     farpfree(hix->pss[i].psqi);
701 
702   pfree(hix->pss);
703   hix->cSeg=0;
704 
705   return rc;
706 }
707 
708