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 <errno.h>
35 #include <assert.h>
36 #include <stdio.h>
37 #include <stdlib.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 /* Read the base header from the beginning of the .sqd file */
67 
_SquishReadBaseHeader(HAREA ha,SQBASE * psqb)68 unsigned _SquishReadBaseHeader(HAREA ha, SQBASE *psqb)
69 {
70   if (lseek(Sqd->sfd, 0L, SEEK_SET) != 0 ||
71       read_sqbase(Sqd->sfd, psqb) != 1)
72   {
73     if (errno==EACCES || errno==-1)
74       msgapierr=MERR_SHARE;
75     else
76       msgapierr=MERR_BADF;
77 
78     return FALSE;
79   }
80 
81   return TRUE;
82 }
83 
84 
85 
86 
87 /* Write the base header back to the beginning of the .sqd file */
88 
_SquishWriteBaseHeader(HAREA ha,SQBASE * psqb)89 unsigned _SquishWriteBaseHeader(HAREA ha, SQBASE *psqb)
90 {
91   if (lseek(Sqd->sfd, 0L, SEEK_SET) != 0 ||
92       write_sqbase(Sqd->sfd, psqb) != 1)
93   {
94     msgapierr=MERR_NODS;
95     return FALSE;
96   }
97 
98   return TRUE;
99 }
100 
101 
102 
103 /* Release the specified frame to the free chain.  The frame is             *
104  * located at offset 'fo', and the header at that offset has                *
105  * already been loaded into *psqh.  This function does **not**              *
106  * change the links of other messages that may point to this                *
107  * message; it simply threads the current message into the free chain.      *
108  *                                                                          *
109  * This function assumes that we have exclusive access to the Squish base.  */
110 
_SquishInsertFreeChain(HAREA ha,FOFS fo,SQHDR * psqh)111 unsigned _SquishInsertFreeChain(HAREA ha, FOFS fo, SQHDR *psqh)
112 {
113   SQHDR sqh=*psqh;
114 
115   assert(Sqd->fHaveExclusive);
116 
117   sqh.id=SQHDRID;
118   sqh.frame_type=FRAME_FREE;
119   sqh.msg_length=sqh.clen=0L;
120 
121   /* If we have no existing free frames, then this is easy */
122 
123   if (Sqd->foLastFree==NULL_FRAME)
124   {
125     sqh.prev_frame=NULL_FRAME;
126     sqh.next_frame=NULL_FRAME;
127 
128     /* Try to write this frame back to the file */
129 
130     if (! _SquishWriteHdr(ha, fo, &sqh))
131       return FALSE;
132 
133     Sqd->foFree=Sqd->foLastFree=fo;
134     return TRUE;
135   }
136 
137 
138   /* There is an existing frame, so we must append to the end of the        *
139    * chain.                                                                 */
140 
141   sqh.prev_frame=Sqd->foLastFree;
142   sqh.next_frame=NULL_FRAME;
143 
144 
145   /* Update the last chain in the free list, pointing it to us */
146 
147   if (!_SquishSetFrameNext(ha, sqh.prev_frame, fo))
148     return FALSE;
149 
150 
151   /* Try to write the current frame to disk */
152 
153   if (_SquishWriteHdr(ha, fo, &sqh))
154   {
155     Sqd->foLastFree=fo;
156     return TRUE;
157   }
158   else
159   {
160     /* The write failed, so just hope that we can undo what we did        *
161      * earlier.                                                           */
162 
163     (void)_SquishSetFrameNext(ha, sqh.prev_frame, NULL_FRAME);
164     return FALSE;
165   }
166 }
167 
168 
169 
170 /* Change the 'next' link of the foModify frame to the value foValue */
171 
_SquishSetFrameNext(HAREA ha,FOFS foModify,FOFS foValue)172 unsigned _SquishSetFrameNext(HAREA ha, FOFS foModify, FOFS foValue)
173 {
174   SQHDR sqh;
175 
176   if (!_SquishReadHdr(ha, foModify, &sqh))
177     return FALSE;
178 
179   sqh.next_frame=foValue;
180 
181   return _SquishWriteHdr(ha, foModify, &sqh);
182 }
183 
184 
185 
186 /* Change the 'prior' link of the foModify frame to the value foValue */
187 
_SquishSetFramePrev(HAREA ha,FOFS foModify,FOFS foValue)188 unsigned _SquishSetFramePrev(HAREA ha, FOFS foModify, FOFS foValue)
189 {
190   SQHDR sqh;
191 
192   if (!_SquishReadHdr(ha, foModify, &sqh))
193     return FALSE;
194 
195   sqh.prev_frame=foValue;
196 
197   return _SquishWriteHdr(ha, foModify, &sqh);
198 }
199 
200 
201 
202 /* This function ensures that the message handle is readable */
203 
_SquishReadMode(HMSG hmsg)204 unsigned _SquishReadMode(HMSG hmsg)
205 {
206   if (hmsg->wMode != MOPEN_READ && hmsg->wMode != MOPEN_RW)
207   {
208     msgapierr=MERR_EACCES;
209     return FALSE;
210   }
211 
212   return TRUE;
213 }
214 
215 
216 
217 /* This function ensures that the message handle is writable */
218 
_SquishWriteMode(HMSG hmsg)219 unsigned _SquishWriteMode(HMSG hmsg)
220 {
221   if (hmsg->wMode != MOPEN_CREATE && hmsg->wMode != MOPEN_WRITE &&
222       hmsg->wMode != MOPEN_RW)
223   {
224     msgapierr=MERR_EACCES;
225     return FALSE;
226   }
227 
228   return TRUE;
229 }
230 
231 
232 
233 /* Translate a message number into a frame offset for area 'ha' */
234 
_SquishGetFrameOfs(HAREA ha,dword dwMsg)235 FOFS _SquishGetFrameOfs(HAREA ha, dword dwMsg)
236 {
237   SQIDX sqi;
238 
239 
240   msgapierr=MERR_NOENT;
241 
242   /* Check for simple stuff that we can handle by following our own         *
243    * linked list.                                                           */
244 
245   if (dwMsg==ha->cur_msg)
246     return Sqd->foCur;
247   else if (dwMsg==ha->cur_msg-1)
248     return Sqd->foPrev;
249   else if (dwMsg==ha->cur_msg+1)
250     return Sqd->foNext;
251 
252   /* We couldn't just follow the linked list, so we will have to consult    *
253    * the Squish index file to find it.                                      */
254 
255   if (! SidxGet(Sqd->hix, dwMsg, &sqi))
256     return NULL_FRAME;
257 
258   return sqi.ofs;
259 }
260 
261 
262 /* Read the Squish header 'psqh' from the specified frame offset */
263 
_SquishReadHdr(HAREA ha,FOFS fo,SQHDR * psqh)264 unsigned _SquishReadHdr(HAREA ha, FOFS fo, SQHDR *psqh)
265 {
266   /* Ensure that we are reading a valid frame header */
267 
268   if (fo < SQBASE_SIZE)
269   {
270     msgapierr=MERR_BADA;
271     return FALSE;
272   }
273 
274   /* Seek and read the header */
275 
276   if (fo >= Sqd->foEnd ||
277       lseek(Sqd->sfd, fo, SEEK_SET) != fo ||
278       read_sqhdr(Sqd->sfd, psqh) != 1 ||
279       psqh->id != SQHDRID)
280   {
281     msgapierr=MERR_BADF;
282     return FALSE;
283   }
284 
285   return TRUE;
286 }
287 
288 
289 
290 /* Write the Squish header 'psqh' to the specified frame offset */
291 
_SquishWriteHdr(HAREA ha,FOFS fo,SQHDR * psqh)292 unsigned _SquishWriteHdr(HAREA ha, FOFS fo, SQHDR *psqh)
293 {
294   /* Make sure that we don't write over the file header */
295 
296   if (fo < SQBASE_SIZE)
297   {
298     msgapierr=MERR_BADA;
299     return FALSE;
300   }
301 
302   if (lseek(Sqd->sfd, fo, SEEK_SET) != fo ||
303       write_sqhdr(Sqd->sfd, psqh) != 1)
304   {
305     msgapierr=MERR_NODS;
306     return FALSE;
307   }
308 
309   return TRUE;
310 }
311 
312 
313 /* This function fixes the in-memory pointers after message dwMsg was       *
314  * removed from the index file.                                             *
315  *                                                                          *
316  * This function assumes that we have exclusive access to the Squish base.  */
317 
_SquishFixMemoryPointers(HAREA ha,dword dwMsg,SQHDR * psqh)318 unsigned _SquishFixMemoryPointers(HAREA ha, dword dwMsg, SQHDR *psqh)
319 {
320   assert(Sqd->fHaveExclusive);
321 
322   /* Adjust the first/last message pointers */
323 
324   if (dwMsg==1)
325     Sqd->foFirst=psqh->next_frame;
326 
327   if (dwMsg==ha->num_msg)
328     Sqd->foLast=psqh->prev_frame;
329 
330 
331   /* Now fix up the in-memory version of the prior/next links */
332 
333   if (dwMsg==ha->cur_msg+1)
334     Sqd->foNext=psqh->next_frame;
335 
336   if (dwMsg==ha->cur_msg-1)
337     Sqd->foPrev=psqh->prev_frame;
338 
339 
340   /* If we killed the message that we are on, it's a special case */
341 
342   if (dwMsg==ha->cur_msg)
343   {
344     SQHDR sqh;
345 
346     /* Go to the header of the prior msg */
347 
348     if (!_SquishReadHdr(ha, psqh->prev_frame, &sqh))
349     {
350       /* That does not exist, so go to msg 0 */
351 
352       Sqd->foCur=Sqd->foPrev=NULL_FRAME;
353       Sqd->foNext=Sqd->foFirst;
354       ha->cur_msg=0;
355     }
356     else
357     {
358       /* Otherwise, adjust pointers appropriately */
359 
360       Sqd->foCur=psqh->prev_frame;
361       Sqd->foPrev=sqh.prev_frame;
362       Sqd->foNext=sqh.next_frame;
363       ha->cur_msg--;
364     }
365   }
366   else
367   {
368     /* We didn't kill the current msg, so just decrement cur_msg if         *
369      * we were higher than the deleted message.                             */
370 
371     if (ha->cur_msg >= dwMsg)
372       ha->cur_msg--;
373   }
374 
375 
376   /* Adjust the message numbers appropriately */
377 
378   ha->num_msg--;
379   ha->high_msg--;
380 
381   if (ha->high_water >= dwMsg)
382     ha->high_water--;
383 
384   return TRUE;
385 }
386 
387 
388 
389 
390 
391 /* Write the index back to disk and free the associated memory */
392 
_SquishFreeIndex(HAREA ha,dword dwMsg,SQIDX * psqi,dword dwIdxSize,unsigned fWrite)393 unsigned _SquishFreeIndex(HAREA ha, dword dwMsg, SQIDX *psqi,
394                           dword dwIdxSize, unsigned fWrite)
395 {
396   unsigned rc=TRUE;
397   long ofs;
398 
399   unused(dwIdxSize);
400 
401 #ifdef __WATCOMC__
402 dwIdxSize=dwIdxSize; /* To prevent warning */
403 #endif
404 
405   if (fWrite)
406   {
407     /* Seek to the offset of the message that we want to delete */
408 
409     ofs=((long)dwMsg-1L) * (long)SQIDX_SIZE;
410 
411     /* Write it back out to disk at the same position */
412 
413     rc=(lseek(Sqd->ifd, ofs, SEEK_SET)==ofs &&
414         write_sqidx(Sqd->ifd, psqi, ((long)dwMsg-1L)) == 1);
415   }
416 
417   pfree(psqi);
418 
419   return rc;
420 }
421 
422 
423 
424 #if 0
425 /* Read from the index file, starting at the dwMsg'th record */
426 
427 SQIDX * _SquishAllocIndex(HAREA ha, dword dwMsg, dword *pdwIdxSize)
428 {
429   SQIDX *psqi;
430   dword dwIdxSize;
431   long ofs;
432 
433   /* We only need enough memory to read in the index file from the point    *
434    * that we are deleting a message.                                        */
435 
436   dwIdxSize = ((long)ha->num_msg - (long)dwMsg + 1L) * (long)sizeof(SQIDX);
437 
438 
439   /* Handle problems that we may have when working on a 16-bit platform */
440 
441   if (dwIdxSize > 65000L)
442   {
443   }
444 
445   /* Allocate memory for handling the index */
446 
447   if ((psqi=palloc((size_t)dwIdxSize))==NULL)
448   {
449     msgapierr=MERR_NOMEM;
450     return NULL;
451   }
452 
453 
454   /* Seek to the offset of the message that we want to delete */
455 
456   ofs=((long)dwMsg-1L) * (long)SQIDX_SIZE;
457 
458 
459   /* Now read it from disk */
460 
461   if (lseek(Sqd->ifd, ofs, SEEK_SET) != ofs ||
462       read_sqidx(Sqd->ifd, psqi, ((long)ha->num_msg - (long)dwMsg + 1L)) != 1)
463   {
464     msgapierr=MERR_BADF;
465     pfree(psqi);
466     return NULL;
467   }
468 
469   *pdwIdxSize=dwIdxSize;
470   return psqi;
471 }
472 
473 /* This function removes the specified message number from the Squish index *
474  * file, moving the rest of the index file back over the message number to  *
475  * fill in the gaps.                                                        *
476  *                                                                          *
477  * This function also adjusts the message number pointers everywhere to     *
478  * accomodate for the deletion of this message.                             *
479  *                                                                          *
480  * This function assumes that we have exclusive access to the Squish base.  */
481 
482 unsigned _SquishRemoveIndex(HAREA ha, dword dwMsg, SQIDX *psqiOut, SQHDR *psqh)
483 {
484   dword dwIdxSize;
485   SQIDX *psqiLast;
486   SQIDX *psqi;
487   unsigned rc;
488 
489   assert(Sqd->fHaveExclusive);
490 
491   /* Read the index from disk */
492 
493   if ((psqi=_SquishAllocIndex(ha, dwMsg, &dwIdxSize))==NULL)
494     return FALSE;
495 
496 
497   /* If the caller wants a copy of the record that we are deleting... */
498 
499   if (psqiOut)
500     memmove(psqiOut, psqi, sizeof(SQIDX));
501 
502 
503   /* Shift everything over by one to accomodate for the deleted msg */
504 
505   memmove(psqi, psqi+1, (size_t)dwIdxSize-sizeof(SQIDX));
506 
507 
508   /* Blank out the last index pointer in the file so that it is invalid */
509 
510   psqiLast=psqi + (ha->num_msg - (long)dwMsg);
511 
512   psqiLast->ofs=NULL_FRAME;
513   psqiLast->umsgid=(UMSGID)-1L;
514   psqiLast->hash=(dword)-1L;
515 
516 
517   /* Write it back to disk and free memory */
518 
519   rc=_SquishFreeIndex(ha, dwMsg, psqi, dwIdxSize, TRUE);
520 
521 
522   /* If the delete succeeded, adjust the memory pointers */
523 
524   if (rc)
525     rc=_SquishFixMemoryPointers(ha, dwMsg, psqh);
526 
527   return rc;
528 }
529 #endif
530 
531