1 /*
2 * QUICK.C
3 *
4 * Written on 30-Jul-90 by jim nutt and released to the public domain.
5 *
6 * Support for QuickBBS-style message bases.
7 */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <time.h>
12 #ifndef PACIFIC
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #else
16 #include <stat.h>
17 #endif
18 #include <assert.h>
19 #include <huskylib/compiler.h>
20 #include "addr.h"
21 #include "nedit.h"
22 #include "msged.h"
23 #include "unused.h"
24 #include "memextra.h"
25 #include "date.h"
26 #include "normal.h"
27 #include "quick.h"
28 #include "charset.h"
29
30
31 typedef unsigned int bits;
32
33 #define CHUNKSZ 32
34
35 #define QLASTN 200
36 short qlast[QLASTN];
37
38 static char msgtxt[FILENAME_MAX];
39 static char msghdr[FILENAME_MAX];
40
41 /* I/O macros for platform independent
42 binary I/O. copied from smapi, as
43 msged with quick can be compiled
44 without/smapi (!) */
45
put_word(unsigned char * ptr,unsigned short value)46 static void put_word(unsigned char *ptr, unsigned short value)
47 {
48 ptr[0] = (value & 0xFF);
49 ptr[1] = (value >> 8) & 0xFF;
50 }
51
52 #define get_word(ptr) \
53 ((unsigned short)((unsigned char)(ptr)[0]) | \
54 (((unsigned short)((unsigned char)(ptr)[1])) << 8 ))
55
56
read_qlast(FILE * f,short * p)57 int read_qlast(FILE *f, short *p)
58 {
59 unsigned char buf[QLASTN * 2], *pbuf = buf;
60 int i;
61
62 if (fread(buf, 2*QLASTN, 1, f) != 1)
63 {
64 return 0;
65 }
66
67 for (i=0; i < QLASTN; i++)
68 {
69 p[i] = get_word(pbuf);
70 pbuf += 2;
71 }
72 return 1;
73
74 }
75
write_qlast(FILE * f,short * p)76 int write_qlast(FILE *f, short *p)
77 {
78 unsigned char buf[QLASTN * 2], *pbuf = buf;
79 int i;
80
81 for (i=0; i < QLASTN; i++)
82 {
83 put_word(pbuf, p[i]); pbuf+=2;
84 }
85
86 assert(pbuf - buf == QLASTN * 2);
87
88 return (fwrite(buf, 2*QLASTN, 1, f) == 2*QLASTN);
89 }
90
91
92
93 struct qinfo
94 {
95 short low;
96 short high;
97 short active;
98 short areas[200];
99 };
100 #define QINFO_SIZE (6+200*2)
101
read_qinfo(FILE * f,struct qinfo * qinfo)102 int read_qinfo(FILE *f, struct qinfo *qinfo)
103 {
104 unsigned char buf[QINFO_SIZE], *pbuf = buf;
105 int i;
106
107 if (fread(buf, QINFO_SIZE, 1, f) != 1)
108 {
109 return 0;
110 }
111
112 qinfo->low = get_word(pbuf); pbuf+=2;
113 qinfo->high = get_word(pbuf); pbuf+=2;
114 qinfo->active = get_word(pbuf); pbuf+=2;
115 for (i=0; i < 200; i++)
116 {
117 qinfo->areas[i] = get_word(pbuf); pbuf+=2;
118 }
119 assert (pbuf - buf == QINFO_SIZE);
120 return 1;
121 }
122
write_qinfo(FILE * f,struct qinfo * qinfo)123 int write_qinfo(FILE *f, struct qinfo *qinfo)
124 {
125 unsigned char buf[QINFO_SIZE], *pbuf = buf;
126 int i;
127
128 put_word(pbuf, qinfo->low); pbuf+=2;
129 put_word(pbuf, qinfo->high); pbuf+=2;
130 put_word(pbuf, qinfo->active); pbuf+=2;
131 for (i=0; i < 200; i++)
132 {
133 put_word(pbuf, qinfo->areas[i]); pbuf+=2;
134 }
135 assert (pbuf - buf == QINFO_SIZE);
136
137 if (fwrite(buf, QINFO_SIZE, 1, f) != 1)
138 {
139 return 0;
140 }
141
142 return 1;
143 }
144
145 struct qidx
146 {
147 short number;
148 char board;
149 };
150 #define QIDX_SIZE 3
151
read_qidx(FILE * f,struct qidx * qidx)152 int read_qidx(FILE *f, struct qidx *qidx)
153 {
154 unsigned char buf[QIDX_SIZE], *pbuf = buf;
155
156 if (fread(buf, QIDX_SIZE, 1, f) != 1)
157 {
158 return 0;
159 }
160
161 qidx->number = get_word(pbuf); pbuf+=2;
162 qidx->board = *pbuf; pbuf++;
163
164 assert (pbuf - buf == QIDX_SIZE);
165 return 1;
166 }
167
write_qidx(FILE * f,struct qidx * qidx)168 int write_qidx(FILE *f, struct qidx *qidx)
169 {
170 unsigned char buf[QIDX_SIZE], *pbuf = buf;
171
172 put_word(pbuf, qidx->number); pbuf+=2;
173 *pbuf = qidx->board; pbuf++;
174
175 assert (pbuf - buf == QIDX_SIZE);
176
177 if (fwrite(buf, QIDX_SIZE, 1, f) != 1)
178 {
179 return 0;
180 }
181 return 1;
182 }
183
184
185 struct qmsg
186 {
187 short number;
188 short replyto;
189 short replyfrom;
190 short times_read; /* 8 bytes */
191 unsigned short start;
192 unsigned short count;
193 short destnet;
194 short destnode; /* 16 bytes */
195 short orignet;
196 short orignode;
197 char destzone;
198 char origzone;
199 short cost; /* 24 bytes */
200
201 /* message attributes */
202 bits deleted : 1;
203 bits outnet : 1;
204 bits netmail : 1;
205 bits priv : 1;
206 bits rcvd : 1;
207 bits echo : 1;
208 bits local : 1;
209 bits xx1 : 1;
210 bits killsent : 1;
211 bits sent : 1;
212 bits attach : 1;
213 bits crash : 1;
214 bits rreq : 1;
215 bits areq : 1;
216 bits rrcpt : 1;
217 bits xx2 : 1; /* 26 bytes */
218
219 char board; /* 27 bytes */
220 char posttime[6]; /* 33 bytes */
221 char postdate[9]; /* 42 bytes */
222 char whoto[36]; /* 78 bytes */
223 char whofrom[36]; /* 114 bytes */
224 char subject[73]; /* 187 bytes */
225 };
226 #define QMSG_SIZE 187
227
read_qmsg(FILE * f,struct qmsg * qmsg)228 static int read_qmsg(FILE *f, struct qmsg *qmsg)
229 {
230 unsigned char buf[QMSG_SIZE], *pbuf = buf;
231 unsigned short attr;
232
233 if (fread(buf, QMSG_SIZE, 1, f) != 1)
234 {
235 return 0;
236 }
237
238 qmsg->number=get_word(pbuf); pbuf+=2;
239 qmsg->replyto=get_word(pbuf); pbuf+=2;
240 qmsg->replyfrom=get_word(pbuf); pbuf+=2;
241 qmsg->times_read=get_word(pbuf); pbuf+=2;
242 qmsg->start=get_word(pbuf); pbuf+=2;
243 qmsg->count=get_word(pbuf); pbuf+=2;
244 qmsg->destnet=get_word(pbuf); pbuf+=2;
245 qmsg->destnode=get_word(pbuf); pbuf+=2;
246 qmsg->orignet=get_word(pbuf); pbuf+=2;
247 qmsg->orignode=get_word(pbuf); pbuf+=2;
248 qmsg->destzone = *pbuf; pbuf++;
249 qmsg->origzone = *pbuf; pbuf++;
250 qmsg->cost=get_word(pbuf); pbuf+=2;
251
252 attr = get_word(pbuf); pbuf+=2;
253 qmsg->deleted = attr & 1; attr = attr >> 1;
254 qmsg->outnet = attr & 1; attr = attr >> 1;
255 qmsg->netmail = attr & 1; attr = attr >> 1;
256 qmsg->priv = attr & 1; attr = attr >> 1;
257 qmsg->rcvd = attr & 1; attr = attr >> 1;
258 qmsg->echo = attr & 1; attr = attr >> 1;
259 qmsg->local = attr & 1; attr = attr >> 1;
260 qmsg->xx1 = attr & 1; attr = attr >> 1;
261 qmsg->killsent = attr & 1; attr = attr >> 1;
262 qmsg->sent = attr & 1; attr = attr >> 1;
263 qmsg->attach = attr & 1; attr = attr >> 1;
264 qmsg->crash = attr & 1; attr = attr >> 1;
265 qmsg->rreq = attr & 1; attr = attr >> 1;
266 qmsg->areq = attr & 1; attr = attr >> 1;
267 qmsg->rrcpt = attr & 1; attr = attr >> 1;
268 qmsg->xx2 = attr & 1; attr = attr >> 1;
269
270 qmsg->board = *pbuf; pbuf++;
271 memcpy(qmsg->posttime, pbuf, 6); pbuf+=6;
272 memcpy(qmsg->postdate, pbuf, 9); pbuf+=9;
273 memcpy(qmsg->whoto, pbuf, 36); pbuf+=36;
274 memcpy(qmsg->whofrom, pbuf, 36); pbuf+=36;
275 memcpy(qmsg->subject, pbuf, 73); pbuf+=73;
276 assert (pbuf - buf == QMSG_SIZE);
277 return 1;
278 }
279
write_qmsg(FILE * f,struct qmsg * qmsg)280 static int write_qmsg(FILE *f, struct qmsg *qmsg)
281 {
282 unsigned char buf[QMSG_SIZE], *pbuf = buf;
283 unsigned short attr;
284
285
286 put_word(pbuf,qmsg->number); pbuf+=2;
287 put_word(pbuf,qmsg->replyto); pbuf+=2;
288 put_word(pbuf,qmsg->replyfrom); pbuf+=2;
289 put_word(pbuf,qmsg->times_read); pbuf+=2;
290 put_word(pbuf,qmsg->start); pbuf+=2;
291 put_word(pbuf,qmsg->count); pbuf+=2;
292 put_word(pbuf,qmsg->destnet); pbuf+=2;
293 put_word(pbuf,qmsg->destnode); pbuf+=2;
294 put_word(pbuf,qmsg->orignet); pbuf+=2;
295 put_word(pbuf,qmsg->orignode); pbuf+=2;
296 *pbuf = qmsg->destzone; pbuf++;
297 *pbuf = qmsg->origzone; pbuf++;
298 put_word(pbuf,qmsg->cost); pbuf+=2;
299
300 attr =
301 (qmsg->deleted ? 1 : 0) +
302 (qmsg->outnet ? 2 : 0) +
303 (qmsg->netmail ? 4 : 0) +
304 (qmsg->priv ? 8 : 0 )+
305 (qmsg->rcvd ? 16 : 0 ) +
306 (qmsg->echo ? 32 : 0 ) +
307 (qmsg->local ? 64 : 0 ) +
308 (qmsg->xx1 ? 128 : 0 ) +
309 (qmsg->killsent ? 256 : 0 ) +
310 (qmsg->sent ? 512 : 0 ) +
311 (qmsg->attach ? 1024 : 0 ) +
312 (qmsg->crash ? 2048 : 0 ) +
313 (qmsg->rreq ? 4096 : 0 ) +
314 (qmsg->areq ? 8192 : 0 ) +
315 (qmsg->rrcpt ? 16384 : 0 ) +
316 (qmsg->xx2 ? 32768U : 0 );
317
318 put_word(pbuf, attr); pbuf+=2;
319
320 *pbuf = qmsg->board; pbuf++;
321 memcpy(pbuf, qmsg->posttime, 6); pbuf+=6;
322 memcpy(pbuf, qmsg->postdate, 9); pbuf+=9;
323 memcpy(pbuf, qmsg->whoto, 36); pbuf+=36;
324 memcpy(pbuf, qmsg->whofrom, 36); pbuf+=36;
325 memcpy(pbuf, qmsg->subject, 73); pbuf+=73;
326
327 assert (pbuf - buf == QMSG_SIZE);
328
329 if (fwrite(buf, QMSG_SIZE, 1, f) != 1)
330 {
331 return 0;
332 }
333
334 return 1;
335 }
336
337 struct qtext
338 {
339 unsigned char length;
340 char text[BLOCKLEN];
341 };
342 #define QTEXT_SIZE (BLOCKLEN+1)
343
read_qtext(FILE * f,struct qtext * qtext)344 static int read_qtext(FILE *f, struct qtext *qtext)
345 {
346 unsigned char buf[QTEXT_SIZE], *pbuf = buf;
347
348 if (fread(buf, QTEXT_SIZE, 1, f) != 1)
349 {
350 return 0;
351 }
352
353 qtext->length= *pbuf; pbuf++;
354 memcpy(qtext->text, pbuf, BLOCKLEN); pbuf+=BLOCKLEN;
355
356 assert (pbuf - buf == QTEXT_SIZE);
357 return 1;
358 }
359
write_qtext(FILE * f,struct qtext * qtext)360 static int write_qtext(FILE *f, struct qtext *qtext)
361 {
362 unsigned char buf[QTEXT_SIZE], *pbuf = buf;
363
364 *pbuf = qtext->length; pbuf++;
365 memcpy(pbuf, qtext->text, BLOCKLEN); pbuf+=BLOCKLEN;
366
367 assert (pbuf - buf == QTEXT_SIZE);
368
369 if (fwrite(buf, QTEXT_SIZE, 1, f) != 1)
370 {
371 return 0;
372 }
373 return 1;
374 }
375
376
377 static struct qinfo info;
378 static struct qmsg header;
379
380 static char path[80];
381 static long start = -1;
382 static long count = 0;
383 static int position = 0;
384 static FILE *infofp = NULL;
385 static FILE *idxfp = NULL;
386 static FILE *textfp = NULL;
387 static FILE *hdrfp = NULL;
388 static FILE *toidxfp = NULL;
389 static short *messages = NULL;
390 static int maxmsgs;
391
QuickMsgDelete(unsigned long n)392 int QuickMsgDelete(unsigned long n)
393 {
394 struct qidx index;
395
396 header.deleted = 1;
397
398 if (fseek(hdrfp, (long)(messages[(size_t) (n - 1)] *
399 (long)QIDX_SIZE), SEEK_SET))
400 {
401 return FALSE;
402 }
403
404 write_qmsg(hdrfp, &header);
405 fflush(hdrfp);
406
407 fseek(idxfp, messages[(size_t) (n - 1)] * (long)QIDX_SIZE, SEEK_SET);
408 index.board = (char)CurArea.board;
409 index.number = -1;
410 write_qidx(idxfp, &index);
411 fflush(idxfp);
412
413 start = count = 0;
414 position = 0;
415
416 info.areas[CurArea.board - 1]--;
417 fseek(infofp, 0L, SEEK_SET);
418 write_qinfo(infofp, &info);
419 fflush(infofp);
420
421 return TRUE;
422 }
423
QuickMsgWriteText(char * text,unsigned long n,unsigned long mlen)424 int QuickMsgWriteText(char *text, unsigned long n, unsigned long mlen)
425 {
426 static struct qtext block;
427 char *s;
428 static char buf[768];
429 struct stat b;
430 static int f = 0;
431
432 unused(mlen);
433 if (f == 0)
434 {
435 f = 1;
436 #if defined(PACIFIC) || defined(LATTICE)
437 stat(msgtxt, &b);
438 #else
439 fstat(fileno(textfp), &b);
440 #endif
441 start = b.st_size / QTEXT_SIZE;
442 count = 0;
443 }
444
445 if (text == NULL)
446 {
447 n = position;
448 memset(block.text, 0, sizeof block.text);
449 strcpy(block.text, buf);
450 block.length = (char)strlen(buf);
451 fseek(textfp, (long)(start + count) * (long)QTEXT_SIZE, SEEK_SET);
452 write_qtext(textfp, &block);
453 fflush(textfp);
454 header.start = (unsigned short)start;
455 header.count = (unsigned short)++count;
456 fseek(hdrfp, (long)n * (long)QMSG_SIZE, SEEK_SET);
457 write_qmsg(hdrfp, &header);
458 fflush(hdrfp);
459 f = 0;
460 memset(buf, 0, sizeof buf);
461 return TRUE;
462 }
463
464 strcat(buf, text);
465 while (strlen(buf) > sizeof block.text)
466 {
467 s = buf + sizeof block.text;
468 memcpy(block.text, buf, sizeof block.text);
469 strcpy(buf, s);
470 block.length = sizeof block.text;
471 fseek(textfp, (long)(start + count) * (long)QTEXT_SIZE, SEEK_SET);
472 write_qtext(textfp, &block);
473 fflush(textfp);
474 count++;
475 }
476
477 return TRUE;
478 }
479
quick2msg(short number)480 short quick2msg(short number)
481 {
482 struct qidx index;
483 int i = 0;
484
485 if (number == 0)
486 {
487 return 0;
488 }
489
490 for (i = 0; i < CurArea.messages; i++)
491 {
492 if (fseek(idxfp, messages[(size_t) i] * (long) QIDX_SIZE, SEEK_SET))
493 {
494 return 0;
495 }
496 if (read_qidx(idxfp, &index) != 1)
497 {
498 return 0;
499 }
500 if (index.number == number)
501 {
502 return (short) (i + 1);
503 }
504 }
505 return 0;
506 }
507
msg2quick(short n)508 short msg2quick(short n)
509 {
510 struct qidx index;
511
512 if (n > (CurArea.messages + 1) || n == 0)
513 {
514 return 0;
515 }
516
517 if (fseek(idxfp, messages[(size_t) (n - 1)] * (long)QIDX_SIZE, SEEK_SET))
518 {
519 return 0;
520 }
521
522 if (read_qidx(idxfp, &index) != 1)
523 {
524 return 0;
525 }
526
527 return index.number;
528 }
529
find_link(unsigned long n)530 short find_link(unsigned long n)
531 {
532 struct qmsg header;
533 struct stat b;
534 long i;
535
536 if (messages == NULL)
537 {
538 return 0;
539 }
540
541 #if defined(PACIFIC) || defined(LATTICE)
542 stat(msghdr, &b);
543 #else
544 fstat(fileno(hdrfp), &b);
545 #endif
546
547 i = (long)(messages[(size_t) (n - 1)]) * (long)QMSG_SIZE;
548 if (i > b.st_size)
549 {
550 return 0;
551 }
552
553 fseek(hdrfp, i, SEEK_SET);
554 if (read_qmsg(hdrfp, &header) != 1)
555 {
556 return 0;
557 }
558
559 #if defined(PACIFIC) || defined(LATTICE)
560 fclose(textfp);
561 textfp = fopen(msgtxt, "r+b");
562 stat(msgtxt, &b);
563 #else
564 fstat(fileno(textfp), &b);
565 #endif
566
567 if ((((long)header.start + (long)header.count) *
568 (long)QTEXT_SIZE) > b.st_size)
569 {
570 return 0;
571 }
572
573 if (header.deleted)
574 {
575 return 0;
576 }
577
578 return quick2msg(header.replyfrom);
579 }
580
QuickMsgReadHeader(unsigned long n,int type)581 msg *QuickMsgReadHeader(unsigned long n, int type)
582 {
583 struct stat b;
584 char path[80];
585 msg *m;
586 long i;
587
588 unused(type);
589 if (messages == NULL || n == 0)
590 {
591 return NULL;
592 }
593 memset(path, 0, sizeof path);
594
595 #if defined(PACIFIC) || defined(LATTICE)
596 stat(msghdr, &b);
597 #else
598 fstat(fileno(hdrfp), &b);
599 #endif
600
601 i = (long)(messages[(size_t) (n - 1)]) * (long) QMSG_SIZE;
602 if (i > b.st_size)
603 {
604 return NULL;
605 }
606
607 position = messages[(size_t) (n - 1)];
608
609 fseek(hdrfp, i, SEEK_SET);
610 if (read_qmsg(hdrfp, &header) != 1)
611 {
612 return NULL;
613 }
614
615 start = (long)header.start;
616 count = (long)header.count;
617
618 #ifdef PACIFIC
619 fclose(textfp);
620 textfp = fopen(msgtxt, "r+b");
621 stat(msgtxt, &b);
622 #else
623 fstat(fileno(textfp), &b);
624 #endif
625 if (((start + count) * (long)QTEXT_SIZE) > b.st_size)
626 {
627 return NULL;
628 }
629
630 if (header.deleted)
631 {
632 return NULL;
633 }
634
635 m = xcalloc(1, sizeof *m);
636 m->msgnum = quick2msg(header.number);
637
638 m->isfrom = xcalloc(header.whofrom[0] + 1, 1);
639 strncpy(m->isfrom, header.whofrom + 1, header.whofrom[0]);
640 m->isto = xcalloc(header.whoto[0] + 1, 1);
641 strncpy(m->isto, header.whoto + 1, header.whoto[0]);
642 m->subj = xcalloc(header.subject[0] + 1, 1);
643 strncpy(m->subj, header.subject + 1, header.subject[0]);
644
645 strncpy(path, header.postdate + 1, header.postdate[0]);
646 strcat(path, " ");
647 strncat(path, header.posttime + 1, header.posttime[0]);
648 m->timestamp = parsedate(path);
649
650 if (!(type & RD_HEADER_BRIEF))
651 {
652 if (header.replyto)
653 {
654 m->replyto = quick2msg(header.replyto);
655 }
656 if (header.replyfrom)
657 {
658 m->replies[0] = quick2msg(header.replyfrom);
659 }
660 if (type & RD_ALL)
661 {
662 header.times_read++;
663 fseek(hdrfp, (long)position * (long)QMSG_SIZE, SEEK_SET);
664 write_qmsg(hdrfp, &header);
665 }
666 }
667
668 m->attrib.priv = header.priv;
669 m->attrib.crash = header.crash;
670 m->attrib.rcvd = header.rcvd;
671 m->attrib.sent = header.sent;
672 m->attrib.attach = header.attach;
673 m->attrib.forward = 0;
674 m->attrib.orphan = 0;
675 m->attrib.killsent = header.killsent;
676 m->attrib.local = header.local;
677 m->attrib.hold = header.xx1;
678 m->attrib.direct = header.xx2;
679 m->attrib.freq = 0;
680 m->attrib.rreq = header.rreq;
681 m->attrib.rcpt = header.rrcpt;
682 m->attrib.areq = header.areq;
683 m->attrib.ureq = 0;
684
685 m->to.zone = header.destzone;
686 m->to.net = header.destnet;
687 m->to.node = header.destnode;
688 m->times_read = header.times_read;
689
690 m->from.zone = header.destzone;
691 m->from.net = header.destnet;
692 m->from.node = header.destnode;
693
694 m->to.fidonet = m->from.fidonet = 1;
695
696 return m;
697 }
698
QuickMsgWriteHeader(msg * m,int type)699 int QuickMsgWriteHeader(msg * m, int type)
700 {
701 struct qidx index;
702 struct tm *ts;
703 struct stat b;
704 FILE *fp;
705 size_t len_to, len_from, len_subj;
706 int c = (int)(CurArea.current - 1);
707
708 unused(type);
709 memset(&header, 0, sizeof header);
710
711 if (m->new)
712 {
713 c = (int)CurArea.messages;
714 #ifdef PACIFIC
715 stat(msghdr, &b);
716 #else
717 fstat(fileno(hdrfp), &b);
718 #endif
719 if (c >= maxmsgs)
720 {
721 messages = xrealloc(messages, (maxmsgs += CHUNKSZ) * sizeof(short));
722 }
723 messages[c] = (short)(b.st_size / QMSG_SIZE);
724 start = (unsigned short)(header.start = 0);
725 count = (unsigned short)(header.count = 0);
726 info.areas[CurArea.board - 1]++;
727 info.active++;
728 header.number = ++info.high;
729 }
730 else
731 {
732 if ((header.number = msg2quick((short)m->msgnum)) == 0)
733 {
734 return FALSE;
735 }
736 header.start = (unsigned short)start;
737 header.count = (unsigned short)count;
738 }
739
740 position = messages[c];
741
742 header.replyto = msg2quick((short)m->replyto);
743 header.replyfrom = msg2quick((short)(m->replies[0]));
744 header.times_read = (short)m->times_read;
745 header.destzone = (char)m->to.zone;
746 header.destnet = (short)m->to.net;
747 header.destnode = (short)m->to.node;
748 header.origzone = (char)m->from.zone;
749 header.orignet = (short)m->from.net;
750 header.orignode = (short)m->from.node;
751 header.cost = (short)m->cost;
752
753 header.deleted = 0;
754 header.outnet = 0;
755 header.netmail = 0;
756 header.echo = 0;
757
758 if (CurArea.netmail)
759 {
760 header.netmail = 1;
761 header.outnet = 1;
762 }
763
764 if (CurArea.echomail)
765 {
766 header.echo = 1;
767 }
768
769 header.priv = m->attrib.priv;
770 header.rcvd = m->attrib.rcvd;
771 header.local = m->attrib.local;
772 header.xx1 = m->attrib.hold;
773 header.killsent = m->attrib.killsent;
774 header.sent = m->attrib.sent;
775 header.attach = m->attrib.attach;
776 header.crash = m->attrib.crash;
777 header.rreq = m->attrib.rreq;
778 header.areq = m->attrib.areq;
779 header.rrcpt = m->attrib.rcpt;
780 header.xx2 = m->attrib.direct;
781 header.board = (char)CurArea.board;
782
783 ts = localtime(&m->timestamp);
784 header.posttime[0] = 5;
785 sprintf(header.posttime + 1, "%02d:%02d", ts->tm_hour, ts->tm_min);
786 header.postdate[0] = 8;
787 sprintf(header.postdate + 1, "%02d-%02d-%02d", ts->tm_mon + 1,
788 ts->tm_mday, (ts->tm_year % 100));
789
790 if (m->isto == NULL)
791 {
792 header.whoto[0] = 0;
793 }
794 else
795 {
796 len_to = strlen(m->isto);
797 header.whoto[0] = (char)min(len_to, sizeof(header.whoto) - 1);
798 memcpy(header.whoto + 1, m->isto, header.whoto[0]);
799 }
800
801 if (m->isfrom == NULL)
802 {
803 header.whofrom[0] = 0;
804 }
805 else
806 {
807 len_from = strlen(m->isfrom);
808 header.whofrom[0] = (char)min(len_from, sizeof(header.whofrom));
809 memcpy(header.whofrom + 1, m->isfrom, header.whofrom[0]);
810 }
811
812 if (m->subj == NULL)
813 {
814 header.subject[0] = 0;
815 }
816 else
817 {
818 len_subj = strlen(m->subj);
819 header.subject[0] = (char)min(len_subj, sizeof(header.subject) - 1);
820 memcpy(header.subject + 1, m->subj, header.subject[0]);
821 }
822
823 fseek(hdrfp, (long)position * (long)QMSG_SIZE, SEEK_SET);
824 write_qmsg(hdrfp, &header);
825
826 fseek(infofp, 0L, SEEK_SET);
827 write_qinfo(infofp, &info);
828
829 index.number = header.number;
830 index.board = (char)CurArea.board;
831 fseek(idxfp, (long)position * (long)QIDX_SIZE, SEEK_SET);
832 write_qidx(idxfp, &index);
833
834 fflush(idxfp);
835 fflush(infofp);
836 fflush(hdrfp);
837
838 strcpy(path, ST->quickbbs);
839 strcat(path, "/msgtoidx.bbs");
840 fp = fopen(path, "r+b");
841 if (fp == NULL)
842 {
843 fp = fopen(path, "w+b");
844 if (fp == NULL)
845 {
846 return TRUE;
847 }
848 }
849
850 fseek(fp, (long)position * (long)sizeof(header.whoto), SEEK_SET);
851 fwrite(header.whoto, sizeof(header.whoto), 1, fp);
852 fclose(fp);
853
854 return TRUE;
855 }
856
QuickMsgReadText(unsigned long n)857 char *QuickMsgReadText(unsigned long n)
858 {
859 static struct qtext text;
860
861 static long int b = -1;
862 static long int c = -1;
863
864 static char *next = NULL;
865 char *t, *t2, ch = '\0';
866
867 static char *s = NULL;
868
869 if ((long)n < 0)
870 {
871 b = c = -1;
872 next = NULL;
873 if (s)
874 {
875 xfree(s);
876 }
877 s = NULL;
878 return NULL;
879 }
880
881 if (next == NULL && s != NULL)
882 {
883 xfree(s);
884 b = c = -1;
885 s = NULL;
886 return NULL;
887 }
888
889 if (s == NULL)
890 {
891
892 if (b == -1)
893 {
894 b = (long)(start = (long)header.start);
895 c = (long)(count = (long)header.count);
896 }
897
898 if (c < 1 || b < 0)
899 {
900 b = c = -1;
901 return NULL;
902 }
903
904 s = xmalloc((size_t) count * sizeof text + 1);
905
906 memset(s, 0, (size_t) c * sizeof text + 1);
907
908 fseek(textfp, (long)(start * (long)QTEXT_SIZE), SEEK_SET);
909 while (c)
910 {
911 memset(&text, 0, sizeof text);
912 if (read_qtext(textfp, &text) == 1)
913 {
914 if (text.length > sizeof text.text) /* Always false!!! */
915 {
916 text.length = sizeof text.text;
917 }
918 strncat(s, text.text, text.length);
919 }
920 c--;
921 }
922 normalize(s);
923 next = s;
924 }
925
926 t = next;
927 next = strchr(t, '\n');
928 if (next)
929 {
930 ch = *(next + 1);
931 *(next + 1) = '\0';
932 }
933
934 t2 = xstrdup(t);
935
936 if (next)
937 {
938 *(next + 1) = ch;
939 next++;
940 }
941
942 return t2;
943 }
944
QuickAreaSetLast(AREA * a)945 int QuickAreaSetLast(AREA * a)
946 {
947 FILE *fp;
948
949 strcpy(path, ST->quickbbs);
950 strcat(path, "/lastread.bbs");
951
952 if (messages == NULL || a->current == 0)
953 {
954 qlast[a->board - 1] = 0;
955 }
956 else
957 {
958 qlast[a->board - 1] = msg2quick((short) a->lastread);
959 }
960
961 fp = fopen(path, "wb");
962 if (fp != NULL)
963 {
964 write_qlast(fp, qlast);
965 fclose(fp);
966 }
967
968 return TRUE;
969 }
970
quick_scan(AREA * a)971 static int quick_scan(AREA * a)
972 {
973 struct qidx index;
974 FILE *fp;
975 int i, idx;
976
977 position = 0;
978
979 if (infofp != NULL)
980 {
981 fclose(infofp);
982 }
983
984 strcpy(path, ST->quickbbs);
985 strcat(path, "/msginfo.bbs");
986
987 infofp = fopen(path, "r+b");
988 if (infofp == NULL)
989 {
990 infofp = fopen(path, "w+b");
991 if (infofp == NULL)
992 {
993 return 0;
994 }
995 }
996
997 if (idxfp != NULL)
998 {
999 fclose(idxfp);
1000 }
1001
1002 strcpy(path, ST->quickbbs);
1003 strcat(path, "/msgidx.bbs");
1004 idxfp = fopen(path, "r+b");
1005 if (idxfp == NULL)
1006 {
1007 idxfp = fopen(path, "w+b");
1008 if (idxfp == NULL)
1009 {
1010 return 0;
1011 }
1012 }
1013
1014 if (textfp != NULL)
1015 {
1016 fclose(textfp);
1017 }
1018
1019 strcpy(path, ST->quickbbs);
1020 strcat(path, "/msgtxt.bbs");
1021 strcpy(msgtxt, path);
1022 textfp = fopen(path, "r+b");
1023 if (textfp == NULL)
1024 {
1025 textfp = fopen(path, "w+b");
1026 if (textfp == NULL)
1027 {
1028 return 0;
1029 }
1030 }
1031
1032 if (hdrfp != NULL)
1033 {
1034 fclose(hdrfp);
1035 }
1036
1037 strcpy(path, ST->quickbbs);
1038 strcat(path, "/msghdr.bbs");
1039 strcpy(msghdr, path);
1040 hdrfp = fopen(path, "r+b");
1041 if (hdrfp == NULL)
1042 {
1043 hdrfp = fopen(path, "w+b");
1044 if (hdrfp == NULL)
1045 {
1046 return 0;
1047 }
1048 }
1049
1050 if (toidxfp != NULL)
1051 {
1052 fclose(toidxfp);
1053 }
1054
1055 strcpy(path, ST->quickbbs);
1056 strcat(path, "/msgtoidx.bbs");
1057 toidxfp = fopen(path, "r+b");
1058 if (toidxfp == NULL)
1059 {
1060 toidxfp = fopen(path, "w+b");
1061 if (toidxfp == NULL)
1062 {
1063 return 0;
1064 }
1065 }
1066
1067 if (messages != NULL)
1068 {
1069 xfree(messages);
1070 }
1071
1072 messages = NULL;
1073
1074 rewind(infofp);
1075 if (read_qinfo(infofp, &info) != 1)
1076 {
1077 memset(&info, 0, sizeof info);
1078 }
1079
1080 i = 0;
1081 maxmsgs = 0;
1082 idx = 0;
1083 rewind(idxfp);
1084 while (read_qidx(idxfp, &index) == 1)
1085 {
1086 if (index.board == (char)a->board && index.number > 0)
1087 {
1088 if (i >= maxmsgs)
1089 {
1090 messages = xrealloc(messages, (maxmsgs += CHUNKSZ) * sizeof(short));
1091 }
1092 messages[i++] = (short)idx;
1093 }
1094 idx++;
1095 }
1096
1097 a->first = 1;
1098 a->last = i;
1099 a->messages = i;
1100
1101 strcpy(path, ST->quickbbs);
1102 strcat(path, "/lastread.bbs");
1103 fp = fopen(path, "rb");
1104 if (fp != NULL)
1105 {
1106 read_qlast(fp, qlast);
1107 a->lastread = qlast[a->board - 1];
1108 fclose(fp);
1109 }
1110
1111 a->current = quick2msg((short) a->lastread);
1112 a->lastread = a->current;
1113
1114 if (a->lastread > i || i <= 0)
1115 {
1116 a->lastread = 0;
1117 }
1118 if (a->current > i || i <= 0)
1119 {
1120 a->current = 0;
1121 }
1122
1123 info.areas[a->board - 1] = (short)i;
1124
1125 return i;
1126 }
1127
QuickMsgClose(void)1128 int QuickMsgClose(void)
1129 {
1130 return 0;
1131 }
1132
QuickMsgAreaOpen(AREA * a)1133 long QuickMsgAreaOpen(AREA * a)
1134 {
1135 long ret;
1136 ret = quick_scan(a);
1137 a->status = 1;
1138 a->scanned = 1;
1139 return ret;
1140 }
1141
QuickMsgAreaClose(void)1142 int QuickMsgAreaClose(void)
1143 {
1144 CurArea.status = 0;
1145 return TRUE;
1146 }
1147
QuickMsgnToUid(unsigned long n)1148 unsigned long QuickMsgnToUid(unsigned long n)
1149 {
1150 return n;
1151 }
1152
QuickUidToMsgn(unsigned long n)1153 unsigned long QuickUidToMsgn(unsigned long n)
1154 {
1155 return n;
1156 }
1157
QuickMsgLock(void)1158 int QuickMsgLock(void)
1159 {
1160 return 0;
1161 }
1162
QuickMsgUnlock(void)1163 int QuickMsgUnlock(void)
1164 {
1165 return 0;
1166 }
1167