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