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