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