1 /*
2 * SMAPI; Modified Squish MSGAPI
3 *
4 * Squish MSGAPI0 is copyright 1991 by Scott J. Dudley. All rights reserved.
5 * Modifications released to the public domain.
6 *
7 * Use of this file is subject to the restrictions contain in the Squish
8 * MSGAPI0 licence agreement. Please refer to licence.txt for complete
9 * details of the licencing restrictions. If you do not find the text
10 * of this agreement in licence.txt, or if you do not have this file,
11 * you should contact Scott Dudley at FidoNet node 1:249/106 or Internet
12 * e-mail Scott.Dudley@f106.n249.z1.fidonet.org.
13 *
14 * In no event should you proceed to use any of the source files in this
15 * archive without having accepted the terms of the MSGAPI0 licensing
16 * agreement, or such other agreement as you are able to reach with the
17 * author.
18 */
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28
29 #include <huskylib/compiler.h>
30
31 #ifdef HAS_IO_H
32 #include <io.h>
33 #endif
34
35 #ifdef HAS_SHARE_H
36 #include <share.h>
37 #endif
38
39 #ifdef HAS_DOS_H
40 #include <dos.h>
41 #endif
42
43 #ifdef HAS_MALLOC_H
44 #include <malloc.h>
45 #endif
46
47 #ifdef __BEOS__
48 #include <be/kernel/fs_attr.h>
49 #include <be/support/TypeConstants.h>
50 #endif
51
52 #define MSGAPI_HANDLERS
53
54 #include <huskylib/huskylib.h>
55
56 /* Swith for build DLL */
57 #define DLLEXPORT
58 #include <huskylib/huskyext.h>
59
60 #include "msgapi.h"
61 #include "old_msg.h"
62 #include "api_sdm.h"
63 #include "api_sdmp.h"
64 #include "apidebug.h"
65
66 #define SDM_BLOCK 256 /* Should be exp2(x) */
67 #define Mhd ((struct _sdmdata *)(mh->apidata))
68 #define MsghMhd ((struct _sdmdata *)(((struct _msgh *)msgh)->sq->apidata))
69
70 static byte *hwm_from = (byte *) "-=|smapi internal|=-";
71
SdmOpenArea(byte * name,word mode,word type)72 MSGA *MSGAPI SdmOpenArea(byte * name, word mode, word type)
73 {
74 MSGA *mh;
75
76 if( !name || !*name )
77 {
78 msgapierr = MERR_BADNAME;
79 return NULL;
80 }
81
82 mh = palloc(sizeof(MSGA));
83 if (mh == NULL)
84 {
85 msgapierr = MERR_NOMEM;
86 goto ErrOpen;
87 }
88
89 memset(mh, '\0', sizeof(MSGA));
90
91 mh->id = MSGAPI_ID;
92
93 if (type & MSGTYPE_ECHO)
94 {
95 mh->isecho = TRUE;
96 }
97
98 mh->api = (struct _apifuncs *)palloc(sizeof(struct _apifuncs));
99 if (mh->api == NULL)
100 {
101 msgapierr = MERR_NOMEM;
102 goto ErrOpen;
103 }
104
105 memset(mh->api, '\0', sizeof(struct _apifuncs));
106
107 mh->apidata = (void *)palloc(sizeof(struct _sdmdata));
108 if (mh->apidata == NULL)
109 {
110 msgapierr = MERR_NOMEM;
111 goto ErrOpen;
112 }
113
114 memset((byte *) mh->apidata, '\0', sizeof(struct _sdmdata));
115
116 strcpy((char *) Mhd->base, (char *) name);
117 Add_Trailing((char *) Mhd->base, PATH_DELIM);
118 Mhd->hwm = (dword) - 1L;
119
120 mh->len = sizeof(MSGA);
121 mh->num_msg = 0;
122 mh->high_msg = 0;
123 mh->high_water = (dword) - 1L;
124
125 if (!direxist((char *) name) && (mode == MSGAREA_NORMAL
126 || _createDirectoryTree((char *) name) != 0))
127 {
128 msgapierr = MERR_NOENT;
129 goto ErrOpen;
130 }
131
132 if (!_SdmRescanArea(mh))
133 {
134 goto ErrOpen;
135 }
136
137 mh->type &= ~MSGTYPE_ECHO;
138
139 *mh->api = sdm_funcs;
140 mh->sz_xmsg = sizeof(XMSG);
141
142 msgapierr = 0;
143 return mh;
144
145 ErrOpen:
146
147 if (mh)
148 {
149 if (mh->api)
150 {
151 if (mh->apidata)
152 {
153 pfree(mh->apidata);
154 }
155
156 pfree(mh->api);
157 }
158
159 pfree(mh);
160 }
161
162 return NULL;
163 }
164
SdmDeleteBase(char * name)165 int SdmDeleteBase(char *name)
166 {
167 FFIND *ff;
168 char *temp;
169
170 if(!name || !*name){ msgapierr=MERR_BADNAME; return FALSE; }
171
172 temp = malloc(strlen(name)+6);
173 if (temp == NULL)
174 return FALSE;
175 sprintf(temp, "%s*.msg", name);
176
177 ff = FFindOpen(temp, 0);
178
179 free(temp);
180
181 if (ff != 0)
182 {
183 do
184 {
185 temp = malloc(strlen(name) + strlen(ff->ff_name) + 1);
186 if (temp == NULL)
187 {
188 FFindClose(ff);
189 return FALSE;
190 }
191 sprintf(temp, "%s%s", name, ff->ff_name);
192 unlink(temp);
193 free(temp);
194 }
195 while (FFindNext(ff) == 0);
196
197 FFindClose(ff);
198 }
199 sprintf(temp, "%slastread", name);
200 unlink(temp);
201 rmdir(name);
202
203 return TRUE; /* rmdir error is ok */
204 }
205
SdmCloseArea(MSGA * mh)206 static sword _XPENTRY SdmCloseArea(MSGA * mh)
207 {
208 XMSG msg;
209 MSGH *msgh;
210 static byte *msgbody = (byte *)
211 "NOECHO\r\rPlease ignore. This message is only used by the SquishMail "
212 "system to store\rthe high water mark for each conference area.\r\r\r\r"
213 "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r(Elvis was here!)\r\r\r";
214
215 if (InvalidMh(mh))
216 {
217 return -1;
218 }
219
220 if (Mhd->hwm_chgd)
221 {
222 msgh = SdmOpenMsg(mh, MOPEN_CREATE, 1L);
223 if (msgh != NULL)
224 {
225 Init_Xmsg(&msg);
226
227 Get_Dos_Date((union stamp_combo *)&msg.date_arrived);
228 Get_Dos_Date((union stamp_combo *)&msg.date_written);
229
230 /*
231 * Use high-bit chars in the to/from field, so that (l)users
232 * can't log on as this userid and delete the HWM.
233 */
234
235 strcpy((char *) msg.from, (char *) hwm_from);
236 strcpy((char *) msg.to, (char *) msg.from);
237 strcpy((char *) msg.subj, "High wadda' mark");
238
239 /* To prevent "INTL 0:0/0 0:0/0" kludges */
240 msg.orig.zone = msg.dest.zone = mi.def_zone;
241
242 msg.replyto = mh->high_water;
243 msg.attr = MSGPRIVATE | MSGREAD | MSGLOCAL | MSGSENT;
244
245 SdmWriteMsg(msgh, FALSE, &msg, msgbody, strlen((char *) msgbody) + 1,
246 strlen((char *) msgbody) + 1, 0L, NULL);
247
248 SdmCloseMsg(msgh);
249 }
250 }
251
252 if (Mhd->msgs_open)
253 {
254 msgapierr = MERR_EOPEN;
255 return -1;
256 }
257
258 if (Mhd->msgnum)
259 {
260 pfree(Mhd->msgnum);
261 }
262
263 pfree(mh->apidata);
264 pfree(mh->api);
265
266 mh->id = 0L;
267 pfree(mh);
268
269 msgapierr = MERR_NONE;
270 return 0;
271 }
272
SdmOpenMsg(MSGA * mh,word mode,dword msgnum)273 static MSGH *_XPENTRY SdmOpenMsg(MSGA * mh, word mode, dword msgnum)
274 {
275 byte msgname[PATHLEN];
276 int handle, filemode;
277 int owrite = FALSE;
278 dword msguid=0;
279
280 MSGH *msgh;
281
282 if (InvalidMh(mh))
283 {
284 return NULL;
285 }
286
287 if (msgnum == MSGNUM_CUR)
288 {
289 msgnum = mh->cur_msg;
290 }
291 else if (msgnum == MSGNUM_PREV)
292 {
293 msgnum = mh->cur_msg - 1;
294 if (msgnum == 0)
295 {
296 msgapierr = MERR_NOENT;
297 return NULL;
298 }
299 }
300 else if (msgnum == MSGNUM_NEXT)
301 {
302 msgnum = mh->num_msg + 1;
303 if (msgnum > mh->num_msg)
304 {
305 msgapierr = MERR_NOENT;
306 return NULL;
307 }
308 }
309 else if (mode != MOPEN_CREATE)
310 {
311 /*
312 * If we're not creating, make sure that the specified msg# can
313 * be found.
314 */
315 if (msgnum <= 0 || msgnum > mh->num_msg)
316 {
317 msgapierr = MERR_NOENT;
318 return NULL;
319 }
320 }
321 if (msgnum <= mh->num_msg && msgnum > 0)
322 msguid = SdmMsgnToUid(mh, msgnum);
323
324 if (mode == MOPEN_CREATE)
325 {
326 /* If we're creating a new message... */
327
328 if (msgnum == 0L)
329 {
330 /*
331 * If the base isn't locked, make sure that we avoid
332 * conflicts...
333 */
334
335 if (!mh->locked)
336 {
337 /* Check to see if the msg we're writing already exists */
338
339 sprintf((char *) msgname, (char *) sd_msg, Mhd->base, (sdm_msgnum_type)mh->high_msg + 1);
340
341 if (fexist((char *) msgname))
342 {
343 /* If so, rescan the base, to find out which msg# it is. */
344
345 if (Mhd->msgnum && Mhd->msgnum_len)
346 {
347 pfree(Mhd->msgnum);
348 }
349
350 if (!_SdmRescanArea(mh))
351 {
352 return NULL;
353 }
354 }
355 }
356
357 msgnum = ++mh->num_msg;
358 msguid = ++mh->high_msg;
359
360 /*
361 * Make sure that we don't overwrite the high-water mark,
362 * unless we call with msgnum != 0L (a specific number).
363 */
364
365 if (mh->isecho && msgnum == 1)
366 {
367 msgnum = mh->high_msg = 2;
368 }
369 }
370 else
371 {
372 /* otherwise, we're overwriting an existing message */
373 owrite = TRUE;
374 }
375
376 filemode = O_CREAT | O_TRUNC | O_RDWR;
377 }
378 else if (mode == MOPEN_READ)
379 {
380 filemode = O_RDONLY;
381 }
382 else if (mode == MOPEN_WRITE)
383 {
384 filemode = O_WRONLY;
385 }
386 else
387 {
388 filemode = O_RDWR;
389 }
390
391 sprintf((char *) msgname, (char *) sd_msg, Mhd->base, (int)msguid);
392 handle = sopen((char *) msgname, filemode | O_BINARY, SH_DENYNONE,
393 FILEMODE(mh->isecho));
394 if (handle == -1)
395 {
396 if (filemode & O_CREAT)
397 {
398 msgapierr = MERR_BADF;
399 }
400 else
401 {
402 msgapierr = MERR_NOENT;
403 }
404 return NULL;
405 }
406
407 mh->cur_msg = msgnum;
408
409 msgh = palloc(sizeof(MSGH));
410 if (msgh == NULL)
411 {
412 close(handle);
413 msgapierr = MERR_NOMEM;
414 return NULL;
415 }
416
417 memset(msgh, '\0', sizeof(MSGH));
418 msgh->fd = handle;
419
420 if (mode == MOPEN_CREATE)
421 {
422 if (mh->num_msg == (dword)(1 << (sizeof(mh->num_msg) * 8 - 1)))
423 { /* Messagebase implementaion (size) limit (messages counter is full)*/
424 pfree(msgh);
425 close(handle);
426 msgapierr = MERR_LIMIT;
427 return NULL;
428 }
429 if ((mh->num_msg + 1) >= Mhd->msgnum_len)
430 {
431 word msgnum_len_new = Mhd->msgnum_len + (word) SDM_BLOCK;
432 Mhd->msgnum = realloc(Mhd->msgnum, msgnum_len_new * sizeof(unsigned));
433
434 if (!Mhd->msgnum)
435 {
436 pfree(msgh);
437 close(handle);
438 msgapierr = MERR_NOMEM;
439 return NULL;
440 }
441 Mhd->msgnum_len = msgnum_len_new;
442 }
443
444 /*
445 * If we're writing a new msg, this is easy -- just add to
446 * end of list.
447 */
448
449 if (!owrite)
450 {
451 Mhd->msgnum[(size_t) (mh->num_msg)] = (word) msguid;
452 mh->num_msg++;
453 }
454 else
455 {
456 /*
457 * If this message is already in the list then do nothing --
458 * simply overwrite it, keeping the same message number, so
459 * no action is required. Otherwise, we have to shift
460 * everything up by one since we're adding this new message
461 * in between two others.
462 */
463
464 if ((dword) Mhd->msgnum[msgnum-1] != msguid)
465 {
466 memmove(Mhd->msgnum + msgnum, Mhd->msgnum + msgnum - 1,
467 ((size_t) mh->num_msg - msgnum) * sizeof(Mhd->msgnum[0]));
468 Mhd->msgnum[msgnum-1] = (word) msguid;
469 mh->num_msg++;
470 }
471 }
472 }
473
474 msgh->cur_pos = 0L;
475
476 if (mode == MOPEN_CREATE)
477 {
478 msgh->msg_len = 0;
479 }
480 else
481 {
482 msgh->msg_len = (dword) - 1;
483 }
484
485 msgh->sq = mh;
486 msgh->id = MSGH_ID;
487 msgh->ctrl = NULL;
488 msgh->clen = -1;
489 msgh->zplen = 0;
490
491 msgapierr = MERR_NONE;
492
493 /* Keep track of how many messages were opened for this area */
494
495 MsghMhd->msgs_open++;
496
497 return msgh;
498 }
499
SdmCloseMsg(MSGH * msgh)500 static sword _XPENTRY SdmCloseMsg(MSGH * msgh)
501 {
502 if (InvalidMsgh(msgh))
503 {
504 return -1;
505 }
506
507 MsghMhd->msgs_open--;
508
509 if (msgh->ctrl)
510 {
511 pfree(msgh->ctrl);
512 msgh->ctrl = NULL;
513 }
514
515 close(msgh->fd);
516
517 msgh->id = 0L;
518 pfree(msgh);
519
520 msgapierr = MERR_NONE;
521 return 0;
522 }
523
SdmReadMsg(MSGH * msgh,XMSG * msg,dword offset,dword bytes,byte * text,dword clen,byte * ctxt)524 static dword _XPENTRY SdmReadMsg(MSGH * msgh, XMSG * msg, dword offset, dword bytes, byte * text, dword clen, byte * ctxt)
525 {
526 unsigned len;
527 dword realbytes, got;
528 struct _omsg fmsg;
529 word need_ctrl;
530 byte *fake_msgbuf = NULL, *newtext;
531
532 if (InvalidMsgh(msgh))
533 {
534 return (dword)-1L;
535 }
536
537 if (!(clen && ctxt))
538 {
539 clen = 0L;
540 ctxt = NULL;
541 }
542
543 if (!(text && bytes))
544 {
545 bytes = 0L;
546 text = NULL;
547 }
548
549 if (msg)
550 {
551 lseek(msgh->fd, 0L, SEEK_SET);
552
553 if (!read_omsg(msgh->fd, &fmsg))
554 {
555 msgapierr = MERR_BADF;
556 return (dword)-1L;
557 }
558
559 fmsg.to[sizeof(fmsg.to) - 1] = '\0';
560 fmsg.from[sizeof(fmsg.from) - 1] = '\0';
561 fmsg.subj[sizeof(fmsg.subj) - 1] = '\0';
562 fmsg.date[sizeof(fmsg.date) - 1] = '\0';
563
564 Convert_Fmsg_To_Xmsg(&fmsg, msg, mi.def_zone);
565
566 StripNasties(msg->from);
567 StripNasties(msg->to);
568 StripNasties(msg->subj);
569 }
570
571
572 /*
573 * If we weren't instructed to read some message text (ie. only the
574 * header, read a block anyway. We need to scan for kludge lines,
575 * to pick out the appropriate zone/point info.)
576 */
577
578 if (msgh->ctrl == NULL && ((msg || ctxt || text) ||
579 (msg || ctxt || text) == 0))
580 {
581 need_ctrl = TRUE;
582 }
583 else
584 {
585 need_ctrl = FALSE;
586 }
587
588 realbytes = bytes;
589 unused(realbytes);
590
591 /*
592 * If we need to read the control information, and the user hasn't
593 * requested a read operation, we'll need to do one anyway.
594 */
595
596 if (need_ctrl && text == NULL)
597 {
598 struct stat st;
599 fstat(msgh->fd, &st);
600 text = fake_msgbuf = palloc(st.st_size - OMSG_SIZE + 1);
601 if (text == NULL)
602 {
603 msgapierr = MERR_NOMEM;
604 return (dword)-1L;
605 }
606
607 text[st.st_size - OMSG_SIZE] = '\0';
608 bytes = st.st_size - OMSG_SIZE;
609 }
610
611 /* If we need to read in some text... */
612
613 if (text)
614 {
615 /* Seek is superfluous if we just read msg header */
616
617 if (!msg || msgh->msgtxt_start != 0)
618 {
619 lseek(msgh->fd, (dword) OMSG_SIZE +
620 msgh->msgtxt_start + offset, SEEK_SET);
621
622 msgh->cur_pos = offset;
623 }
624
625 got = (dword) farread(msgh->fd, text, (unsigned int)bytes);
626 text[(unsigned int)got] = '\0';
627
628 /*
629 * Update counter only if we got some text, and only if we're
630 * doing a read requested by the user (as opposed to reading
631 * ahead to find kludge lines).
632 */
633
634 if (got > 0 && !fake_msgbuf)
635 {
636 msgh->cur_pos += got;
637 }
638 }
639 else
640 {
641 got = 0;
642 }
643
644 /* Convert the kludges into 'ctxt' format */
645
646 if (need_ctrl && got && offset == 0L)
647 {
648 len = got;
649
650 msgh->ctrl = CopyToControlBuf(text, &newtext, &len);
651 if (msgh->ctrl != NULL)
652 {
653 msgh->clen = (dword) strlen((char *) msgh->ctrl) + 1;
654 msgh->msgtxt_start = newtext - text;
655
656 /* Shift back the text buffer to counter absence of ^a strings */
657
658 memmove(text, newtext, (size_t) (bytes - (newtext - text)));
659
660 got -= (dword) (msgh->clen - 1);
661 }
662 }
663
664 /* Scan the ctxt ourselves to find zone/point info */
665
666 if (msg && msgh->ctrl)
667 {
668 ConvertControlInfo(msgh->ctrl, &msg->orig, &msg->dest);
669 }
670
671 /* And if the app requested ctrlinfo, put it in its place. */
672
673 if (ctxt && msgh->ctrl)
674 {
675 size_t slen;
676
677 slen = strlen((char *) msgh->ctrl) + 1;
678 memmove(ctxt, msgh->ctrl, min(slen, (size_t) clen));
679 ctxt[min(slen, (size_t) clen)] = '\0';
680 }
681
682 if (fake_msgbuf)
683 {
684 pfree(fake_msgbuf);
685 got = 0;
686 }
687
688 msgapierr = MERR_NONE;
689 return got;
690 }
691
SdmWriteMsg(MSGH * msgh,word append,XMSG * msg,byte * text,dword textlen,dword totlen,dword clen,byte * ctxt)692 static sword _XPENTRY SdmWriteMsg(MSGH * msgh, word append, XMSG * msg, byte * text, dword textlen, dword totlen, dword clen, byte * ctxt)
693 {
694 struct _omsg fmsg;
695 byte *s;
696
697 unused(totlen);
698
699 if (clen == 0L || ctxt == NULL)
700 {
701 ctxt = NULL;
702 clen = 0L;
703 }
704
705 if (InvalidMsgh(msgh))
706 {
707 return -1;
708 }
709
710 lseek(msgh->fd, 0L, SEEK_SET);
711
712 if (msg)
713 {
714 Convert_Xmsg_To_Fmsg(msg, &fmsg);
715
716 if (!write_omsg(msgh->fd, &fmsg))
717 {
718 msgapierr = MERR_NODS;
719 return -1;
720 }
721
722 if (!append && msgh->clen <= 0 && msgh->zplen == 0 && !msgh->sq->isecho)
723 {
724 statfd = msgh->fd;
725 msgh->zplen = (word) WriteZPInfo(msg, WriteToFd, ctxt);
726 }
727
728 /* Use Attributes und BeOS */
729 #ifdef __BEOS__
730 {
731 struct tm tmdate;
732 time_t ttime;
733
734 fs_write_attr(msgh->fd, "BEOS:TYPE", B_MIME_TYPE, 0l, "message/fmsg", 13);
735 fs_write_attr(msgh->fd, "XMSG:FROM", B_STRING_TYPE, 0l, msg->from, strlen((char*)msg->from));
736 fs_write_attr(msgh->fd, "XMSG:TO" , B_STRING_TYPE, 0l, msg->to, strlen((char*)msg->to));
737 fs_write_attr(msgh->fd, "XMSG:SUBJ", B_STRING_TYPE, 0l, msg->subj, strlen((char*)msg->subj));
738 ttime = mktime(DosDate_to_TmDate((union stamp_combo *)&msg->date_written, &tmdate));
739 fs_write_attr(msgh->fd, "XMSG:DATE", B_TIME_TYPE, 0l, &ttime, 4l);
740 ttime = mktime(DosDate_to_TmDate((union stamp_combo *)&msg->date_arrived, &tmdate));
741 fs_write_attr(msgh->fd, "XMSG:DTAR", B_TIME_TYPE, 0l, &ttime, 4l);
742 /* ... and so on ... not fully implemented ! (Yet) */
743 }
744 #endif
745 }
746 else if (!append || ctxt)
747 {
748 /* Skip over old message header */
749 lseek(msgh->fd, (dword) OMSG_SIZE +
750 (dword) msgh->zplen, SEEK_SET);
751 }
752
753 /* Now write the control info / kludges */
754
755 if (clen && ctxt)
756 {
757 if (!msg)
758 {
759 lseek(msgh->fd, (dword) OMSG_SIZE +
760 (dword) msgh->zplen, SEEK_SET);
761 }
762
763 s = CvtCtrlToKludge(ctxt);
764
765 if (s)
766 {
767 unsigned sl_s = (unsigned) strlen((char *)s);
768 int ret;
769
770 ret = farwrite(msgh->fd, s, sl_s);
771 pfree(s);
772 if (ret != (int) sl_s)
773 {
774 msgapierr = MERR_NODS;
775 return -1;
776 }
777 }
778 }
779
780 if (append)
781 {
782 lseek(msgh->fd, 0L, SEEK_END);
783 }
784
785 if (text)
786 {
787 if (farwrite(msgh->fd, text, (unsigned)textlen) != (signed) textlen)
788 {
789 msgapierr = MERR_NODS;
790 return -1;
791 }
792 if (text[textlen])
793 if (farwrite(msgh->fd, "", 1) != 1)
794 {
795 msgapierr = MERR_NODS;
796 return -1;
797 }
798 }
799
800 msgapierr = MERR_NONE;
801 return 0;
802 }
803
SdmKillMsg(MSGA * mh,dword msgnum)804 static sword _XPENTRY SdmKillMsg(MSGA * mh, dword msgnum)
805 {
806 dword hwm;
807 byte temp[PATHLEN];
808 UMSGID msguid;
809
810 if (InvalidMh(mh))
811 {
812 return -1;
813 }
814
815 if (msgnum > mh->num_msg || msgnum <= 0)
816 {
817 msgapierr = MERR_NOENT;
818 return -1;
819 }
820
821 msguid = SdmMsgnToUid(mh, msgnum);
822
823 /* Remove the message number from our private index */
824
825 memmove(Mhd->msgnum + msgnum - 1, Mhd->msgnum + msgnum,
826 (int)(mh->num_msg - msgnum) * sizeof(Mhd->msgnum[0]));
827
828 /* If we couldn't find it, return an error message */
829
830 sprintf((char *) temp, (char *) sd_msg, Mhd->base, (unsigned int)msguid);
831
832 if (unlink((char *) temp) == -1)
833 {
834 msgapierr = MERR_NOENT;
835 return -1;
836 }
837
838 mh->num_msg--;
839
840 /* Adjust the high message number */
841
842 if (msguid == mh->high_msg)
843 {
844 if (mh->num_msg)
845 {
846 mh->high_msg = SdmMsgnToUid(mh, mh->num_msg);
847 }
848 else
849 {
850 mh->high_msg = 0;
851 }
852 }
853
854 /* Now adjust the high-water mark, if necessary */
855
856 hwm = SdmGetHighWater(mh);
857
858 if (hwm != (dword) -1 && hwm > 0 && hwm >= msgnum)
859 {
860 SdmSetHighWater(mh, msgnum - 1);
861 }
862
863 if (mh->cur_msg >= msgnum)
864 mh->cur_msg--;
865
866 msgapierr = MERR_NONE;
867 return 0;
868 }
869
SdmLock(MSGA * mh)870 static sword _XPENTRY SdmLock(MSGA * mh)
871 {
872 if (InvalidMh(mh))
873 {
874 return -1;
875 }
876
877 msgapierr = MERR_NONE;
878 return 0;
879 }
880
SdmUnlock(MSGA * mh)881 static sword _XPENTRY SdmUnlock(MSGA * mh)
882 {
883 if (InvalidMh(mh))
884 {
885 return -1;
886 }
887
888 msgapierr = MERR_NONE;
889 return 0;
890 }
891
SdmValidate(byte * name)892 sword MSGAPI SdmValidate(byte * name)
893 {
894 msgapierr = MERR_NONE;
895 return ((sword) (direxist((char *) name) != FALSE));
896 }
897
SdmSetCurPos(MSGH * msgh,dword pos)898 static sword _XPENTRY SdmSetCurPos(MSGH * msgh, dword pos)
899 {
900 if (InvalidMsgh(msgh))
901 {
902 return 0;
903 }
904
905 lseek(msgh->fd, msgh->cur_pos = pos, SEEK_SET);
906 msgapierr = MERR_NONE;
907 return 0;
908 }
909
SdmGetCurPos(MSGH * msgh)910 static dword _XPENTRY SdmGetCurPos(MSGH * msgh)
911 {
912 if (InvalidMsgh(msgh))
913 {
914 return (dword)-1L;
915 }
916
917 msgapierr = MERR_NONE;
918 return msgh->cur_pos;
919 }
920
SdmMsgnToUid(MSGA * mh,dword msgnum)921 static UMSGID _XPENTRY SdmMsgnToUid(MSGA * mh, dword msgnum)
922 {
923 if (InvalidMh(mh))
924 {
925 return (UMSGID) - 1;
926 }
927
928 msgapierr = MERR_NONE;
929 if (msgnum > mh->num_msg) return (UMSGID)-1;
930 if (msgnum <= 0) return 0;
931 return (UMSGID) Mhd->msgnum[msgnum - 1];
932 }
933
SdmUidToMsgn(MSGA * mh,UMSGID umsgid,word type)934 static dword _XPENTRY SdmUidToMsgn(MSGA * mh, UMSGID umsgid, word type)
935 {
936 dword left, right, nnew;
937 UMSGID umsg;
938
939 if (InvalidMh(mh))
940 return (dword)-1L;
941 if (umsgid <= 0)
942 return 0;
943 left = 1;
944 right = mh->num_msg;
945 while (left <= right)
946 {
947 nnew = (right + left) / 2;
948 umsg = SdmMsgnToUid(mh, nnew);
949 if (umsg == (UMSGID)-1)
950 return 0;
951 if (umsg < umsgid)
952 left = nnew + 1;
953 else if (umsg > umsgid){
954 if(nnew>0) right = nnew - 1;
955 else right=0;
956 }else
957 return nnew;
958 }
959 if (type == UID_EXACT) return 0;
960 if (type == UID_PREV)
961 return right;
962 return (left > mh->num_msg) ? mh->num_msg : left;
963 }
964
SdmGetHighWater(MSGA * mh)965 static dword _XPENTRY SdmGetHighWater(MSGA * mh)
966 {
967 MSGH *msgh;
968 XMSG msg;
969
970 if (InvalidMh(mh))
971 {
972 return (dword)-1L;
973 }
974
975 /* If we've already fetched the highwater mark... */
976
977 if (mh->high_water != (dword) - 1L)
978 {
979 return SdmUidToMsgn(mh, mh->high_water, UID_PREV);
980 }
981
982 msgh = SdmOpenMsg(mh, MOPEN_READ, 1L);
983 if (msgh == NULL)
984 {
985 return 0L;
986 }
987
988 if (SdmReadMsg(msgh, &msg, 0L, 0L, NULL, 0L, NULL) == (dword) - 1 ||
989 (strcmp((char *) msg.from, (char *) hwm_from)!=0) )
990 {
991 mh->high_water = 0L;
992 }
993 else
994 {
995 mh->high_water = (dword) msg.replyto;
996 }
997
998 SdmCloseMsg(msgh);
999
1000 return SdmUidToMsgn(mh, mh->high_water, UID_PREV);
1001 }
1002
SdmSetHighWater(MSGA * mh,dword hwm)1003 static sword _XPENTRY SdmSetHighWater(MSGA * mh, dword hwm)
1004 {
1005 if (InvalidMh(mh))
1006 {
1007 return -1;
1008 }
1009
1010 /*
1011 * Only write it to memory for now. We'll do a complete update of
1012 * the real HWM in 1.MSGA only when doing a MsgCloseArea(), to save
1013 * time.
1014 */
1015
1016 if (hwm != mh->high_water)
1017 {
1018 Mhd->hwm_chgd = TRUE;
1019 }
1020
1021 mh->high_water = hwm;
1022 return 0;
1023 }
1024
SdmGetTextLen(MSGH * msgh)1025 static dword _XPENTRY SdmGetTextLen(MSGH * msgh)
1026 {
1027 dword pos, end;
1028
1029 if(InvalidMsgh(msgh))
1030 {
1031 return (dword)-1L;
1032 }
1033
1034 /* Figure out the physical length of the message */
1035
1036 if (msgh->msg_len == -1)
1037 {
1038 pos = (dword) tell(msgh->fd);
1039 end = lseek(msgh->fd, 0L, SEEK_END);
1040
1041 if (end < OMSG_SIZE)
1042 {
1043 msgh->msg_len = 0L;
1044 }
1045 else
1046 {
1047 msgh->msg_len = end - (dword) OMSG_SIZE;
1048 }
1049
1050 lseek(msgh->fd, pos, SEEK_SET);
1051 }
1052
1053 /* If we've already figured out the length of the control info */
1054
1055 if ((msgh->clen == -1) && (_Grab_Clen(msgh) == -1))
1056 {
1057 return 0;
1058 }
1059 else
1060 {
1061 return (dword) (msgh->msg_len - msgh->msgtxt_start);
1062 }
1063 }
1064
SdmGetCtrlLen(MSGH * msgh)1065 static dword _XPENTRY SdmGetCtrlLen(MSGH * msgh)
1066 {
1067
1068 if(InvalidMsgh(msgh))
1069 {
1070 return (dword)-1L;
1071 }
1072
1073 /* If we've already figured out the length of the control info */
1074
1075 if ((msgh->clen == -1) && (_Grab_Clen(msgh) == -1))
1076 {
1077 return 0;
1078 }
1079 else
1080 {
1081 return (dword) msgh->clen;
1082 }
1083 }
1084
_Grab_Clen(MSGH * msgh)1085 static sword near _Grab_Clen(MSGH * msgh)
1086 {
1087 if ((sdword) SdmReadMsg(msgh, NULL, 0L, 0L, NULL, 0L, NULL) < (sdword) 0)
1088 {
1089 return (sword) -1;
1090 }
1091 else
1092 {
1093 return (sword) 0;
1094 }
1095 }
1096
_SdmRescanArea(MSGA * mh)1097 static sword near _SdmRescanArea(MSGA * mh)
1098 {
1099 FFIND *ff;
1100 char *temp;
1101 word mn, thismsg;
1102
1103 if(InvalidMh(mh))
1104 {
1105 return -1;
1106 }
1107
1108 mh->num_msg = 0;
1109
1110 Mhd->msgnum = palloc(SDM_BLOCK * sizeof(unsigned));
1111 if (Mhd->msgnum == NULL)
1112 {
1113 msgapierr = MERR_NOMEM;
1114 return FALSE;
1115 }
1116
1117 Mhd->msgnum_len = SDM_BLOCK;
1118
1119 temp = malloc(strlen((char *)Mhd->base)+6);
1120 if (temp == NULL)
1121 return -1;
1122 sprintf((char *) temp, "%s*.msg", Mhd->base);
1123
1124 ff = FFindOpen((char *) temp, 0);
1125
1126 free(temp);
1127
1128 if (ff != 0)
1129 {
1130 mn = 0;
1131
1132 do
1133 {
1134 /* Don't count zero-length or invalid messages */
1135
1136 #ifndef __UNIX__
1137 if (ff->ff_fsize < OMSG_SIZE)
1138 {
1139 continue;
1140 }
1141 #endif
1142
1143 if (mh->num_msg == (dword)(1 << (sizeof(mh->num_msg) * 8 - 1)))
1144 { /* Messagebase implementaion (size) limit (messages counter is full)*/
1145 msgapierr = MERR_LIMIT;
1146 return FALSE;
1147 }
1148 if (mn >= Mhd->msgnum_len)
1149 {
1150 word msgnum_len_new = Mhd->msgnum_len + (word) SDM_BLOCK;
1151 Mhd->msgnum = realloc(Mhd->msgnum, msgnum_len_new * sizeof(unsigned));
1152
1153 if (!Mhd->msgnum)
1154 {
1155 msgapierr = MERR_NOMEM;
1156 return FALSE;
1157 }
1158 Mhd->msgnum_len = msgnum_len_new;
1159 }
1160
1161 thismsg = (word) atoi(ff->ff_name);
1162 if (thismsg != 0)
1163 {
1164 Mhd->msgnum[mn++] = thismsg;
1165
1166 if ((dword) thismsg > mh->high_msg)
1167 {
1168 mh->high_msg = (dword) thismsg;
1169 }
1170
1171 mh->num_msg = (dword) mn;
1172 }
1173
1174 #ifdef __OS2__
1175 if ((mn % 128) == 127)
1176 tdelay(1L); /* give up cpu */
1177 #endif
1178 }
1179 while (FFindNext(ff) == 0);
1180
1181 FFindClose(ff);
1182
1183 /* Now sort the list of messages */
1184 qksort((int *)Mhd->msgnum, (word) mh->num_msg);
1185 }
1186
1187 return TRUE;
1188 }
1189
Init_Xmsg(XMSG * msg)1190 static void MSGAPI Init_Xmsg(XMSG * msg)
1191 {
1192 if(InvalidMsg(msg))
1193 {
1194 return;
1195 }
1196 memset(msg, '\0', sizeof(XMSG));
1197 }
1198
Convert_Fmsg_To_Xmsg(struct _omsg * fmsg,XMSG * msg,word def_zone)1199 static void MSGAPI Convert_Fmsg_To_Xmsg(struct _omsg *fmsg, XMSG * msg,
1200 word def_zone)
1201 {
1202 NETADDR *orig, *dest;
1203
1204 if(!fmsg){
1205 msgapierr = MERR_BADH;
1206 return;
1207 }
1208 if(InvalidMsg(msg))
1209 {
1210 return;
1211 }
1212
1213 Init_Xmsg(msg);
1214
1215 orig = &msg->orig;
1216 dest = &msg->dest;
1217
1218 fmsg->to[sizeof(fmsg->to) - 1] = '\0';
1219 fmsg->from[sizeof(fmsg->from) - 1] = '\0';
1220 fmsg->subj[sizeof(fmsg->subj) - 1] = '\0';
1221 fmsg->date[sizeof(fmsg->date) - 1] = '\0';
1222
1223 strcpy((char *) msg->from, (char *) fmsg->from);
1224 strcpy((char *) msg->to, (char *) fmsg->to);
1225 strcpy((char *) msg->subj, (char *) fmsg->subj);
1226
1227 orig->zone = dest->zone = def_zone;
1228 orig->point = dest->point = 0;
1229
1230 orig->net = fmsg->orig_net;
1231 orig->node = fmsg->orig;
1232
1233 dest->net = fmsg->dest_net;
1234 dest->node = fmsg->dest;
1235
1236 Get_Binary_Date(&msg->date_written, &fmsg->date_written, fmsg->date);
1237 Get_Binary_Date(&msg->date_arrived, &fmsg->date_arrived, fmsg->date);
1238
1239 strcpy((char *) msg->__ftsc_date, (char *) fmsg->date);
1240
1241 msg->utc_ofs = 0;
1242
1243 msg->replyto = fmsg->reply;
1244 msg->replies[0] = fmsg->up;
1245 msg->attr = (dword) fmsg->attr;
1246 msg->xmtimesread = fmsg->times;
1247 msg->xmcost = fmsg->cost;
1248 }
1249
Convert_Xmsg_To_Fmsg(XMSG * msg,struct _omsg * fmsg)1250 static void MSGAPI Convert_Xmsg_To_Fmsg(XMSG * msg, struct _omsg *fmsg)
1251 {
1252 NETADDR *orig, *dest;
1253
1254 if(!fmsg){
1255 msgapierr = MERR_BADH;
1256 return;
1257 }
1258 if(InvalidMsg(msg))
1259 {
1260 return;
1261 }
1262 memset(fmsg, '\0', sizeof(struct _omsg));
1263
1264 orig = &msg->orig;
1265 dest = &msg->dest;
1266
1267 strncpy((char *) fmsg->from, (char *) msg->from, sizeof(fmsg->from));
1268 strncpy((char *) fmsg->to, (char *) msg->to, sizeof(fmsg->to));
1269 strncpy((char *) fmsg->subj, (char *) msg->subj, sizeof(fmsg->subj));
1270
1271 fmsg->from[sizeof(fmsg->from) - 1] = '\0';
1272 fmsg->to[sizeof(fmsg->to) - 1] = '\0';
1273 fmsg->subj[sizeof(fmsg->subj) - 1] = '\0';
1274
1275 fmsg->orig_net = orig->net;
1276 fmsg->orig = orig->node;
1277
1278 fmsg->dest_net = dest->net;
1279 fmsg->dest = dest->node;
1280
1281 if (*msg->__ftsc_date)
1282 {
1283 strncpy((char *) fmsg->date, (char *) msg->__ftsc_date, sizeof(fmsg->date));
1284 fmsg->date[sizeof(fmsg->date) - 1] = '\0';
1285 }
1286 else
1287 {
1288 sprintf((char *) fmsg->date, "%02d %s %02d %02d:%02d:%02d",
1289 msg->date_written.date.da ? msg->date_written.date.da : 1,
1290 months_ab[msg->date_written.date.mo ? msg->date_written.date.mo - 1 : 0],
1291 (msg->date_written.date.yr + 80) % 100, msg->date_written.time.hh,
1292 msg->date_written.time.mm, msg->date_written.time.ss << 1);
1293 }
1294
1295 fmsg->date_written = msg->date_written;
1296 fmsg->date_arrived = msg->date_arrived;
1297
1298 fmsg->reply = (word) msg->replyto;
1299 fmsg->up = (word) msg->replies[0];
1300 fmsg->attr = (word) (msg->attr & 0xffffL);
1301 fmsg->times = (word)msg->xmtimesread;
1302 fmsg->cost = (word)msg->xmcost;
1303 }
1304
WriteZPInfo(XMSG * msg,void (_stdc * wfunc)(byte * str),byte * kludges)1305 int _XPENTRY WriteZPInfo(XMSG * msg, void (_stdc * wfunc) (byte * str), byte * kludges)
1306 {
1307 byte temp[PATHLEN], *null = (byte *) "";
1308 int bytes = 0;
1309
1310 if(!wfunc){
1311 msgapierr = MERR_BADH;
1312 return -1;
1313 }
1314 if(InvalidMsg(msg))
1315 {
1316 return -1;
1317 }
1318
1319 if (!kludges)
1320 {
1321 kludges = null;
1322 }
1323
1324 if ((msg->dest.zone != mi.def_zone || msg->orig.zone != mi.def_zone) &&
1325 !strstr((char *) kludges, "\001INTL"))
1326 {
1327 sprintf((char *) temp, "\001INTL %hu:%hu/%hu %hu:%hu/%hu\r", msg->dest.zone, msg->dest.net,
1328 msg->dest.node, msg->orig.zone, msg->orig.net, msg->orig.node);
1329
1330 (*wfunc) (temp);
1331 bytes += strlen((char *) temp);
1332 }
1333
1334 if (msg->orig.point && !strstr((char *) kludges, "\001" "FMPT"))
1335 {
1336 sprintf((char *) temp, "\001" "FMPT %hu\r", msg->orig.point);
1337 (*wfunc) (temp);
1338 bytes += strlen((char *) temp);
1339 }
1340
1341 if (msg->dest.point && !strstr((char *) kludges, "\001" "TOPT"))
1342 {
1343 sprintf((char *) temp, "\001" "TOPT %hu\r", msg->dest.point);
1344 (*wfunc) (temp);
1345 bytes += strlen((char *) temp);
1346 }
1347
1348 return bytes;
1349 }
1350
WriteToFd(byte * str)1351 static void _stdc WriteToFd(byte * str)
1352 {
1353 if(str && *str)
1354 {
1355 if( 0 > farwrite(statfd, str, strlen((char *) str)) )
1356 msgapierr = MERR_BADF;
1357 }
1358 else msgapierr = MERR_BADH;
1359 }
1360
Get_Binary_Date(struct _stamp * todate,struct _stamp * fromdate,byte * asciidate)1361 static void near Get_Binary_Date(struct _stamp *todate, struct _stamp *fromdate, byte * asciidate)
1362 {
1363 if(!todate || !fromdate || !asciidate){
1364 msgapierr = MERR_BADH;
1365 return;
1366 }
1367
1368 if (fromdate->date.da == 0 || fromdate->date.da > 31 || fromdate->date.yr > 50 ||
1369 fromdate->time.hh > 23 || fromdate->time.mm > 59 || fromdate->time.ss > 59 ||
1370 ((union stamp_combo *)(void *)&fromdate)->ldate == 0)
1371 {
1372 ASCII_Date_To_Binary((char *) asciidate, (union stamp_combo *)todate);
1373 }
1374 else
1375 {
1376 *todate = *fromdate;
1377 }
1378 }
1379
SdmGetHash(HAREA mh,dword msgnum)1380 static dword _XPENTRY SdmGetHash(HAREA mh, dword msgnum)
1381 {
1382 XMSG xmsg;
1383 HMSG msgh;
1384 dword rc = 0l;
1385
1386 msgh=SdmOpenMsg(mh, MOPEN_READ, msgnum);
1387 if (msgh==NULL)
1388 return (dword) 0l;
1389
1390 if (SdmReadMsg(msgh, &xmsg, 0L, 0L, NULL, 0L, NULL)!=(dword)-1)
1391 {
1392 rc = SquishHash(xmsg.to) | (xmsg.attr & MSGREAD) ? 0x80000000l : 0;
1393 }
1394
1395 SdmCloseMsg(msgh);
1396
1397 msgapierr=MERR_NONE;
1398 return rc;
1399 }
1400
SdmGetNextUid(HAREA ha)1401 static UMSGID _XPENTRY SdmGetNextUid(HAREA ha)
1402 {
1403 if (InvalidMh(ha))
1404 return 0L;
1405
1406 if (!ha->locked)
1407 {
1408 msgapierr=MERR_NOLOCK;
1409 return 0L;
1410 }
1411
1412 msgapierr=MERR_NONE;
1413 return ha->high_msg+1;
1414 }
1415