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