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_area.c 330 2020-04-26 12:47:01Z dukelsky $";
26  #pragma on(unreferenced)
27  */
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 
35 #define _SMAPI_EXT
36 #include "compiler.h"
37 
38 #define MSGAPI_HANDLERS
39 #define MSGAPI_NO_OLD_TYPES
40 
41 #ifdef HAS_IO_H
42     #include <io.h>
43 #endif
44 
45 #ifdef HAS_SHARE_H
46     #include <share.h>
47 #endif
48 
49 #ifdef HAS_UNISTD_H
50     #include <unistd.h>
51 #endif
52 
53 #include <errno.h>
54 
55 #ifdef HAS_MALLOC_H
56     #include <malloc.h>
57 #endif
58 
59 #include "memory.h"
60 #include "ftnaddr.h"
61 #include "locking.h"
62 /* Swith for build DLL */
63 #define DLLEXPORT
64 
65 
66 #include "old_msg.h"
67 #include "msgapi.h"
68 #include "api_sq.h"
69 #include "api_sqp.h"
70 #include "apidebug.h"
71 /* Linked list of open Squish areas */
72 static HAREA haOpen   = NULL;
73 static char dot_sqd[] = ".sqd";
74 static char dot_sqi[] = ".sqi";
75 static char dot_sql[] = ".sql";
76 static char dot_lck[] = ".lck";
77 static unsigned near _SquishUnlinkBaseFiles(byte *);
78 
SquishDeleteBase(char * name)79 int SquishDeleteBase(char * name)
80 {
81     return (int)_SquishUnlinkBaseFiles((byte *)name);
82 }
83 
84 /* Exitlist routine to make sure that all areas are closed */
_SquishCloseOpenAreas(void)85 unsigned _SquishCloseOpenAreas(void)
86 {
87     HAREA ha, haNext;
88 
89     /* If nothing to close, just get out. */
90     if(!haOpen)
91     {
92         return TRUE;
93     }
94 
95     for(ha = haOpen; ha; ha = haNext)
96     {
97         haNext = Sqd->haNext;
98         apiSquishCloseArea(ha);
99     }
100     haOpen = NULL;
101     return TRUE;
102 }
103 
104 /* List of function pointers to use in Squish areas */
105 static struct _apifuncs sq_funcs =
106 {
107     apiSquishCloseArea,
108     apiSquishOpenMsg,
109     apiSquishCloseMsg,
110     apiSquishReadMsg,
111     apiSquishWriteMsg,
112     apiSquishKillMsg,
113     apiSquishLock,
114     apiSquishUnlock,
115     apiSquishSetCurPos,
116     apiSquishGetCurPos,
117     apiSquishMsgnToUid,
118     apiSquishUidToMsgn,
119     apiSquishGetHighWater,
120     apiSquishSetHighWater,
121     apiSquishGetTextLen,
122     apiSquishGetCtrlLen,
123     apiSquishGetNextUid,
124     apiSquishGetHash
125 };
126 
127 /* Open the .SQD and .SQI files for an existing base */
_SquishOpenBaseFiles(HAREA ha,byte * szName,int mode)128 static unsigned near _SquishOpenBaseFiles(HAREA ha, byte * szName, int mode)
129 {
130     char szFile[PATHLEN];
131 
132     (void)strcpy(szFile, (char *)szName);
133     (void)strcat(szFile, dot_sqd);
134     Sqd->sfd = sopen(szFile, mode | O_RDWR | O_BINARY, SH_DENYNO, FILEMODE(ha->isecho));
135 
136     if((Sqd->sfd == -1) && (mode & O_CREAT) && (errno == ENOENT))
137     {
138         char * slash = strrchr((char *)szName, PATH_DELIM);
139 
140         if(slash)
141         {
142             *slash = '\0';
143             _createDirectoryTree((char *)szName);
144             *slash = PATH_DELIM;
145         }
146 
147         Sqd->sfd = sopen(szFile, mode | O_RDWR | O_BINARY, SH_DENYNO, FILEMODE(ha->isecho));
148     }
149 
150     if(Sqd->sfd == -1)
151     {
152         msgapierr = MERR_NOENT;
153         return FALSE;
154     }
155 
156     (void)strcpy(szFile, (char *)szName);
157     (void)strcat(szFile, dot_sqi);
158     Sqd->ifd = sopen(szFile, mode | O_RDWR | O_BINARY, SH_DENYNO, FILEMODE(ha->isecho));
159 
160     if(Sqd->ifd == -1)
161     {
162         (void)close(Sqd->sfd);
163         msgapierr = MERR_NOENT;
164         return FALSE;
165     }
166 
167 #ifdef ALTLOCKING
168     (void)strcpy(szFile, szName);
169     (void)strcat(szFile, dot_lck);
170     ha->lck_path = sstrdup(szFile);
171 #endif
172 
173     return TRUE;
174 } /* _SquishOpenBaseFiles */
175 
176 /* Delete the .SQD and .SQI files for an area */
_SquishUnlinkBaseFiles(byte * szName)177 static unsigned near _SquishUnlinkBaseFiles(byte * szName)
178 {
179     char szFile[PATHLEN];
180     unsigned rc = TRUE;
181 
182     if(!szName || (szName && (strlen((char *)szName) + 5 > PATHLEN)))
183     {
184         return FALSE;
185     }
186 
187     (void)strcpy(szFile, (char *)szName);
188     (void)strcat(szFile, dot_sqd);
189 
190     if(unlink(szFile) != 0)
191     {
192         rc = FALSE;
193     }
194 
195     (void)strcpy(szFile, (char *)szName);
196     (void)strcat(szFile, dot_sqi);
197 
198     if(unlink(szFile) != 0)
199     {
200         rc = FALSE;
201     }
202 
203     (void)strcpy(szFile, (char *)szName);
204     (void)strcat(szFile, dot_sql);
205 
206     if(unlink(szFile) != 0 && errno != ENOENT)
207     {
208         rc = FALSE;
209     }
210 
211     (void)strcpy(szFile, (char *)szName);
212     (void)strcat(szFile, dot_lck);
213 
214     if(unlink(szFile) != 0 && errno != ENOENT)
215     {
216         rc = FALSE;
217     }
218 
219     return rc;
220 } /* _SquishUnlinkBaseFiles */
221 
222 /* Close the data files for this message base */
_SquishCloseBaseFiles(HAREA ha)223 static void near _SquishCloseBaseFiles(HAREA ha)
224 {
225     (void)close(Sqd->sfd);
226     (void)close(Sqd->ifd);
227     Sqd->sfd = -1;
228     Sqd->ifd = -1;
229 }
230 
231 /* Ensure that the SQBASE header is valid */
_SquishValidateBaseHeader(SQBASE * psqb)232 static unsigned near _SquishValidateBaseHeader(SQBASE * psqb)
233 {
234     if (psqb->num_msg > psqb->high_msg ||
235             psqb->num_msg > psqb->uid+1 ||
236             psqb->high_msg > psqb->uid+1 ||
237             psqb->num_msg > 1000000L ||
238             psqb->num_msg != psqb->high_msg ||
239             psqb->len < SQBASE_SIZE ||
240             psqb->len >= 1024 ||
241             psqb->begin_frame > psqb->end_frame ||
242             psqb->last_frame > psqb->end_frame ||
243             psqb->free_frame > psqb->end_frame ||
244             psqb->last_free_frame > psqb->end_frame ||
245             psqb->end_frame==0)
246     {
247         msgapierr = MERR_BADF;
248         return FALSE;
249     }
250 
251     return TRUE;
252 }
253 
254 /* Copy information from the psqb disk header to our in-memory struct */
_SquishCopyBaseToData(HAREA ha,SQBASE * psqb)255 unsigned _SquishCopyBaseToData(HAREA ha, SQBASE * psqb)
256 {
257     Sqd->cbSqbase    = psqb->len;
258     Sqd->cbSqhdr     = psqb->sz_sqhdr;
259     Sqd->wSkipMsg    = (word)psqb->skip_msg;
260     Sqd->dwMaxMsg    = psqb->max_msg;
261     Sqd->wMaxDays    = psqb->keep_days;
262     Sqd->dwHighWater = psqb->high_water;
263     Sqd->uidNext     = psqb->uid;
264     Sqd->foFirst     = psqb->begin_frame;
265     Sqd->foLast      = psqb->last_frame;
266     Sqd->foFree      = psqb->free_frame;
267     Sqd->foLastFree  = psqb->last_free_frame;
268     Sqd->foEnd       = psqb->end_frame;
269     Sqd->sqbDelta    = *psqb;
270     ha->num_msg      = psqb->num_msg;
271     ha->high_msg     = psqb->num_msg;
272     ha->high_water   = psqb->high_water;
273     return TRUE;
274 }
275 
276 /* Copy data from the in-memory struct into the disk header */
_SquishCopyDataToBase(HAREA ha,SQBASE * psqb)277 unsigned _SquishCopyDataToBase(HAREA ha, SQBASE * psqb)
278 {
279     (void)memset(psqb, 0, sizeof(SQBASE));
280     psqb->len             = Sqd->cbSqbase;
281     psqb->sz_sqhdr        = Sqd->cbSqhdr;
282     psqb->skip_msg        = Sqd->wSkipMsg;
283     psqb->max_msg         = Sqd->dwMaxMsg;
284     psqb->keep_days       = Sqd->wMaxDays;
285     psqb->high_water      = Sqd->dwHighWater;
286     psqb->uid             = Sqd->uidNext;
287     psqb->begin_frame     = Sqd->foFirst;
288     psqb->last_frame      = Sqd->foLast;
289     psqb->free_frame      = Sqd->foFree;
290     psqb->last_free_frame = Sqd->foLastFree;
291     psqb->end_frame       = Sqd->foEnd;
292     psqb->num_msg         = ha->num_msg;
293     psqb->high_msg        = ha->high_msg;
294     psqb->high_water      = ha->high_water;
295     return TRUE;
296 }
297 
298 /* Set the starting values for this message base */
_SquishSetBaseDefaults(HAREA ha)299 static unsigned near _SquishSetBaseDefaults(HAREA ha)
300 {
301     /* Set up our current position in the linked list */
302     Sqd->foNext = Sqd->foFirst;
303     Sqd->foCur  = NULL_FRAME;
304     Sqd->foPrev = NULL_FRAME;
305     ha->cur_msg = 0;
306     ha->sz_xmsg = XMSG_SIZE;
307     return TRUE;
308 }
309 
310 /* Fill out the initial values in a Squish base header */
_SquishFillBaseHeader(SQBASE * psqb,byte * szName)311 static unsigned near _SquishFillBaseHeader(SQBASE * psqb, byte * szName)
312 {
313     psqb->len        = SQBASE_SIZE;
314     psqb->rsvd1      = 0;
315     psqb->num_msg    = 0L;
316     psqb->high_msg   = 0L;
317     psqb->skip_msg   = 0L;
318     psqb->high_water = 0L;
319     psqb->uid        = 1L;
320     (void)strcpy((char *)(psqb->base), (char *)szName);
321     psqb->begin_frame     = NULL_FRAME;
322     psqb->last_frame      = NULL_FRAME;
323     psqb->free_frame      = NULL_FRAME;
324     psqb->last_free_frame = NULL_FRAME;
325     psqb->end_frame       = SQBASE_SIZE;
326     psqb->max_msg         = 0L;
327     psqb->keep_days       = 0;
328     psqb->sz_sqhdr        = SQHDR_SIZE;
329     (void)memset(psqb->rsvd2, 0, sizeof psqb->rsvd2);
330     return TRUE;
331 }
332 
333 /* Create a new Squish message area */
_SquishCreateNewBase(HAREA ha,byte * szName)334 static unsigned near _SquishCreateNewBase(HAREA ha, byte * szName)
335 {
336     SQBASE sqb;           /* Header from Squish base */
337 
338     /* Try to open the files */
339     if(!_SquishOpenBaseFiles(ha, szName, O_CREAT | O_EXCL))
340     {
341         return FALSE; /* File exists or i/o error */
342     }
343 
344     if(!_SquishFillBaseHeader(&sqb, szName) ||
345        !_SquishWriteBaseHeader(ha, &sqb) ||
346        !_SquishCopyBaseToData(ha, &sqb) || !_SquishSetBaseDefaults(ha))
347     {
348         /* The open failed, so delete the partially-created Squishbase */
349         _SquishCloseBaseFiles(ha);
350         (void)_SquishUnlinkBaseFiles(szName);
351         return FALSE;
352     }
353 
354     return TRUE;
355 }
356 
357 /* Open an existing Squish base and fill out 'ha' appropriately */
_SquishOpenExistingBase(HAREA ha,byte * szName)358 static unsigned near _SquishOpenExistingBase(HAREA ha, byte * szName)
359 {
360     SQBASE sqb;           /* Header from Squish base */
361 
362     /* Try to open the files */
363     if(!_SquishOpenBaseFiles(ha, szName, 0))
364     {
365         return FALSE;
366     }
367 
368     if(!_SquishReadBaseHeader(ha,
369                               &sqb) || !_SquishValidateBaseHeader(&sqb) ||
370        !_SquishCopyBaseToData(ha, &sqb) || !_SquishSetBaseDefaults(ha))
371     {
372         _SquishCloseBaseFiles(ha);
373         return FALSE;
374     }
375 
376     return TRUE;
377 }
378 
379 /* Allocate a new area handle */
NewHarea(word wType)380 static HAREA NewHarea(word wType)
381 {
382     HAREA ha;
383 
384     /* Try to allocate memory for the area handle */
385     ha = (HAREA)palloc(sizeof(*ha));
386 
387     if(ha == NULL)
388     {
389         return NULL;
390     }
391 
392     (void)memset(ha, 0, sizeof *ha);
393     ha->id     = MSGAPI_ID;
394     ha->len    = sizeof(struct _msgapi);
395     ha->type   = wType & ~MSGTYPE_ECHO;
396     ha->isecho = (byte) !!(wType & MSGTYPE_ECHO);
397     return ha;
398 }
399 
400 /* Open a Squish base */
SquishOpenArea(byte * szName,word wMode,word wType)401 HAREA MSGAPI SquishOpenArea(byte * szName, word wMode, word wType)
402 {
403     HAREA ha;                       /* Area handle for this area */
404     unsigned fOpened;               /* Has this area been opened? */
405 
406     /* Make sure that we have a valid base name */
407     if(!szName)
408     {
409         msgapierr = MERR_BADA;
410         return NULL;
411     }
412 
413     /* Allocate memory for the Squish handle */
414     ha = NewHarea(wType);
415 
416     if(ha == NULL)
417     {
418         return NULL;
419     }
420 
421     /* Allocate memory for the Squish-specific part of the handle */
422     ha->apidata = (void *)palloc(sizeof(struct _sqdata));
423 
424     if(ha->apidata == NULL)
425     {
426         pfree(ha);
427         return NULL;
428     }
429 
430     memset(ha->apidata, 0, sizeof(struct _sqdata));
431     /* Allocate memory to hold the function pointers */
432     ha->api = (struct _apifuncs *)palloc(sizeof(struct _apifuncs));
433 
434     if(ha->api == NULL)
435     {
436         pfree(ha->apidata);
437         pfree(ha);
438         return NULL;
439     }
440 
441     /* Fill out the function pointers for this area */
442     *ha->api = sq_funcs;
443     /* Open the index interface for this area */
444     Sqd->hix = _SquishOpenIndex(ha);
445 
446     if(Sqd->hix == NULL)
447     {
448         return NULL;
449     }
450 
451     fOpened = FALSE;
452     /* If we want to open an existing area, try it here */
453     msgapierr = 0;
454 
455     if(wMode == MSGAREA_NORMAL || wMode == MSGAREA_CRIFNEC)
456     {
457         fOpened = _SquishOpenExistingBase(ha, szName);
458     }
459     else
460     {
461         msgapierr = MERR_NOENT;
462     }
463 
464     /* If we want to create a new area, try that now */
465     if(msgapierr == MERR_NOENT &&
466        (wMode == MSGAREA_CREATE || (wMode == MSGAREA_CRIFNEC && !fOpened)))
467     {
468         fOpened = _SquishCreateNewBase(ha, szName);
469     }
470 
471     /* If the open succeeded */
472     if(fOpened)
473     {
474         /* Add us to the linked list of open areas */
475         Sqd->haNext = haOpen;
476         haOpen      = ha;
477     }
478     else
479     {
480         pfree(ha->apidata);
481         pfree(ha->api);
482         pfree(ha);
483         return NULL;
484     }
485 
486 
487 #ifdef ALTLOCKING
488     ha->lck_handle = 0;
489 #endif
490     /* Return the handle to this area */
491     return ha;
492 } /* SquishOpenArea */
493 
494 /* Close any messages in this area which may be open */
_SquishCloseAreaMsgs(HAREA ha)495 static unsigned near _SquishCloseAreaMsgs(HAREA ha)
496 {
497     HMSG hm, hmNext;
498 
499     /* Close any open messages, if necessary */
500     for(hm = Sqd->hmsgOpen; hm; hm = hmNext)
501     {
502         hmNext = hm->hmsgNext;
503 
504         if(apiSquishCloseMsg(hm) == -1)
505         {
506             msgapierr = MERR_EOPEN;
507             return FALSE;
508         }
509     }
510     return TRUE;
511 }
512 
_SquishRemoveAreaList(HAREA haThis)513 static unsigned near _SquishRemoveAreaList(HAREA haThis)
514 {
515     HAREA ha, haNext;
516 
517     if(!haOpen)
518     {
519         msgapierr = MERR_BADA;
520         return FALSE;
521     }
522 
523     /* If we were at the head of the list, adjust the main pointer only */
524     if(haOpen == haThis)
525     {
526         ha     = haThis;
527         haOpen = Sqd->haNext;
528         return TRUE;
529     }
530 
531     /* Try to find us in the middle of the list */
532     for(ha = haOpen; ha; ha = haNext)
533     {
534         haNext = Sqd->haNext;
535 
536         if(haNext == haThis)
537         {
538             Sqd->haNext = ((SQDATA *)(haThis->apidata))->haNext;
539             return TRUE;
540         }
541     }
542     msgapierr = MERR_BADA;
543     return FALSE;
544 } /* _SquishRemoveAreaList */
545 
546 /* Close an open message area */
apiSquishCloseArea(HAREA ha)547 sword _XPENTRY apiSquishCloseArea(HAREA ha)
548 {
549     if(MsgInvalidHarea(ha))
550     {
551         return -1;
552     }
553 
554     /* Close any open messages */
555     if(!_SquishCloseAreaMsgs(ha))
556     {
557         return -1;
558     }
559 
560     /* Unlock the area, if necessary */
561     if(Sqd->fHaveExclusive)
562     {
563         Sqd->fHaveExclusive = 1;
564         (void)_SquishExclusiveEnd(ha);
565     }
566 
567     /* Unlock the area as well */
568     if(Sqd->fLockFunc)
569     {
570         if(Sqd->fLocked)
571         {
572             Sqd->fLocked = 1;
573         }
574 
575         Sqd->fLockFunc = 1;
576         apiSquishUnlock(ha);
577     }
578 
579     (void)_SquishCloseIndex(Sqd->hix);
580     /* Close off the Squish data files */
581     _SquishCloseBaseFiles(ha);
582     /* Remove ourselves from the list of open areas */
583     (void)_SquishRemoveAreaList(ha);
584     /* Blank out the ID, then free all of the memory associated with this     *
585      * area handle.                                                           */
586     ha->id = 0;
587 
588 #ifdef ALTLOCKING
589 
590     if(ha->lck_path)
591     {
592         pfree(ha->lck_path);
593     }
594 
595 #endif
596 
597     pfree(ha->api);
598     pfree(ha->apidata);
599     pfree(ha);
600     return 0;
601 } /* apiSquishCloseArea */
602 
603 /* This function ensures that the specified Squish base name exists */
SquishValidate(byte * szName)604 sword MSGAPI SquishValidate(byte * szName)
605 {
606     char szFile[PATHLEN];
607 
608     (void)strcpy(szFile, (char *)szName);
609     (void)strcat(szFile, dot_sqd);
610 
611     if(!fexist(szFile))
612     {
613         return FALSE;
614     }
615 
616     (void)strcpy(szFile, (char *)szName);
617     (void)strcat(szFile, dot_sqi);
618 
619     if(!fexist(szFile))
620     {
621         return FALSE;
622     }
623 
624     return TRUE;
625 }
626 
_SquishInit()627 void _SquishInit()
628 {}
629 
_SquishDeInit()630 void _SquishDeInit()
631 {
632     _SquishCloseOpenAreas();
633 }
634