1 /*
2 * MSG.C
3 *
4 * Written on 10-Jul-94 by John Dennis and released to the public domain.
5 *
6 * Note: Because the SDM routines are NOT the same (the Msgn are the
7 * same as the UIDs, so the Msgn's are not contiguous), I basically had
8 * to create my own API to distance my code from the real API. (Making
9 * it easy to integrate other message types). All msgbase specific
10 * stuff should be kept within the module that handles it.
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
17 #include <errno.h>
18 #include <assert.h>
19
20 #if !defined(UNIX) && !defined(SASC)
21 #include <io.h>
22 #endif
23
24 #if defined(UNIX) || defined(__CYGWIN__)
25 #include <unistd.h>
26 #endif
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31
32 #ifdef __MSC__
33 #include <sys/locking.h>
34 #endif
35
36 #if !defined(UNIX) && !defined(SASC) && !defined(__CYGWIN__)
37 #include <share.h>
38 #endif
39
40 #include <smapi/msgapi.h>
41 #include "addr.h"
42 #include "nedit.h"
43 #include "msged.h"
44 #include "memextra.h"
45 #include "date.h"
46 #include "normal.h"
47 #include "unused.h"
48 #include "msg.h"
49 #include "charset.h"
50
51 static char *cinfbuf = NULL; /* control info buffer, size BUFLEN */
52
53 static unsigned long num_msgs; /* number of messages in msgbase */
54 static unsigned long new = 0; /* if msg being written is new */
55
56 static time_t stampToTimeT(struct _stamp *st);
57 static struct _stamp *timeTToStamp(time_t);
58
59 static struct _minf minf;
60
61 static MSGA *Ahandle = NULL; /* area handle */
62 static MSGH *mh = NULL; /* message handle */
63 static XMSG xmsg; /* squish message header */
64
65 /* these are used by the JAM routines only */
66 static char *global_text = NULL;
67 static unsigned long global_pos = 0;
68 static unsigned long global_len;
69 static unsigned long global_msgn;
70 static int global_ctrl = 1;
71
72 static int ready = FALSE, ctrl = TRUE;
73
74
75 static UMSGID replyto = 0; /* to ensure correct uplinks when mxx is used */
76
77 /* Make Msged work with both stable and current smapi: */
78 #ifndef S_IMODE
79 #define S_IMODE S_IREAD | S_IWRITE
80 #endif
81
82 /*
83 * SquishMsgAreaOpen; Scans an area for messages, opening the message
84 * base and filling the message[] array.
85 */
86
SquishMsgAreaOpen(AREA * a)87 long SquishMsgAreaOpen(AREA * a)
88 {
89 unsigned long lastread; /* lastread record */
90 char work[256]; /* path to sql file */
91 int sql; /* file handle */
92 unsigned long k = 0; /* counter */
93 struct stat bstat; /* stats for sql file */
94 unsigned char buffer[4]; /* for reading and writing the sql */
95
96
97 a->scanned = 1;
98 a->last = 1;
99 a->first = 1;
100 a->lastread = 0;
101 a->current = 0;
102 a->status = 0;
103
104 /* open the msgbase */
105
106 if (mh != NULL)
107 {
108 MsgCloseMsg(mh);
109 mh = NULL;
110 }
111
112 if (Ahandle != NULL)
113 {
114 if (SW->squish_lock)
115 {
116 MsgUnlock(Ahandle);
117 }
118
119 if (MsgCloseArea(Ahandle) == -1)
120 {
121 return 0;
122 }
123 }
124
125
126 Ahandle = MsgOpenArea((byte *)a->path, MSGAREA_CRIFNEC,
127 ((a->msgtype == JAM) ? MSGTYPE_JAM:MSGTYPE_SQUISH));
128 if (Ahandle == NULL)
129 {
130 return 0;
131 }
132
133 if (SW->squish_lock)
134 {
135 if (MsgLock(Ahandle) == -1) /* Lock failed - return */
136 {
137 MsgCloseArea(Ahandle);
138 Ahandle = NULL;
139 return 0;
140 }
141 }
142
143 sprintf(work, "%s.sql", a->path);
144 sql = sopen(work, O_BINARY | O_RDONLY, SH_DENYNO, S_IMODE);
145 if (sql != -1)
146 {
147 #if defined(PACIFIC) || defined(LATTICE)
148 stat(work, &bstat);
149 #else
150 fstat(sql, &bstat);
151 #endif
152 /* we make it big enough */
153 if (bstat.st_size < SW->useroffset * 4)
154 {
155 close(sql);
156 sql = sopen(work, O_BINARY | O_RDWR, SH_DENYNO, S_IMODE);
157 if (sql != -1)
158 {
159 #if defined(PACIFIC) || defined(LATTICE)
160 stat(work, &bstat);
161 #else
162 fstat(sql, &bstat);
163 #endif
164 lastread = 0;
165 buffer[0] = buffer[1] = buffer[2] = buffer[3] = '\0';
166 k = bstat.st_size / 4;
167 lseek(sql, 0L, SEEK_END);
168 while (SW->useroffset > k)
169 {
170 farwrite(sql, buffer, 4);
171 k++;
172 }
173 }
174 }
175 else
176 {
177 /* we read the data in */
178 lseek(sql, SW->useroffset * 4, SEEK_SET);
179 if (farread(sql, buffer, 4) == 4)
180 {
181 lastread = buffer[0] + (((unsigned long)(buffer[1])) << 8) +
182 (((unsigned long)(buffer[2])) << 16) +
183 (((unsigned long)(buffer[3])) << 24);
184
185 if (CurArea.netmail)
186 {
187 a->lastread = MsgUidToMsgn(Ahandle, lastread, UID_PREV);
188 }
189 else
190 {
191 a->lastread = MsgUidToMsgn(Ahandle, lastread, UID_NEXT);
192 }
193 a->current = a->lastread;
194 }
195 }
196 close(sql);
197 }
198
199 if (Ahandle->type != MSGTYPE_JAM)
200 a->last = MsgHighMsg(Ahandle);
201 else
202 a->last = Ahandle->num_msg; /* work around bug in JAM api */
203
204 a->status = 1;
205
206 if (a->last >= 1 && a->current == 0)
207 {
208 a->lastread = 0;
209 a->current = 1;
210 }
211
212 return a->last;
213 }
214
215 /*
216 * SquishMsgReadHeader; Reads in the message header and control
217 * information for the message.
218 */
219
SquishMsgReadHeader(unsigned long n,int type)220 msg *SquishMsgReadHeader(unsigned long n, int type)
221 {
222 char path[PATHLEN];
223 msg *m;
224 int i = 0;
225
226 if (cinfbuf == NULL) cinfbuf = xmalloc(BUFLEN);
227
228 if (Ahandle == NULL)
229 {
230 return NULL;
231 }
232
233 if (mh != NULL)
234 {
235 /* if open, close it */
236 MsgCloseMsg(mh);
237 }
238
239 /* open msg we want to open */
240 mh = MsgOpenMsg(Ahandle, MOPEN_READ, n);
241 if (mh == NULL)
242 {
243 return NULL;
244 }
245
246 if (MsgReadMsg(mh, &xmsg, 0L, 0L, NULL, BUFLEN, (byte *) cinfbuf) == (dword) - 1)
247 {
248 /* no message header or control info! */
249 MsgCloseMsg(mh);
250 mh = NULL;
251 return NULL;
252 }
253
254 m = xcalloc(1, sizeof *m);
255
256 /* basically copy info across to msg */
257 m->msgnum = MsgMsgnToUid(Ahandle, n);
258 m->from.zone = xmsg.orig.zone;
259 m->from.net = xmsg.orig.net;
260 m->from.node = xmsg.orig.node;
261 m->from.point = xmsg.orig.point;
262
263 m->to.zone = xmsg.dest.zone;
264 m->to.net = xmsg.dest.net;
265 m->to.node = xmsg.dest.node;
266 m->to.point = xmsg.dest.point;
267
268 m->from.domain = NULL;
269 m->to.domain = NULL;
270
271 if (xmsg.date_written.date.yr != 0)
272 {
273 m->timestamp = stampToTimeT(&xmsg.date_written);
274 m->time_arvd = stampToTimeT(&xmsg.date_arrived);
275 }
276 else
277 {
278 /* only use this when necesary */
279 memset(path, 0, sizeof path);
280 memcpy(path, xmsg.__ftsc_date, sizeof xmsg.__ftsc_date);
281 m->timestamp = parsedate(path);
282 }
283
284 m->isto = xcalloc(1, sizeof xmsg.to + 1);
285 m->isfrom = xcalloc(1, sizeof xmsg.from + 1);
286 m->subj = xcalloc(1, sizeof xmsg.subj + 1);
287
288 memcpy(m->isto, xmsg.to, sizeof xmsg.to);
289 memcpy(m->isfrom, xmsg.from, sizeof xmsg.from);
290 memcpy(m->subj, xmsg.subj, sizeof xmsg.subj);
291
292 m->attrib.priv = (xmsg.attr & MSGPRIVATE) != 0;
293 m->attrib.crash = (xmsg.attr & MSGCRASH) != 0;
294 m->attrib.rcvd = (xmsg.attr & MSGREAD) != 0;
295 m->attrib.sent = (xmsg.attr & MSGSENT) != 0;
296 m->attrib.attach = (xmsg.attr & MSGFILE) != 0;
297 m->attrib.forward = (xmsg.attr & MSGFWD) != 0;
298 m->attrib.orphan = (xmsg.attr & MSGORPHAN) != 0;
299 m->attrib.killsent = (xmsg.attr & MSGKILL) != 0;
300 m->attrib.local = (xmsg.attr & MSGLOCAL) != 0;
301 m->attrib.hold = (xmsg.attr & MSGHOLD) != 0;
302 m->attrib.direct = (xmsg.attr & MSGXX2) != 0;
303 m->attrib.freq = (xmsg.attr & MSGFRQ) != 0;
304 m->attrib.rreq = (xmsg.attr & MSGRRQ) != 0;
305 m->attrib.rcpt = (xmsg.attr & MSGCPT) != 0;
306 m->attrib.areq = (xmsg.attr & MSGARQ) != 0;
307 m->attrib.ureq = (xmsg.attr & MSGURQ) != 0;
308
309 m->attrib.lock = (xmsg.attr & MSGLOCKED) != 0;
310
311 if (xmsg.attr & MSGSCANNED)
312 {
313 m->scanned = 1;
314 }
315
316 if (type != RD_HEADER_BRIEF)
317 {
318 m->replyto = MsgUidToMsgn(Ahandle, xmsg.replyto, UID_EXACT);
319
320 while (i < 9)
321 {
322 if (xmsg.replies[i] != 0)
323 {
324 m->replies[i] = MsgUidToMsgn(Ahandle, xmsg.replies[i], UID_EXACT);
325 }
326 else
327 {
328 m->replies[i] = 0;
329 }
330 i++;
331 }
332 m->replies[9] = 0;
333 }
334
335 m->cost = 0;
336 m->times_read = 0;
337 m->text = NULL;
338 m->to.fidonet = 1;
339 m->from.fidonet = 1;
340
341 if (type == RD_HEADER || type == RD_HEADER_BRIEF)
342 {
343 MsgCloseMsg(mh);
344 mh = NULL;
345 }
346
347 return m;
348 }
349
350 /*
351 * SquishMsgReadText; Reads in the entire message, adds the control
352 * information to the beginning of the message and continues to return
353 * the message to the caller line by line (at each subsequent call).
354 * Basically a conversion of the correspoding Fido function.
355 */
356
SquishMsgReadText(unsigned long n)357 char *SquishMsgReadText(unsigned long n)
358 {
359 static char *next = NULL;
360 static char *end = NULL;
361 char *t = NULL;
362 char *text = NULL;
363 char eol = '\0';
364 unsigned long i, l;
365 static unsigned long ofs = 0, s = 0;
366
367 unused(n);
368 if (Ahandle == NULL)
369 {
370 return NULL;
371 }
372
373 if (cinfbuf == NULL) cinfbuf = xmalloc(BUFLEN);
374
375 if (next == NULL && s != 0)
376 {
377 /* we are finished */
378 s = ofs = 0;
379 return NULL;
380 }
381
382 if (s == 0)
383 {
384 /* ready to read in new msg */
385 memset(msgbuf, 0, BUFLEN - 1);
386 next = msgbuf;
387 if (MsgGetCtrlLen(mh) > 0)
388 {
389 /* copy control info from */
390 t = cinfbuf; /* insert /r's */
391 *(t + (size_t) ((MsgGetCtrlLen(mh)>=BUFLEN) ? (BUFLEN - 1) :
392 MsgGetCtrlLen(mh))) = '\0';
393 if (*t != '\0')
394 {
395 *next++ = *t++;
396 while (*t != '\0' && next - msgbuf < BUFLEN - 2)
397 {
398 if (*t == '\01')
399 {
400 *next++ = '\r'; /* add a \r to the text */
401 }
402 if (next - msgbuf < BUFLEN - 2)
403 {
404 *next++ = *t++;
405 }
406 }
407 if (*(next - 1) == '\01')
408 {
409 next--;
410 *(next) = '\0';
411 }
412 else
413 {
414 if (next - msgbuf < BUFLEN - 2)
415 {
416 *next++ = '\r';
417 }
418 *next = '\0'; /* terminate string */
419 }
420 }
421 next = msgbuf;
422 end = msgbuf + normalize(msgbuf);
423 }
424 else
425 {
426 next = NULL;
427 }
428
429 s = BUFLEN;
430 }
431
432 /* return msg a line at a time */
433 if (next == NULL)
434 {
435 i = MsgReadMsg(mh, NULL, ofs, s - 1, (byte *) msgbuf, 0L, NULL);
436 ofs += i;
437 if (i < 1)
438 {
439 s = ofs = 0;
440 next = NULL;
441 return NULL;
442 }
443 next = msgbuf;
444 while (i && *next == '\0')
445 {
446 i--;
447 next++;
448 }
449 normalize(next);
450 end = msgbuf + strlen(msgbuf);
451 if (end < next)
452 {
453 next = end;
454 }
455 }
456
457 if (end - next == 0)
458 {
459 t = NULL;
460 }
461 else
462 {
463 t = memchr(next, '\n', (int)(end - next));
464 }
465
466 if (t == NULL)
467 {
468 l = strlen(next);
469 memmove(msgbuf, next, (size_t) (l + 1));
470 i = MsgReadMsg(mh, NULL, ofs, s - l - 1,
471 (byte *)(msgbuf + (size_t) l), 0L, NULL);
472 ofs += i;
473 if (i < 1)
474 {
475 next = NULL;
476 return xstrdup(msgbuf);
477 }
478 *(msgbuf + (size_t) l + (size_t) i) = '\0';
479 end = msgbuf + l + normalize(msgbuf + (size_t) l);
480 next = msgbuf;
481 t = strchr(next, '\n');
482 }
483
484 if (t != NULL)
485 {
486 eol = *(t + 1);
487 *(t + 1) = '\0';
488 }
489
490 text = xstrdup(next);
491
492 if (t != NULL)
493 {
494 *(t + 1) = eol;
495 next = t + 1;
496 }
497 else
498 {
499 next = NULL;
500 }
501
502 return text;
503 }
504
505 /*
506 * SquishMsgWriteHeader; Writes message header to the message base,
507 * creates new frame if new message, and makes sure links are correct.
508 */
509
SquishMsgWriteHeader(msg * m,int type)510 int SquishMsgWriteHeader(msg * m, int type)
511 {
512 unsigned long n;
513 int i = 0;
514
515 n = MsgUidToMsgn(Ahandle, m->msgnum, UID_EXACT);
516
517 if (Ahandle == NULL)
518 {
519 return FALSE;
520 }
521
522 if (mh != NULL) /* close old msg, if left open */
523 {
524 MsgCloseMsg(mh);
525 }
526
527 if (m->new)
528 {
529 /*
530 * If new, store current number of messages (for use in
531 * SquishMsgWriteText, and create a new frame for the new
532 * message.
533 */
534
535 num_msgs = MsgGetNumMsg(Ahandle);
536 mh = MsgOpenMsg(Ahandle, MOPEN_CREATE, 0L);
537 if (mh == NULL)
538 {
539 return ERR_OPEN_MSG;
540 }
541 new = TRUE;
542 }
543 else
544 {
545 /* else we open the message to be changed */
546 mh = MsgOpenMsg(Ahandle, MOPEN_RW, n);
547 if (mh == NULL)
548 {
549 return ERR_OPEN_MSG;
550 }
551 new = FALSE;
552 }
553
554 memset(&xmsg, 0, sizeof xmsg);
555
556 xmsg.attr = 0;
557 if (m->attrib.priv)
558 {
559 xmsg.attr |= MSGPRIVATE;
560 }
561 if (m->attrib.crash)
562 {
563 xmsg.attr |= MSGCRASH;
564 }
565 if (m->attrib.rcvd)
566 {
567 xmsg.attr |= MSGREAD;
568 }
569 if (m->attrib.sent)
570 {
571 xmsg.attr |= MSGSENT;
572 }
573 if (m->attrib.attach)
574 {
575 xmsg.attr |= MSGFILE;
576 }
577 if (m->attrib.forward)
578 {
579 xmsg.attr |= MSGFWD;
580 }
581 if (m->attrib.orphan)
582 {
583 xmsg.attr |= MSGORPHAN;
584 }
585 if (m->attrib.killsent)
586 {
587 xmsg.attr |= MSGKILL;
588 }
589 if (m->attrib.local)
590 {
591 xmsg.attr |= MSGLOCAL;
592 }
593 if (m->attrib.hold)
594 {
595 xmsg.attr |= MSGHOLD;
596 }
597 if (m->attrib.direct)
598 {
599 xmsg.attr |= MSGXX2;
600 }
601 if (m->attrib.freq)
602 {
603 xmsg.attr |= MSGFRQ;
604 }
605 if (m->attrib.rreq)
606 {
607 xmsg.attr |= MSGRRQ;
608 }
609 if (m->attrib.rcpt)
610 {
611 xmsg.attr |= MSGCPT;
612 }
613 if (m->attrib.areq)
614 {
615 xmsg.attr |= MSGARQ;
616 }
617 if (m->attrib.ureq)
618 {
619 xmsg.attr |= MSGURQ;
620 }
621 if (m->attrib.lock)
622 {
623 xmsg.attr |= MSGLOCKED;
624 }
625
626 if (new == FALSE)
627 {
628 /*
629 * If the old message had been scanned, then we make sure that
630 * the MSGSCANNED bit is set on the way out. New messages get
631 * this bit stripped.
632 */
633
634 if (m->scanned && !m->new)
635 {
636 xmsg.attr |= MSGSCANNED;
637 }
638 }
639
640 if (m->replyto != 0)
641 {
642 /* get the links for replies */
643 xmsg.replyto = MsgMsgnToUid(Ahandle, m->replyto);
644 }
645
646 for (i = 0; i < 9; i++)
647 {
648 if (m->replies[i] != 0)
649 {
650 xmsg.replies[i] = MsgMsgnToUid(Ahandle, m->replies[i]);
651 }
652 }
653
654 i = 0;
655
656 while (m->replies[i] != 0 && i < 9)
657 {
658 i++;
659 }
660
661 if (i == 9)
662 {
663 i = 8;
664 }
665
666 if (!m->new && replyto != 0)
667 {
668 xmsg.replies[i] = replyto;
669 replyto = 0;
670 }
671
672 xmsg.dest.zone = (word) m->to.zone;
673 xmsg.dest.net = (word) m->to.net;
674 xmsg.dest.node = (word) m->to.node;
675 xmsg.dest.point = (word) m->to.point;
676
677 xmsg.orig.zone = (word) m->from.zone;
678 xmsg.orig.net = (word) m->from.net;
679 xmsg.orig.node = (word) m->from.node;
680 xmsg.orig.point = (word) m->from.point;
681
682 if (m->isto != NULL)
683 {
684 memcpy(xmsg.to, m->isto, min(sizeof xmsg.to, strlen(m->isto)));
685 }
686
687 if (m->isfrom != NULL)
688 {
689 memcpy(xmsg.from, m->isfrom, min(sizeof xmsg.from, strlen(m->isfrom)));
690 }
691
692 if (m->subj != NULL)
693 {
694 memcpy(xmsg.subj, m->subj, min(sizeof xmsg.subj, strlen(m->subj)));
695 }
696
697 memcpy(xmsg.__ftsc_date, mtime(m->timestamp), 20);
698
699 xmsg.date_written = *timeTToStamp(m->timestamp);
700
701 if (m->time_arvd != 0)
702 {
703 xmsg.date_arrived = *timeTToStamp(m->time_arvd);
704 }
705 else
706 {
707 xmsg.date_arrived = xmsg.date_written;
708 }
709
710 if (type == WR_HEADER || !new)
711 {
712 MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, 0L, 0L, NULL);
713 MsgCloseMsg(mh);
714 mh = NULL;
715 }
716
717 return TRUE;
718 }
719
720 /*
721 * strip_whitel; Strips the white spaces from the control info,
722 * copying it to the msgbuf array while it's at it. Returns new
723 * length.
724 */
725
strip_whitel(void)726 static dword strip_whitel(void)
727 {
728 char *s, *c, *cptr;
729
730 if (cinfbuf == NULL) cinfbuf = xmalloc(BUFLEN);
731
732 /* we put it in the cinfbuf, killing any \r & \n's in the process */
733 cptr = cinfbuf;
734 s = msgbuf;
735 c = s + strlen(s) + 1;
736 while (s != c)
737 {
738 /* copy buffer across, ignoring any fluff in the source buffer */
739 switch (*s)
740 {
741 case '\r':
742 case '\n':
743 s++;
744 break;
745 default:
746 *cptr++ = *s++;
747 break;
748 }
749 }
750 *cptr = '\0';
751 return cptr - cinfbuf;
752 }
753
JamMsgWriteText(char * text,unsigned long msgn,unsigned long mlen)754 int JamMsgWriteText(char *text, unsigned long msgn, unsigned long mlen)
755 {
756 int l;
757
758 if (global_ctrl)
759 {
760 if (text != NULL && *text != '\01')
761 {
762 global_ctrl = 0;
763 }
764 else
765 {
766 return SquishMsgWriteText(text, msgn, mlen);
767 }
768 }
769
770
771 if (global_text == NULL)
772 {
773 global_text = xmalloc(mlen + 1);
774 global_pos = 0;
775 global_len = mlen;
776 global_msgn = msgn;
777 }
778
779 if (text != NULL)
780 l = strlen(text);
781 else
782 l = 0;
783
784 assert(global_len == mlen);
785 assert(global_pos + l <= mlen);
786
787 if (l)
788 {
789 memcpy(global_text + global_pos, text, l);
790 global_text[global_pos + l] = '\0';
791 global_pos += l;
792 }
793
794 return TRUE;
795 }
796
797
798 /*
799 * SquishMsgWriteText; Writes message text (and header if a new
800 * message), to the message base. If the message is not new and
801 * new text is larger, it creates a new frame, while keeping the
802 * same position in the index.
803 */
804
SquishMsgWriteText(char * text,unsigned long msgn,unsigned long mlen)805 int SquishMsgWriteText(char *text, unsigned long msgn, unsigned long mlen)
806 {
807 static char *tptr, *c;
808 static unsigned long n = 0;
809 char cz = 0;
810 unsigned long clen;
811
812 if (Ahandle == NULL)
813 {
814 return FALSE;
815 }
816
817 if (cinfbuf == NULL) cinfbuf = xmalloc(BUFLEN);
818
819 if (ready == FALSE)
820 {
821 /* starting on new message; reset pointers */
822 ready = TRUE;
823 tptr = msgbuf;
824 n = MsgUidToMsgn(Ahandle, msgn, UID_EXACT);
825 }
826
827 if (text == NULL)
828 {
829 if (ctrl)
830 {
831 /* no body in the message */
832 if (new)
833 {
834 clen = strip_whitel();
835
836 /* we could fix this to not use append. */
837 MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, mlen, clen,
838 (byte *)cinfbuf);
839 MsgWriteMsg(mh, TRUE, NULL, (byte *)&cz,
840 sizeof(char), mlen, 0L, NULL);
841 }
842 else
843 {
844 mh = MsgOpenMsg(Ahandle, MOPEN_RW, n);
845 if (mh == NULL)
846 {
847 ready = FALSE;
848 ctrl = TRUE;
849 new = FALSE; /* we only change the header */
850 return FALSE;
851 }
852 MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, mlen, 0L, NULL);
853 }
854 }
855 else
856 {
857 /* I THINK we might also be able to fix this
858 not to use append. */
859 MsgWriteMsg(mh, TRUE, NULL, (byte *)&cz, sizeof(char),
860 mlen, 0L, NULL);
861 }
862
863 if (new)
864 {
865 /*
866 * Message is a reply - save new number so next header
867 * written can use it for the uplink number.
868 */
869
870 if (xmsg.replyto)
871 {
872 replyto = MsgMsgnToUid(Ahandle, MsgGetNumMsg(Ahandle));
873 }
874 if (num_msgs == MsgGetNumMsg(Ahandle))
875 {
876 CurArea.messages--;
877 }
878 }
879
880 new = ready = FALSE;
881 ctrl = TRUE;
882 return TRUE;
883 }
884
885 if (*text == '\01' && ctrl)
886 {
887 c = text;
888 while (*c != '\0')
889 {
890 /* store the control info */
891 *tptr++ = *c++;
892 }
893 *tptr = '\0';
894 }
895 else
896 {
897 if (*text != '\01' && ctrl)
898 {
899 ctrl = FALSE;
900 clen = strip_whitel();
901 if (!new)
902 {
903 /* we are modifying a non-new message */
904 mh = MsgOpenMsg(Ahandle, MOPEN_RW, n);
905 if (mh == NULL)
906 {
907 ready = FALSE;
908 ctrl = TRUE;
909 new = FALSE;
910 return FALSE;
911 }
912
913 if (MsgReadMsg(mh, &xmsg, 0L, 0L, NULL, 0L, NULL) == (dword) - 1)
914 {
915 new = FALSE;
916 ready = FALSE;
917 ctrl = TRUE;
918 return FALSE;
919 }
920
921 MsgCloseMsg(mh); /* copy xmsg information across */
922
923 mh = MsgOpenMsg(Ahandle, MOPEN_CREATE, n);
924 if (mh == NULL)
925 {
926 ready = FALSE;
927 ctrl = TRUE;
928 new = FALSE;
929 return FALSE;
930 }
931
932 /* messy, but it works */
933 MsgWriteMsg(mh, FALSE, &xmsg, (byte *)text,
934 strlen(text), mlen, clen, (byte *)cinfbuf);
935 }
936 else
937 {
938 /* we'd need to intercept this call if we want
939 to make it work with JAM api */
940
941 MsgWriteMsg(mh, FALSE, &xmsg, (byte *)text,
942 strlen(text), mlen, clen, (byte *)cinfbuf);
943 }
944 }
945 else
946 {
947 /* this does NOT work with JAM api */
948 MsgWriteMsg(mh, TRUE, NULL, (byte *)text, strlen(text),
949 mlen, 0L, NULL);
950 }
951 }
952
953 return TRUE;
954 }
955
JamMsgClose(void)956 int JamMsgClose(void)
957 {
958 int rv = TRUE;
959 int srv = TRUE;
960
961 if (global_text != NULL)
962 {
963 if (SquishMsgWriteText(global_text, global_msgn, global_len) != TRUE)
964 rv = ERR_CLOSE_MSG;
965 xfree(global_text);
966
967 global_ctrl = 1; /* reset! */
968 global_text = NULL;
969 global_pos = 0;
970 }
971
972 srv = SquishMsgClose();
973 return (rv != TRUE ? rv : srv);
974 }
975
976 /*
977 * SquishMsgClose; Closes the message currently opened.
978 */
979
SquishMsgClose(void)980 int SquishMsgClose(void)
981 {
982 if (mh == NULL)
983 {
984 return TRUE;
985 }
986
987 if (MsgCloseMsg(mh) == -1)
988 {
989 printf("\n!SquishMsgClose(): Message didn't close, error %ud!\n", msgapierr);
990 exit(-1);
991 return ERR_CLOSE_MSG;
992 }
993 else
994 {
995 ready = FALSE; ctrl = TRUE;
996 mh = NULL;
997 return TRUE;
998 }
999 }
1000
1001
1002 /*
1003 * Area locking functions
1004 */
1005
SquishMsgLock(void)1006 int SquishMsgLock(void)
1007 {
1008 if (!SW->squish_lock)
1009 {
1010 return MsgLock(Ahandle);
1011 }
1012 else
1013 {
1014 return 0; /* area already locked */
1015 }
1016 }
1017
SquishMsgUnlock(void)1018 int SquishMsgUnlock(void)
1019 {
1020 if (!SW->squish_lock)
1021 {
1022 return MsgUnlock(Ahandle);
1023 }
1024 else
1025 {
1026 return 0;
1027 }
1028 }
1029
1030
1031 /*
1032 * SquishMsgAreaClose; Closes the area currently opened.
1033 */
1034
SquishMsgAreaClose(void)1035 int SquishMsgAreaClose(void)
1036 {
1037 if (Ahandle == NULL)
1038 {
1039 return TRUE;
1040 }
1041
1042 if (SW->squish_lock)
1043 {
1044 MsgUnlock(Ahandle);
1045 }
1046
1047 if (MsgCloseArea(Ahandle) == -1)
1048 {
1049 printf("\n!SquishMsgAreaClose(): Area didn't close, error %ud!\n", msgapierr);
1050 exit(-1);
1051 return ERR_CLOSE_AREA;
1052 }
1053 else
1054 {
1055 CurArea.status = 0;
1056 Ahandle = NULL;
1057 return TRUE;
1058 }
1059 }
1060
1061 /*
1062 * SquishUidToMsgn; Returns the corresponding message number of a UID.
1063 */
1064
SquishUidToMsgn(unsigned long n)1065 unsigned long SquishUidToMsgn(unsigned long n)
1066 {
1067 return MsgUidToMsgn(Ahandle, n, UID_EXACT);
1068 }
1069
1070 /*
1071 * SquishMsgnToUid; Returns the corresponding UID of a message number.
1072 */
1073
SquishMsgnToUid(unsigned long n)1074 unsigned long SquishMsgnToUid(unsigned long n)
1075 {
1076 return MsgMsgnToUid(Ahandle, n);
1077 }
1078
1079 /*
1080 * SquishAreaSetLast; Sets the last message read in the .sql file and
1081 * closes the message area. If the .sql file doesn't exist, create it.
1082 */
1083
SquishAreaSetLast(AREA * a)1084 int SquishAreaSetLast(AREA * a)
1085 {
1086 char work[255];
1087 long i = 1;
1088 int ret = TRUE;
1089 int fd;
1090 unsigned char buffer[4];
1091
1092 if (mh != NULL)
1093 {
1094 MsgCloseMsg(mh);
1095 mh = NULL;
1096 }
1097
1098 if (Ahandle != NULL)
1099 {
1100 sprintf(work, "%s.sql", a->path);
1101
1102 fd = sopen(work, O_BINARY | O_RDWR, SH_DENYNO, S_IMODE);
1103 if (fd == -1)
1104 {
1105 if (errno != EACCES && errno != EMFILE)
1106 {
1107 fd = sopen(work, O_BINARY | O_WRONLY | O_CREAT, SH_DENYNO,
1108 S_IMODE);
1109 if (fd == -1)
1110 {
1111 ret = FALSE;
1112 }
1113 else
1114 {
1115 buffer[0] = buffer[1] = buffer[2] = buffer[3] = '\0';
1116 lseek(fd, 0L, SEEK_SET);
1117 for (i = 0; SW->useroffset > (int)i; i++)
1118 {
1119 farwrite(fd, buffer, 4);
1120 }
1121
1122 i = MsgMsgnToUid(Ahandle, CurArea.lastread);
1123 buffer[0] = i & 0xFF;
1124 buffer[1] = (i >> 8) & 0xFF;
1125 buffer[2] = (i >> 16) & 0xFF;
1126 buffer[3] = (i >> 24) & 0xFF;
1127
1128 farwrite(fd, buffer, 4);
1129 close(fd);
1130 }
1131 }
1132 else
1133 {
1134 ret = FALSE;
1135 }
1136 }
1137 else
1138 {
1139 lseek(fd, SW->useroffset * 4, SEEK_SET);
1140
1141 if (SW->use_lastr)
1142 {
1143 i = MsgMsgnToUid(Ahandle, CurArea.lastread);
1144 }
1145 else
1146 {
1147 i = MsgMsgnToUid(Ahandle, CurArea.current);
1148 }
1149
1150 buffer[0] = i & 0xFF;
1151 buffer[1] = (i >> 8) & 0xFF;
1152 buffer[2] = (i >> 16) & 0xFF;
1153 buffer[3] = (i >> 24) & 0xFF;
1154
1155 farwrite(fd, buffer, 4);
1156 close(fd);
1157 }
1158 }
1159 return ret;
1160 }
1161
1162 /*
1163 * SquishMsgDelete; Erases a message in the current area, specified
1164 * by the passed index.
1165 */
1166
SquishMsgDelete(unsigned long n)1167 int SquishMsgDelete(unsigned long n)
1168 {
1169 unsigned long msgn;
1170 msgn = MsgUidToMsgn(Ahandle, n, UID_EXACT);
1171 if (MsgKillMsg(Ahandle, msgn) == -1)
1172 {
1173 return FALSE;
1174 }
1175 return TRUE;
1176 }
1177
stampToTimeT(struct _stamp * st)1178 static time_t stampToTimeT(struct _stamp *st)
1179 {
1180 time_t tt;
1181 struct tm tms;
1182 tms.tm_sec = st->time.ss << 1;
1183 tms.tm_min = st->time.mm;
1184 tms.tm_hour = st->time.hh;
1185 tms.tm_mday = st->date.da;
1186 tms.tm_mon = st->date.mo - 1;
1187 tms.tm_year = st->date.yr + 80;
1188 tms.tm_isdst = -1;
1189 tt = mktime(&tms);
1190 return tt;
1191 }
1192
timeTToStamp(time_t tt)1193 static struct _stamp *timeTToStamp(time_t tt)
1194 {
1195 struct tm *tmsp;
1196 static struct _stamp st;
1197 tmsp = localtime(&tt);
1198 st.time.ss = tmsp->tm_sec >> 1;
1199 st.time.mm = tmsp->tm_min;
1200 st.time.hh = tmsp->tm_hour;
1201 st.date.da = tmsp->tm_mday;
1202 st.date.mo = tmsp->tm_mon + 1;
1203 st.date.yr = tmsp->tm_year - 80;
1204 return &st;
1205 }
1206
MsgApiInit(void)1207 void MsgApiInit(void)
1208 {
1209 minf.def_zone = 0; /* set default zone */
1210 minf.req_version = 0; /* level 0 of the MsgAPI */
1211 MsgOpenApi(&minf); /* init the MsgAPI */
1212 }
1213
MsgApiTerm(void)1214 void MsgApiTerm(void)
1215 {
1216 MsgCloseApi();
1217 }
1218