1 /*
2  *  READMAIL.C
3  *
4  *  Written on 30-Jul-90 by jim nutt.  Changes on 10-Jul-94 by John Dennis.
5  *  Released to the public domain.
6  *
7  *  Handles high-level message I/O.
8  */
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14 #include <ctype.h>
15 
16 #if defined(__MSC__) || defined(OS216)
17 #include <sys/types.h>
18 #include <sys/timeb.h>
19 #include <direct.h>
20 #endif
21 
22 #if defined(MSDOS) && defined(__TURBOC__)
23 #include <dir.h>
24 #endif
25 
26 #ifdef __WATCOMC__
27 #if defined(MSDOS) || defined(WINNT)
28 #include <direct.h>
29 #endif
30 #endif
31 
32 #ifdef PACIFIC
33 #include <sys.h>
34 int bdos(int func, unsigned reg_dx, unsigned char reg_al);
35 #endif
36 
37 #if defined(MSDOS) || (defined(WINNT) && (!defined(__MINGW32__)) && (!defined(__CYGWIN__)))
38 #include <dos.h>
39 #ifdef __TURBOC__
40 #include <dir.h>
41 #endif
42 #endif
43 
44 #ifdef OS2
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #endif
49 
50 #if defined(UNIX) || defined(__DJGPP__)
51 #include <unistd.h>
52 #endif
53 
54 #ifdef __MINGW32__
55 #define chdir _chdir
56 #endif
57 
58 #include "addr.h"
59 #include "nedit.h"
60 #include "msged.h"
61 #include "flags.h"
62 #include "memextra.h"
63 #include "strextra.h"
64 #include "config.h"
65 #include "quote.h"
66 #include "wrap.h"
67 #include "fecfg145.h"
68 #include "winsys.h"
69 #include "menu.h"
70 #include "dialogs.h"
71 #include "version.h"
72 #include "readmail.h"
73 #include "charset.h"
74 #include "date.h"
75 #include "echotoss.h"
76 #include "mctype.h"
77 #include "help.h"
78 #include "template.h"
79 
80 #define rand_number(num) ((int) (((long) rand()) % (num)))
81 
82 #define TEXTLEN 96
83 
84 static void deleteCrapLine(LINE * crap);
85 static int is_sameaddr(FIDO_ADDRESS * msg);
86 
87 extern int set_rcvd;      /* located in msged.c */
88 
89 int read_verbatim = 0;    /* see readmail.h for explanation */
90 
91 #ifdef OS2
92 static unsigned long setDefaultDisk(unsigned short x);
93 #endif
94 
95 static int changeDir(char *path);
96 
do_softcrxlat(char * ptr)97 char *do_softcrxlat(char *ptr)
98 {
99     char *p;
100 
101     if (softcrxlat && ptr != NULL)
102     {
103         p = strchr(ptr, 0x8d);
104         while (p != NULL)
105         {
106             *p++ = softcrxlat;
107             p = strchr(p, 0x8d);
108         }
109     }
110 
111     return ptr;
112 }
113 
clearbuffer(LINE * buffer)114 LINE *clearbuffer(LINE * buffer)
115 {
116     LINE *curline;
117 
118     curline = buffer;
119     if (curline != NULL)
120     {
121 	while (curline->next != NULL)
122 	{
123 	    curline = curline->next;
124 	    if (curline->prev == NULL)
125 	    {
126 		continue;
127 	    }
128 	    if (curline->prev->text != NULL)
129 	    {
130 		xfree(curline->prev->text);
131 	    }
132 	    curline->prev->next = NULL;
133 	    xfree(curline->prev);
134 	    curline->prev = NULL;
135 	}
136 	if (curline != NULL)
137 	{
138 	    if (curline->text)
139 	    {
140 		xfree(curline->text);
141 	    }
142 	    curline->text = NULL;
143 	    xfree(curline);
144 	}
145     }
146     return NULL;
147 }
148 
KillTrailingLF(char * text)149 static void KillTrailingLF(char *text)
150 {
151     char *s;
152 
153     if (text == NULL)
154     {
155 	return;
156     }
157 
158     s = strchr(text, '\n');
159     if (s != NULL)
160     {
161 	*s = '\0';
162     }
163 }
164 
readmsg(unsigned long n)165 msg *readmsg(unsigned long n)
166 {
167     FIDO_ADDRESS a;
168     LINE *l;
169     char *tokens[10];
170     int headerfin = 0, lastwasfromto = 0;
171     int afound = 0;
172     msg *m;
173     char *text;
174     char *t, *s;
175     char *ptmp;
176     char tmp[128];
177     int goteot = 0;
178     int gotsot = 0;
179     int had_codepage = 0;
180     LOOKUPTABLE *ltable = NULL;
181     int fmpt, topt;
182     int clevel = 0;
183 
184     l = NULL;
185 
186     memset(&a, 0, sizeof a);
187 
188     m = MsgReadHeader(n, RD_ALL);
189     if (m == NULL)
190     {
191 	read_verbatim = 0;
192 	return NULL;
193     }
194 
195     stripSoft = 1;
196     m->replyarea = NULL;
197     if (ST->enforced_charset != NULL || ST->input_charset != NULL)
198     {
199         memset(tokens, 0, sizeof(tokens));
200         if (ST->enforced_charset != NULL)
201         {
202             text = xstrdup(ST->enforced_charset);
203         }
204         else
205         {
206             text = xstrdup(ST->input_charset);
207         }
208         parse_tokens(text, tokens, 2);
209         if (tokens[1])
210         {
211             m->charset_level = atoi(tokens[1]);
212         }
213         else
214         {
215             m->charset_level = 2;
216         }
217         m->charset_name = xstrdup(tokens[0]);
218         ltable = get_readtable(m->charset_name, m->charset_level);
219         free(text);
220     }
221     else
222     {
223 	m->charset_name = NULL;
224 	m->charset_level = 0;
225 	ltable = get_readtable("ASCII", 2);
226     }
227 
228     while ((text = MsgReadText(n)) != NULL)
229     {
230 	if (*text == '\n' || *text == '\0' || !stricmp(text, "Lines:"))
231 	{
232 	    headerfin = 1;  /* want to stop looking unix header info */
233 
234 	    if (lastwasfromto && (!SW->shownotes) && (!read_verbatim))
235 	    {
236 		 release(text); /* skip the blank line after from: / to: */
237 		 lastwasfromto = 0;
238 		 continue;
239 	    }
240 	}
241 
242 	lastwasfromto = 0;
243 
244 	if (*text == '\01')
245 	{
246 	    switch (*(text + 1))
247 	    {
248 	    case 'A':
249 		if (strncmp(text + 1, "AREA:", 5) != 0)
250 		{
251 		    break;
252 		}
253 		s = text + 6;
254 
255 		while (m_isspace(*s))
256 		{
257 		    s++;
258 		}
259 
260 		release(m->replyarea);
261 		m->replyarea = xstrdup(s);
262 		KillTrailingLF(m->replyarea);
263 		break;
264 
265 	    case 'C':
266                 if (ST->enforced_charset != NULL)
267                 {
268                     /* CHRS kludge is ignored if a special input charset
269                        is enforced */
270                     break;
271                 }
272 
273 		if (strncmp(text + 1, "CHRS:", 5) == 0)
274 		{
275                     if (had_codepage)
276                         break;  /* @CODEPAGE is definitive override */
277                     s = text + 6;
278                     strcpy(tmp, s + 1);
279                 }
280                 else if (strncmp(text + 1, "CHARSET:", 8) == 0)
281                 {
282                     if (had_codepage)
283                         break;  /* @CODEPAGE is definitive override */
284                     s = text + 9;
285                     strcpy(tmp, s + 1);
286                 }
287                 else if (strncmp(text + 1, "CODEPAGE:", 9) == 0)
288                 {
289                     had_codepage = 1;
290                     s = text + 10;
291                     sprintf(tmp, "CP%s 2", s+1);
292                 }
293                 else
294                 {
295                     break;
296                 }
297 
298 		memset(tokens, 0, sizeof(tokens));
299 		parse_tokens(tmp, tokens, 2);
300 		if (!tokens[1] || !tokens[1][0])
301 		{
302                     clevel = 2;
303                        /* Assume level 2 as default. The CHARSET kludge has no
304                           level at all, and some broken message readers omit
305                           the level also for the CHRS kludge. */
306 		}
307                 else
308                 {
309                     clevel = atoi(tokens[1]);
310                 }
311 
312                 if ( have_readtable(tokens[0], clevel) ||
313                      ST->input_charset == NULL /* user wants no assumptions */)
314                 {
315                     release(m->charset_name);
316                     m->charset_name  = xstrdup(tokens[0]);
317                     m->charset_level = clevel;
318                     ltable = get_readtable(m->charset_name,
319                                            m->charset_level);
320                 }
321 		break;
322 
323 	    case 'M':
324 		if (strncmp(text + 1, "MSGID:", 6) != 0)
325 		{
326 		    break;
327 		}
328 		s = text + 7;
329 
330 		while (m_isspace(*s))
331 		{
332 		    s++;
333 		}
334 
335 		release(m->msgid);
336 		m->msgid = xstrdup(s);
337 		KillTrailingLF(m->msgid);
338 		break;
339 
340 	    case 'R':
341 		if (strncmp(text + 1, "REPLY:", 6) != 0)
342 		{
343 		    break;
344 		}
345 		s = text + 7;
346 
347 		while (m_isspace(*s))
348 		{
349 		    s++;
350 		}
351 
352 		if (arealist[SW->area].msgtype != QUICK)
353 		{
354 		    release(m->reply);
355 		    m->reply = xstrdup(s);
356 		    KillTrailingLF(m->reply);
357 		}
358 		break;
359 
360 	    case 'E':
361 		if (strncmp(text + 1, "EOT:", 4) == 0)
362 		{
363 		    goteot = 1;
364 		    if (gotsot && !(SW->showseenbys ||
365 				    SW->shownotes   || read_verbatim))
366 		    {
367 			m->soteot = 1;
368 		    }
369 		}
370 		break;
371 
372 	    case 'S':
373 		if (strncmp(text + 1, "SOT:", 4) == 0)
374 		{
375 		    gotsot = 1;
376 		    stripSoft = 0;
377 		}
378 		break;
379 
380 	    case 'F':
381 		if (strncmp(text + 1, "FMPT", 4) == 0)
382 		{
383                     s = text + 5;
384                     m->from.point = atoi(s + 1);
385                 }
386                 else if (strncmp(text + 1, "FLAGS", 5) == 0)
387                 {
388                     parseflags(text + 7, m);
389                 }
390 
391                 break;
392 
393 	    case 'T':
394 		if (strncmp(text + 1, "TOPT", 4) == 0)
395                 {
396                     s = text + 5;
397                     m->to.point = atoi(s + 1);
398                 }
399                 else if (strncmp(text + 1, "TZUTC:", 6) == 0)
400                 {
401                     s = text + 7;
402 
403                     while (m_isspace(*s))
404                     {
405                         s++;
406                     }
407 
408                     m->timezone = (atoi(s) % 100) + ((atoi(s) / 100) * 60);
409                     m->has_timezone = 1;
410                 }
411                 break;
412 
413 	    case 'D':
414 		if (strncmp(text + 1, "DOMAIN", 6) != 0)
415 		{
416 		    break;
417 		}
418 
419 		s = text + 7;
420 		strcpy(tmp, s);
421 		memset(tokens, 0, sizeof(tokens));
422 		parse_tokens(tmp, tokens, 4);
423 
424 		if (!tokens[3])
425 		{
426 		    break;
427 		}
428 
429 		memset(&a, 0, sizeof a);
430 		a = parsenode(tokens[1]);
431 		if (a.fidonet)
432 		{
433 		    release(m->to.domain);
434 		    m->to = a;
435 		    m->to.domain = xstrdup(tokens[0]);
436 		}
437 		memset(&a, 0, sizeof a);
438 		a = parsenode(tokens[3]);
439 		if (a.fidonet)
440 		{
441 		    release(m->from.domain);
442 		    m->from = a;
443 		    m->from.domain = xstrdup(tokens[2]);
444 		}
445 		break;
446 
447 	    case 'I':
448 		fmpt = m->from.point; /* INTL kludge is not 4D */
449 		topt = m->to.point;
450 
451 		if (strncmp(text + 1, "INTL", 4) != 0)
452 		{
453 		    break;
454 		}
455 
456 		s = text + 5;
457 		strcpy(tmp, s + 1);
458 		memset(tokens, 0, sizeof(tokens));
459 		parse_tokens(tmp, tokens, 2);
460 
461 		if (!tokens[1])
462 		{
463 		    break;
464 		}
465 
466 		memset(&a, 0, sizeof a);
467 		a = parsenode(tokens[0]);
468 		if (a.fidonet)
469 		{
470 		    release(m->to.domain);
471 		    m->to = a;
472 		}
473 		memset(&a, 0, sizeof a);
474 		a = parsenode(tokens[1]);
475 		if (a.fidonet)
476 		{
477 		    release(m->from.domain);
478 		    m->from = a;
479 		}
480 
481 		m->to.point = topt;    /* restore the point numbers */
482 		m->from.point = fmpt;
483 
484 		break;
485 	    }
486 
487 	    if ((!SW->shownotes) && (!read_verbatim))
488 	    {
489 		release(text);
490 		continue;
491 	    }
492 	}
493 
494 	if (*text == 'S')
495 	{
496 	    if (strncmp(text, "SEEN-BY:", 8) == 0 &&
497 		!(SW->showseenbys || SW->shownotes || read_verbatim) &&
498 		(!gotsot || goteot))
499 	    {
500 		release(text);
501 		continue;
502 	    }
503 	}
504 
505 	if (goteot && *text == '\n' &&
506 	    !(SW->showseenbys || SW->shownotes || read_verbatim))
507 	{
508 	    release(text);
509 	    continue;
510 	}
511 
512 	/* from Roland Gautschi */
513 
514 	if (SW->tabexpand && strchr(text, '\t') != NULL)
515 	{
516 	    do
517 	    {
518 		ptmp = xstrdup(text);
519 		release(text);
520 
521 		text = xmalloc(strlen(ptmp) + SW->tabsize);
522 		t = strchr(ptmp, '\t');
523 
524 		/* characters before \t */
525 
526 		strncpy(text, ptmp, (size_t) (t - ptmp));
527 
528 		/* replace \t with spaces */
529 
530 		memset(text + (size_t) (t - ptmp), ' ', SW->tabsize);
531 
532 		/* copy the rest */
533 
534 		strcpy(text + (size_t) (t - ptmp) + SW->tabsize, t + 1);
535 		xfree(ptmp);
536 	    }
537 	    while (strchr(text, '\t') != NULL);
538 	}
539 
540 	if (CurArea.echomail)
541 	{
542 	    if (afound == 0 && strlen(text) > 10 && *(text + 1) == '*')
543 	    {
544 		if (!strncmp(text, " * Origin:", 10))
545 		{
546 		    /* probably the origin line */
547 
548 		    s = strrchr(text, '(');
549 		    if (s != NULL)
550 		    {
551 			while (*s && !m_isdigit(*s) && *s != ')')
552 			{
553 			    s++;
554 			}
555 
556 			if (m_isdigit(*s))
557 			{
558 			    m->from = parsenode(s);
559 			}
560 		    }
561 		    else
562 		    {
563 			m->from.notfound = 1;
564 		    }
565 		}
566 	    }
567 	}
568 
569 	if (strncmp(text, "---", 3) == 0 && strncmp(text, "----", 4) != 0 &&
570 	  !(SW->showtearlines || SW->shownotes || read_verbatim) &&
571 	    (!gotsot || goteot))
572 	{
573 	    release(text);
574 	    continue;
575 	}
576 
577 	if (strncmp(text, " * Origin:", 10) == 0 &&
578 	  !(SW->showorigins || SW->shownotes || read_verbatim) &&
579 	  (!gotsot || goteot))
580 	{
581 	    release(text);
582 	    continue;
583 	}
584 
585 	if ((CurArea.uucp || CurArea.news) && headerfin == 0)
586 	{
587 	    char *s;
588 
589 	    if (CurArea.uucp)
590 	    {
591 		if (strncmpi(text, "To: ", 4) == 0)
592 		{
593 		    char *cpdomain, *cpname;
594 
595 		    s = strchr(text, ' ') + 1;
596 		    parse_internet_address(s, &cpdomain, &cpname);
597 		    m->to.fidonet = 0;
598 		    m->to.internet = 0;
599 		    m->to.bangpath = 0;
600 		    m->to.notfound = 0;
601 		    if (strchr(cpdomain, '@') != NULL)
602 		    {
603 			m->to.internet = 1;
604 		    }
605 		    else
606 		    {
607 			m->to.bangpath = 1;
608 		    }
609 		    release(m->to.domain);
610 		    m->to.domain = cpdomain;
611 		    release (m->isto);
612 		    m->isto = cpname;
613 		    lastwasfromto = 1;
614 		    if (!(SW->shownotes || read_verbatim))
615 		    {
616 			release(text);
617 			continue;
618 		    }
619 		}
620 	    }
621 
622 	    if ( (strncmpi(text, "From: ", 6) == 0) ||
623 		 (strncmpi(text, "Reply-To: ", 10) == 0) )  /* TE 03/01/98 */
624 	    {
625 		char *cpname, *cpdomain;
626 
627 		s = strchr(text,' ') + 1;
628 
629 		parse_internet_address(s, &cpdomain, &cpname);
630 
631 		/* do not adopt a probably non-existent Reply-To User Name */
632 		if (strncmpi(text, "Reply-To: ", 10) != 0)
633 		{
634 		    release(m->isfrom);
635 		    m->isfrom = cpname;
636 		}
637 		m->from.fidonet = 0;
638 		m->from.internet = 0;
639 		m->from.bangpath = 0;
640 		m->from.notfound = 0;
641 		afound = 1;
642 		if (strchr(cpdomain, '@') != NULL)
643 		{
644 		    m->from.internet = 1;
645 		}
646 		else
647 		{
648 		    m->from.bangpath = 1;
649 		}
650 		release(m->from.domain);
651 		m->from.domain = cpdomain;
652 		lastwasfromto = 1;
653 		if (!(SW->shownotes || read_verbatim))
654 		{
655 		    release(text);
656 		    continue;
657 		}
658 	    }
659 	}
660 
661 	if (*text != '\01' || SW->shownotes || read_verbatim)
662 	{
663 	    if (l == NULL)
664 	    {
665 		l = xcalloc(1, sizeof(LINE));
666 		m->text = l;
667 		l->next = l->prev = NULL;
668 	    }
669 	    else
670 	    {
671 		l->next = xcalloc(1, sizeof(LINE));
672 		if (l->next == NULL)
673 		{
674 		    xfree(text);
675 		    break;
676 		}
677 		l->next->next = NULL;
678 		l->next->prev = l;
679 		l = l->next;
680 	    }
681 
682 	    l->block = 0;
683 	    if (!read_verbatim)
684 	    {
685 		/* character set translation: import to local  charset */
686 		l->text = translate_text(text, ltable);
687 		strip_control_chars(l->text);
688 	    }
689 	    else
690 	    {
691 		l->text = xstrdup(text);
692 	    }
693 	    release(text); text = l->text;
694 	    l->hide = (*text == '\01');
695 
696 	    if (is_quote(text))
697 	    {
698 		l->quote = 1;
699 	    }
700 	    else
701 	    {
702 		l->quote = 0;
703 	    }
704 
705 	    if (l->quote)
706 	    {
707 		if (strlen(l->text) > maxx)
708 		{
709 		    wrap(l, 1, maxy, maxx);
710 		    while (l->next)
711 		    {
712 			l = l->next;
713 		    }
714 		}
715 	    }
716 	    else
717 	    {
718 		if (*text != '\01' && *text != '\n' && strlen(text) > maxx)
719 		{
720 		    wrap(l, 1, maxy, maxx);
721 		    while (l->next)
722 		    {
723 			l = l->next;
724 		    }
725 		}
726 	    }
727 	}
728 	else
729 	{
730 	    release(text);
731 	}
732     }
733 
734     MsgClose();
735 
736     if (!read_verbatim) /* recode the header, important for Russian users */
737     {
738         char *tmp;
739 
740         tmp = translate_text(m->isfrom, ltable);
741         release(m->isfrom); m->isfrom = tmp;
742         strip_control_chars(m->isfrom);
743 
744         tmp = translate_text(m->isto, ltable);
745         release(m->isto); m->isto = tmp;
746         strip_control_chars(m->isto);
747 
748         tmp = translate_text(m->subj, ltable);
749         release(m->subj); m->subj = tmp;
750         strip_control_chars(m->subj);
751     }
752 
753     if (set_rcvd)
754     {
755 	checkrcvd(m, n);
756     }
757     read_verbatim = 0;
758     return m;
759 }
760 
761 /*
762  *  checkrcvd(); Checks to see if a message has been recieved. If so,
763  *  reads the message header again (avoiding translations done in the
764  *  original readinf process) and then writes the header to the message
765  *  base.
766  */
767 
checkrcvd(msg * m,unsigned long n)768 void checkrcvd(msg * m, unsigned long n)
769 {
770     msg *mn;
771     int set_received = 0, j;
772 
773     if (m->attrib.rcvd)
774     {
775 	return;
776     }
777 
778     m->times_read++;
779 
780     if (is_sameaddr(&m->to))
781     {
782         if (SW->receiveallnames)
783         {
784             for (j = 0; j < MAXUSERS && (!set_received); j++)
785             {
786                 if (user_list[j].name != NULL &&
787                     stricmp(user_list[j].name, m->isto) == 0)
788                 {
789                     set_received = 1;
790                 }
791             }
792         }
793         else
794         {
795             if (stricmp(ST->username, m->isto) == 0)
796             {
797                 set_received = 1;
798             }
799         }
800     }
801 
802     if (set_received)
803     {
804 	mn = MsgReadHeader(n, RD_HEADER);
805 	if (mn == NULL)
806 	{
807 	    return;
808 	}
809 	mn->attrib.rcvd = 1;
810 	m->attrib.rcvd = 1;
811 	m->newrcvd = 1;
812 	mn->times_read++;
813 	MsgWriteHeader(mn, WR_HEADER);
814 	dispose(mn);
815     }
816 }
817 
is_sameaddr(FIDO_ADDRESS * msg)818 static int is_sameaddr(FIDO_ADDRESS * msg)
819 {
820     int j;
821 
822     if (!CurArea.netmail)
823     {
824 	/* we only care about the address in netmail areas */
825 	return 1;
826     }
827 
828     if (!SW->receivealladdr)
829     {
830         if (msg->zone != CurArea.addr.zone ||
831             msg->net != CurArea.addr.net   ||
832             msg->node != CurArea.addr.node ||
833             msg->point != CurArea.addr.point)
834         {
835             return 0;
836         }
837         return 1;
838     }
839     else
840     {
841         for (j = 0; j < SW->aliascount; j++)
842         {
843             if (alias[j].zone  == msg->zone  &&
844                 alias[j].net   == msg->net   &&
845                 alias[j].node  == msg->node  &&
846                 alias[j].point == msg->point)
847             {
848                 return 1;
849             }
850         }
851         return 0;
852     }
853 }
854 
855 /*
856  *  Clears a message only - wipes the slate clean.
857  */
858 
clearmsg(msg * m)859 void clearmsg(msg * m)
860 {
861     if (m == NULL)
862     {
863 	return;
864     }
865 
866     /* kill the header stuff */
867 
868     release(m->reply);
869     release(m->msgid);
870     release(m->isfrom);
871     release(m->isto);
872     release(m->subj);
873     release(m->to.domain);
874     release(m->from.domain);
875     release(m->replyarea);
876     release(m->charset_name);
877 
878     if (m->text)
879     {
880 	/* kill the text */
881 	m->text = clearbuffer(m->text);
882     }
883 
884     /* clear the whole lot */
885     memset(m, 0, sizeof *m);
886 
887     /* set the defaults */
888     m->attrib.priv = CurArea.priv;
889     m->attrib.crash = CurArea.crash;
890     m->attrib.hold = CurArea.hold;
891     m->attrib.direct = CurArea.direct;
892     m->attrib.killsent = CurArea.killsent;
893     m->attrib.local = 1;
894 }
895 
setcwd(char * path)896 int setcwd(char *path)
897 {
898     char *p;
899 
900     p = strchr(path, ':');
901     if (p == NULL)
902     {
903 	p = path;
904     }
905 
906     if (*p == ':')
907     {
908 	p++;
909 #if defined(OS2)
910 	setDefaultDisk((unsigned short)(toupper(*path) - 'A' + 1));
911 #elif defined(MSDOS) && !defined(__FLAT__)
912 	bdos(14, toupper(*path) - 'A', 0);
913 #elif defined(__FLAT__) && defined(MSDOS)
914 	{
915 	    unsigned dummy;
916 	    _dos_setdrive(toupper(*path) - 'A' + 1, &dummy);
917 	}
918 #endif
919     }
920 
921     return changeDir(p);
922 }
923 
isleap(int year)924 int isleap(int year)
925 {
926     return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
927 }
928 
unixtime(const struct tm * tm)929 unsigned long unixtime(const struct tm *tm)
930 {
931     int year, i;
932     unsigned long result;
933 
934     result = 0UL;
935     year = tm->tm_year + 1900;
936 
937     /* traverse through each year */
938 
939     for (i = 1970; i < year; i++)
940     {
941 	result += 31536000UL;  /* 60s * 60m * 24h * 365d = 31536000s */
942 	if (isleap(i))
943 	{
944 	    /* it was a leap year; add a day's worth of seconds */
945 	    result += 86400UL;  /* 60s * 60m * 24h = 86400s */
946 	}
947     }
948 
949     /*
950      *  Traverse through each day of the year, adding a day's worth
951      *  of seconds each time.
952      */
953 
954     for (i = 0; i < tm->tm_yday; i++)
955     {
956 	result += 86400UL;  /* 60s * 60m * 24h = 86400s */
957     }
958 
959     /* now add the number of seconds remaining */
960 
961     result += 3600UL * tm->tm_hour;
962     result += 60UL * tm->tm_min;
963     result += (unsigned long) tm->tm_sec;
964 
965     return result;
966 }
967 
sec_time(void)968 unsigned long sec_time(void)
969 {
970     time_t now;
971     struct tm *tm;
972     now = time(NULL);
973     tm = localtime(&now);
974     return unixtime(tm);
975 }
976 
977 /*
978  *  Inserts a line after the passed line and returns a pointer to it.
979  */
980 
InsertAfter(LINE * l,char * text)981 LINE *InsertAfter(LINE * l, char *text)
982 {
983     LINE *nl;
984 
985     nl = xcalloc(1, sizeof(LINE));
986     nl->text = xstrdup(text);
987 
988     if (l == NULL)
989     {
990 	return nl;
991     }
992 
993     nl->next = l->next;
994     nl->prev = l;
995     l->next = nl;
996     if (nl->next)
997     {
998 	nl->next->prev = nl;
999     }
1000 
1001     return nl;
1002 }
1003 
1004 
1005 /* Translate a token for the origin line */
1006 
trans_token(char * line,int maxlen,msg * m)1007 static void trans_token(char *line, int maxlen, msg *m)
1008 {
1009 
1010     char *old, *cp, *cp2, *atm;
1011     int linelen = 0, digits;
1012     struct tm tm;
1013     long count = -1, quote_count = -1, temp;
1014 
1015     if (line == NULL || maxlen < 1)
1016     {
1017 	return;
1018     }
1019 
1020     cp2 = cp = old = xstrdup(line);
1021     *line = 0;
1022 
1023     while (cp != NULL && maxlen - 1 > linelen)
1024     {
1025 	cp = strchr(cp2, '@');
1026 	if (cp != NULL)
1027 	{
1028 	    *cp = '\0';
1029 	}
1030 	linelen += sprintf(line + linelen, "%-.*s",
1031 			   maxlen - 1 - linelen, cp2);
1032 	if (cp == NULL)
1033 	{
1034 	    break;
1035 	}
1036 	cp++;
1037 	switch (toupper(*cp))
1038 	{
1039 	case '@':                      /* escaped @ character */
1040 	    strcat(line + (linelen), "@");
1041 	    linelen++;
1042 	    break;
1043 	case 'N':                      /* insert full name */
1044 	    if (m->isto != NULL)
1045 	    {
1046 		linelen += sprintf(line + linelen, "%-.*s",
1047 				   maxlen - 1 - linelen,
1048 				   m->isto);
1049 	    }
1050 	    break;
1051 	case 'A':                      /* insert reply area name */
1052 	    linelen += sprintf(line + linelen, "%-.*s",
1053 			       maxlen - 1 - linelen,
1054 			       CurArea.tag);
1055 	    break;
1056 	case 'S':                      /* insert subject */
1057 	    if (m->subj != NULL)
1058 	    {
1059 		linelen += sprintf(line + linelen, "%-.*s",
1060 				   maxlen - 1 - linelen,
1061 				   m->subj);
1062 	    }
1063 	    break;
1064 	case 'Y':                      /* insert user's full name */
1065 	    linelen += sprintf(line + linelen, "%-.*s",
1066 			       maxlen - 1 - linelen,
1067 			       m->isfrom);
1068 	    break;
1069 	case 'I':                      /* insert message size */
1070 	    if (count == -1)
1071 	    {
1072 		count_bytes(m->text, &count, &quote_count);
1073 	    }
1074 	    for (digits = 0, temp = count; temp !=0; digits++)
1075 	    {
1076 		temp = temp / 10;
1077 	    }
1078 	    if (!digits)
1079 	    {
1080 		digits++;
1081 	    }
1082 	    if (maxlen - 1 - linelen >= digits)
1083 	    {
1084 		linelen += sprintf(line + linelen, "%ld", count);
1085 	    }
1086 	    else
1087 	    {
1088 		linelen = maxlen;
1089 	    }
1090 	    break;
1091 
1092 	case 'Q':                      /* in sert quote % */
1093 	    if (count == -1)
1094 	    {
1095 		count_bytes(m->text, &count, &quote_count);
1096 	    }
1097 	    if (maxlen - 1 - linelen >= ((quote_count == count) ? 4 : 3))
1098 	    {
1099 		linelen += sprintf(line + linelen, "%02ld%%",
1100 				   quote_count * 100 / count);
1101 	    }
1102 	    else
1103 	    {
1104 		linelen = maxlen;
1105 	    }
1106 	    break;
1107 	case 'D':                      /* insert date */
1108 	    tm = *localtime(&m->timestamp);
1109 	    switch (toupper(*(++cp)))
1110 	    {
1111 	    case 'D':                /* day */
1112 		if (maxlen - 1 - linelen >= 2)
1113 		{
1114 		    linelen += sprintf(line + linelen, "%2.2d",
1115 				       tm.tm_mday);
1116 		}
1117 		else
1118 		{
1119 		    linelen = maxlen;
1120 		}
1121 		break;
1122 	    case 'W':                /* week day (mon, tue, ...) */
1123 		if (maxlen - 1 - linelen >= 3)
1124 		{
1125 		    atm = atime(m->timestamp);
1126 		    linelen += sprintf(line + linelen, "%3.3s", atm);
1127 		}
1128 		else
1129 		{
1130 		    linelen = maxlen;
1131 		}
1132 		break;
1133 	    case 'M':                /* month (jan, feb, .....) */
1134 		if (maxlen - 1 - linelen >= 3)
1135 		{
1136 		    atm = atime(m->timestamp);
1137 		    linelen += sprintf(line + linelen, "%3.3s",
1138 				       atm + 4);
1139 		}
1140 		else
1141 		{
1142 		    linelen = maxlen;
1143 		}
1144 		break;
1145 	    case 'Y':                /* two digit year */
1146 		if (maxlen - 1 - linelen >= 2)
1147 		{
1148 		    linelen += sprintf(line + linelen, "%2.2d",
1149 				       tm.tm_year % 100);
1150 		}
1151 		else
1152 		{
1153 		    linelen = maxlen;
1154 		}
1155 		break;
1156 	    case 'C':                /* century: 1900 - 1999: 20, etc. */
1157 		if (maxlen - 1 - linelen >= 2)
1158 		{
1159 		    linelen += sprintf(line + linelen, "%2.2d",
1160 				       (tm.tm_year / 100) + 20);
1161 		}
1162 		else
1163 		{
1164 		    linelen = maxlen;
1165 		}
1166 		break;
1167 	    case '4':                /* four digit year */
1168 		if (maxlen - 1 - linelen >= 4)
1169 		{
1170 		    linelen += sprintf(line + linelen, "%4.4d",
1171 				       tm.tm_year + 1900);
1172 		}
1173 		else
1174 		{
1175 		    linelen = maxlen;
1176 		}
1177 		break;
1178 	    default:                 /* date in format DD Mon YY */
1179 		cp--;
1180 		if (maxlen - 1 - linelen >= 9)
1181 		{
1182 		    linelen += sprintf(line + linelen, "%-9.9s",
1183 				       mtime(m->timestamp));
1184 		}
1185 		else
1186 		{
1187 		    linelen = maxlen;
1188 		}
1189 		break;
1190 	    }
1191 	    break;
1192 	case 'T':                      /* insert time hh:mm:ss */
1193 	    if (maxlen - 1 - linelen >= 8)
1194 	    {
1195 		tm = *localtime(&m->timestamp);
1196 		linelen += sprintf(line + linelen, "%2.2d:%2.2d:%2.2d",
1197 				   tm.tm_hour, tm.tm_min, tm.tm_sec);
1198 	    }
1199 	    else
1200 	    {
1201 		linelen = maxlen;
1202 	    }
1203 	    break;
1204 	case 'F':    /* First Name in TO: Field of new message */
1205 	    linelen += sprintf(line + linelen, "%-.*s",
1206 			       maxlen - linelen - 1, firstname(m->isto));
1207 	    break;
1208 	case 'L':     /* Last Name in TO: Field of new message */
1209 	    linelen += sprintf(line + linelen, "%-.*s",
1210 			       maxlen - linelen - 1, lastname(m->isto));
1211 	    break;
1212 	}                                  /* end switch */
1213 	cp2 = ++cp;
1214     }                                      /* end while */
1215     xfree(old);
1216 }
1217 
1218 
1219 /*
1220  *  Gets the origin line to use.
1221  */
1222 
GetFastEchoOrigin(int board)1223 static char *GetFastEchoOrigin(int board)
1224 {
1225     FILE *fp;
1226     CONFIG feconfig;
1227     Area fearea;
1228     ExtensionHeader feexthdr;
1229     static OriginLines feorigin;
1230     int cnt, found;
1231 
1232     fp = fopen(ST->fecfgpath, "rb");
1233     if (fp == NULL)
1234     {
1235 	return NULL;
1236     }
1237 
1238     if (fread(&feconfig, sizeof feconfig, 1, fp) != 1)
1239     {
1240 	return NULL;
1241     }
1242 
1243     fseek(fp, sizeof feconfig + feconfig.offset + feconfig.NodeCnt *
1244       feconfig.NodeRecSize, SEEK_SET);
1245 
1246     do
1247     {
1248 	if (fread(&fearea, sizeof fearea, 1, fp) != 1)
1249 	{
1250 	    return NULL;
1251 	}
1252     }
1253     while (board != fearea.board);
1254 
1255     cnt = 0;
1256     found = 0;
1257 
1258     fseek(fp, sizeof feconfig, SEEK_SET);
1259     while (!found)
1260     {
1261 	fread(&feexthdr, sizeof feexthdr, 1, fp);
1262 	if (feexthdr.type == EH_ORIGINS)
1263 	{
1264 	    do
1265 	    {
1266 		if (fread(&feorigin, sizeof feorigin, 1, fp) != 1)
1267 		{
1268 		    return NULL;
1269 		}
1270 		cnt++;
1271 	    }
1272 	    while (cnt <= (fearea.flags.origin));
1273 	    found = 1;
1274 	}
1275 	else
1276 	{
1277 	    fseek(fp, feexthdr.offset, SEEK_CUR);
1278 	}
1279     }
1280 
1281     fclose(fp);
1282 
1283     if (feorigin.line && *feorigin.line != '\0')
1284     {
1285 	return feorigin.line;
1286     }
1287     else
1288     {
1289 	return NULL;
1290     }
1291 }
1292 
GetOrigin(char * origin)1293 void GetOrigin(char *origin)
1294 {
1295     FILE *fp;
1296     char path[255];
1297 
1298     if (n_origins > 1)          /* origin shuffling */
1299     {
1300 	release(ST->origin);
1301 	ST->origin = xstrdup(origins[rand_number(n_origins)]);
1302     }
1303 
1304     if (!SW->override)
1305     {
1306 	if (CurArea.msgtype == SQUISH)
1307 	{
1308 	    sprintf(path, "%s.sqo", CurArea.path);
1309 	}
1310 	else
1311 	{
1312 	    sprintf(path, "%s\\origin", CurArea.path);
1313 	}
1314 
1315 	fp = fopen(path, "r");
1316 	if (fp != NULL)
1317 	{
1318 	    int i, orgnum, orgcnt;
1319 
1320 	    i = 0;
1321 	    orgnum = 0;
1322 	    orgcnt = 0;
1323 
1324 	    do
1325 	    {
1326 		*origin = '\0';
1327 		fgets(origin, 65, fp);
1328 		if (*origin)
1329 		{
1330 		    orgcnt++;
1331 		}
1332 	    }
1333 	    while (!feof(fp));
1334 
1335 	    orgnum = rand_number(orgcnt) + 1;
1336 
1337 	    rewind(fp);
1338 
1339 	    do
1340 	    {
1341 		*origin = '\0';
1342 		fgets(origin, 65, fp);
1343 		if (*origin)
1344 		{
1345 		    i++;
1346 		}
1347 		if (i == orgnum)
1348 		{
1349 		    break;
1350 		}
1351 	    }
1352 	    while (!feof(fp));
1353 
1354 	    fclose(fp);
1355 	}
1356 	else
1357 	{
1358 	    if (ST->origin != NULL)
1359 	    {
1360 		sprintf(origin, "%s", ST->origin);
1361 	    }
1362 	    else
1363 	    {
1364 		sprintf(origin, "%s", ST->username);
1365 	    }
1366 	    if (CurArea.msgtype == QUICK && areas_type == FASTECHO)
1367 	    {
1368 		char *feorigin;
1369 		feorigin = GetFastEchoOrigin(CurArea.board);
1370 		if (feorigin != NULL)
1371 		{
1372 		    sprintf(origin, "%s", feorigin);
1373 		}
1374 	    }
1375 	}
1376     }
1377     else
1378     {
1379 	if (ST->origin != NULL)
1380 	{
1381 	    sprintf(origin, "%s", ST->origin);
1382 	}
1383 	else
1384 	{
1385 	    sprintf(origin, "%s", ST->username);
1386 	}
1387     }
1388     striptwhite(origin);
1389 }
1390 
InvalidateKludges(msg * m)1391 static void InvalidateKludges(msg * m)
1392 {
1393     LINE *line;
1394 
1395     line = m->text;
1396     while (line != NULL)
1397     {
1398 	char *p;
1399 	p = line->text;
1400 	if (p != NULL)
1401 	{
1402 	    if (*p == '\01')
1403 	    {
1404 		*p = '@';
1405 	    }
1406 	    else if (strstr(p, "SEEN-BY: ") == p)
1407 	    {
1408 		*(p + 4) = '+';
1409 	    }
1410 	    else if (strstr(p, "---\n") == p || strstr(p, "--- ") == p ||
1411 	      strstr(p, " * Origin: ") == p)
1412 	    {
1413 		*(p + 1) = '+';
1414 	    }
1415 	}
1416 	line = line->next;
1417     }
1418 }
1419 
StripKludges(msg * m,int * got_originline,char * origin,int * got_tearline,char * tearline)1420 static void StripKludges(msg * m, int *got_originline, char *origin,
1421 				  int *got_tearline,   char *tearline)
1422 {
1423     LINE *line;
1424     int got_origin, got_tear, got_text;
1425 
1426     /* traverse forwards through linked list until the end */
1427 
1428     line = m->text;
1429     while (line->next != NULL)
1430     {
1431 	line = line->next;
1432     }
1433 
1434     /* now go backwards, removing any unwanted stuff */
1435 
1436     got_origin = 0;
1437     got_tear = 0;
1438     got_text = 0;
1439 
1440     while (line != NULL)
1441     {
1442 	char *p;
1443 
1444 	p = line->text;
1445 	if (p != NULL)
1446 	{
1447 	    if (strstr(p, "\01MSGID: ") == p || strstr(p, "\01REPLY: ") == p ||
1448 	      strstr(p, "\01FLAGS ") == p || strstr(p, "\01PID: ") == p ||
1449 	      strstr(p, "\01SOT:") == p || strstr(p, "\01EOT:") == p ||
1450 	      strstr(p, "\01CHRS: ") == p || strstr(p, "\01TZUTC:") == p ||
1451               strstr(p, "\01CODEPAGE:") == p)
1452 	    {
1453 		*p = '\0';
1454 	    }
1455 	    else if (CurArea.netmail)
1456 	    {
1457 		if (strstr(p, "\01INTL ") == p || strstr(p, "\01TOPT ") == p ||
1458 		  strstr(p, "\01FMPT ") == p || strstr(p, "\01DOMAIN ") == p ||
1459 		  strstr(p, "\01Via ") == p)
1460 		{
1461 		    *p = '\0';
1462 		}
1463 	    }
1464 	    else if (!CurArea.netmail)
1465 	    {
1466 		if (strstr(p, "SEEN-BY: ") == p || strstr(p, "\01PATH: ") == p)
1467 		{
1468 		    *p = '\0';
1469 		}
1470 		else if (!got_text && !got_origin && strstr(p, " * Origin: ") == p)
1471 		{
1472 		    *p = '\0';
1473 		    got_origin = 1;
1474 
1475 		    if (origin != NULL)  /* preserve an user-edited origin */
1476 		    {
1477 			strncpy (origin, p + 11, 79);
1478 			origin[79] = 0;
1479 			p = strrchr(origin, '(');
1480 			if (p != NULL)
1481 			{
1482 			    *p = '\0';
1483 			}
1484 			striptwhite(origin);
1485 		    }
1486 		}
1487 		else if (!got_text && !got_tear && (strstr(p, "---\n") == p ||
1488 		  strstr(p, "--- ") == p))
1489 		{
1490 		    /* preserve an user-edited tearline */
1491 		    if (tearline != NULL)
1492 		    {
1493 			strncpy (tearline, p+4, SW->xxltearline ? 75 : 31);
1494 			tearline[SW->xxltearline ? 75 : 31] = 0;
1495 			striptwhite (tearline);
1496 		    }
1497 		    *p = '\0';
1498 		    got_tear = 1;
1499 		}
1500 		else if (!got_text && (*p == '\n' || *p == '\r'))
1501 		{
1502 		    *p = '\0';
1503 		}
1504 		else if (!got_text && *p != '\0' && *p != '\n' && *p != '\r')
1505 		{
1506 		    got_text = 1;
1507 		}
1508 	    }
1509 	}
1510 
1511 	line = line->prev;
1512     }
1513 
1514     *got_originline = got_origin;
1515     *got_tearline   = got_tear;
1516 }
1517 
space_after_period(LINE * ln)1518 char *space_after_period(LINE *ln)
1519 {
1520     int snt_count, spc_count;
1521     snt_count = 0;
1522     spc_count = 0;
1523     while (ln != NULL)
1524     {
1525 	char *p;
1526 	p = ln->text;
1527 	while (*p != '\0')
1528 	{
1529 	    if (*p == '.' && *(p + 1) == ' ')
1530 	    {
1531 		snt_count++;
1532 		spc_count++;
1533 		if (*(p + 2) == ' ')
1534 		{
1535 		    spc_count++;
1536 		}
1537 	    }
1538 	    p++;
1539 	}
1540 	ln = ln->prev;
1541     }
1542     if (snt_count != 0 && spc_count / snt_count == 2)
1543     {
1544 	return "  ";
1545     }
1546     else
1547     {
1548 	return " ";
1549     }
1550 }
1551 
askgate(char * which)1552 static int askgate(char *which)
1553 {
1554     char str[80];
1555     int rc;
1556 
1557     sprintf(str, "Send this message via %s gate?", which);
1558 
1559     while (1)
1560     {
1561         rc = ChoiceBox("", str, "Yes", "No",
1562                        strcmp(which, "zone") ? NULL : "Help");
1563 
1564         switch(rc)
1565         {
1566         case ID_ONE:
1567             return 1;
1568         case ID_TWO:
1569             return 0;
1570         case ID_THREE:
1571             if (!strcmp(which, "zone"))
1572             {
1573                 DoHelp(6);
1574             }
1575             break;
1576         }
1577     }
1578 }
1579 
1580 
1581 /*
1582  *  Sequence of events:
1583  *
1584  *  Original address is saved (what is displayed);
1585  *  Domain gates are checked for and address is modified if one found;
1586  *  if no domain gates, search for UUCP gate && mod address if found.
1587  *  check INTL
1588  *  check MSGID
1589  *  check REPLY
1590  *  do PID if one,
1591  *  If we found domain gate, do DOMAIN with original saved addresses.
1592  *  if we found UUCP, then do a "to:" kludge.
1593  */
1594 
1595 /*
1596  *  Writes a message to disk.
1597  */
1598 
writemsg(msg * m)1599 int writemsg(msg * m)
1600 {
1601     LINE *curr, *l, *ufrom, *uto, *ureplyto, *xblank,
1602          *xtear, *xorigin, *ublank;
1603     FIDO_ADDRESS to;
1604     FIDO_ADDRESS from;
1605     unsigned long n;            /* UMSGID msgnum */
1606     unsigned long length;       /* length in bytes of the message */
1607     char text[255];             /* buffer useage */
1608     char origin[255];           /* out origin line */
1609     char tearline[76];          /* user-defined output tearline */
1610     char *uucp_from;            /* saved UUCP from address */
1611     char *uucp_to;              /* saved UUCP to address */
1612     int domain_gated, uucp_gated;
1613     int do_zonegate = 0;
1614     char *s;
1615     int i, abortWrite, got_origin, got_tear, ctrl;
1616     static unsigned long now = 0L;
1617     LOOKUPTABLE *ltable = NULL;
1618     int write_chrs_kludge;
1619     const int tear_max = SW->xxltearline ? 79 : 35;
1620 
1621     char *temptext;
1622 
1623     domain_gated = 0;
1624     uucp_gated = 0;
1625     length = 0;
1626     ctrl = 1;
1627     n = m->msgnum;
1628     curr = NULL;
1629     uto = NULL;
1630     ureplyto = NULL;
1631     ufrom = NULL;
1632     uucp_from = NULL;
1633     uucp_to = NULL;
1634     xorigin = NULL;
1635     xtear = NULL;
1636     xblank = NULL;
1637     ublank = NULL;
1638 #if 0
1639     while (MsgLockArea() == -1)          /* Lock the Msg area for writing */
1640     {
1641 	int ret;
1642 
1643 	ret = ChoiceBox(" Error! ", "Could not write message!",
1644 			"Retry", "Cancel", NULL);
1645 
1646 	if (ret == ID_TWO)
1647 	{
1648 	    return FALSE;
1649 	}
1650     }
1651 #endif
1652     if (now == 0L)
1653     {
1654 	now = sec_time();
1655     }
1656 
1657     if (m->invkludges)
1658     {
1659 	InvalidateKludges(m);
1660 	got_origin = got_tear = 0;
1661     }
1662     else if (!m->rawcopy)
1663     {
1664 	StripKludges(m, &got_origin, origin, &got_tear, tearline);
1665     }
1666 
1667     ltable = get_writetable(CurArea.eightbits ? ST->output_charset : "ASCII",
1668 	       &write_chrs_kludge);
1669 
1670     if (!m->rawcopy)
1671     {
1672 	/* save the original address */
1673 
1674 	to = m->to;
1675 	from = m->from;
1676 
1677 	/* do domain gating */
1678 
1679         if (SW->domains &&
1680             m->to.domain &&
1681             m->from.domain &&
1682             stricmp(m->from.domain, m->to.domain) &&
1683             (SW->gate == GDOMAINS || SW->gate == BOTH ||
1684              (SW->gate == GASK && askgate("domain"))) &&
1685             !m->to.internet /* in this case, "domain" string is e-mail addr */
1686            )
1687 	{
1688 	    /*
1689 	     *  If we have two domains and they're different, then we want to
1690 	     *  gate. If we have a to: domain and no from: domain, then we
1691 	     *  still may want to gate.  If we don't have a to: domain, then
1692 	     *  we don't want to gate the message (we assume it's destined to
1693 	     *  our own network).
1694 	     */
1695 
1696             for (i = 0; i < SW->domains; i++)
1697             {
1698                 if (!stricmp(domain_list[i].domain, m->to.domain))
1699                 {
1700                     domain_gated = 1;
1701 
1702                     if (m->attrib.crash || m->attrib.direct ||
1703                         m->attrib.hold  || m->attrib.immediate)
1704                     {
1705                         int ret;
1706 
1707                         ret = ChoiceBox(" Direct Message ",
1708                                         " Direct Message "
1709                                         "(crash, dir, imm or hold) to?",
1710                                         "Domain Gate", "Destination Node", NULL);
1711 
1712                         if (ret == ID_ONE)
1713                         {
1714                             m->to = domain_list[i];
1715                             if (domain_list[i].domain)
1716                             {
1717                                 m->to.domain = xstrdup(domain_list[i].domain);
1718                             }
1719                         }
1720                     }
1721                     else
1722                     {
1723                         m->to = domain_list[i];
1724                         if (domain_list[i].domain)
1725                         {
1726                             m->to.domain = xstrdup(domain_list[i].domain);
1727                         }
1728                     }
1729                     break;
1730                 }
1731             }
1732         }
1733 
1734 
1735 	/* do uucp gating */
1736 
1737 	if (m->to.internet || m->to.bangpath)
1738 	{
1739 	    uucp_gated = 1;
1740 	    uucp_to = m->to.domain;
1741 	    if (!CurArea.echomail)              /* don't change adresses */
1742 	    {                                   /* in echomail areas     */
1743 		m->to = uucp_gate;
1744 	    }
1745 	    if (uucp_gate.domain)
1746 	    {
1747 		m->to.domain = xstrdup(uucp_gate.domain);
1748 	    }
1749 
1750             if (CurArea.netmail)
1751             {
1752                 /* AKA-Matching for UUCP gated messages */
1753                 akamatch(&(m->from), &(m->to));
1754             }
1755 	}
1756 
1757 	if (m->from.internet || m->from.bangpath)
1758 	{
1759 	    uucp_gated = 1;
1760 	    uucp_from = xstrdup(m->from.domain);
1761 	    if (!CurArea.echomail)              /* don't change adresses */
1762 	    {                                   /* in echomail areas     */
1763 		m->from = uucp_gate;
1764 	    }
1765 	    if (uucp_gate.domain)
1766 	    {
1767 		m->from.domain = xstrdup(uucp_gate.domain);
1768 	    }
1769 	}
1770 
1771 	/* do the netmail stuff */
1772 
1773 	    /* uccp is an ADD ON flag for netmail, not a replacement,
1774 	       so I commented it out below, because it lead to INTL
1775 	       kludges in echomail areas and the like */
1776 	if (CurArea.netmail /* || CurArea.uucp */ )
1777 	{
1778 
1779             /* print INTL kludge */
1780  	    if (m->from.zone != m->to.zone || m->from.zone != thisnode.zone)
1781 	    {
1782 		sprintf(text, "\01INTL %d:%d/%d %d:%d/%d\r", m->to.zone,
1783 		  m->to.net, m->to.node, m->from.zone, m->from.net, m->from.node);
1784 		curr = InsertAfter(curr, text);
1785 	    }
1786 
1787             /* print FMPT / TOPT kludges */
1788 	    if (m->to.point)
1789 	    {
1790 		sprintf(text, "\01TOPT %d\r", m->to.point);
1791 		curr = InsertAfter(curr, text);
1792 	    }
1793 
1794             if (! (!m->attrib.direct && !m->attrib.crash && m->from.point &&
1795                    SW->pointnet != 0 && CurArea.netmail))
1796             {
1797                 /* privatenet / fakenet is not used */
1798                 if (m->from.point)
1799                 {
1800                     sprintf(text, "\01FMPT %d\r", m->from.point);
1801                     curr = InsertAfter(curr, text);
1802                 }
1803             }
1804 
1805             /* see if we want to zonegate and set the ZON flag if
1806                necessary. The actual readressing proceudre is done later. */
1807 
1808             if (m->from.zone != m->to.zone && !m->attrib.direct &&
1809                 !m->attrib.crash && CurArea.netmail &&
1810                 (SW->gate == GZONES || SW->gate == BOTH ||
1811                  m->attrib.zon ||
1812                  (SW->gate == GASK && askgate("zone"))
1813                 ))
1814             {
1815                 do_zonegate = 1;
1816                 m->attrib.zon = 1;
1817             }
1818 
1819         }
1820 
1821 	/* these babies go everywhere */
1822 
1823 	if (m->new)
1824 	{
1825 	    if (SW->msgids)
1826 	    {
1827 		sprintf(text, "\01MSGID: %s %08lx\r",
1828                         SW->domainmsgid ? show_address(&from) : show_4d(&from),
1829                         now);
1830 
1831 		now++;
1832 		curr = InsertAfter(curr, text);
1833 	    }
1834 	}
1835 	else
1836 	{
1837 	    if (m->msgid)
1838 	    {
1839 		sprintf(text, "\01MSGID: %s\r", m->msgid);
1840 		curr = InsertAfter(curr, text);
1841 	    }
1842 	}
1843 
1844         if (m->has_timezone)
1845         {
1846             sprintf(text, "\01TZUTC: %.4li\r",
1847                     (long)(((m->timezone / 60) * 100) + (m->timezone % 60)));
1848             curr = InsertAfter(curr, text);
1849         }
1850 
1851 	if (m->reply && (!m->new || SW->msgids))
1852 	{
1853 	    sprintf(text, "\01REPLY: %s\r", m->reply);
1854 	    curr = InsertAfter(curr, text);
1855 	}
1856 
1857 	if ((SW->echoflags && CurArea.echomail) || (CurArea.netmail))
1858 	{
1859 	    char flags[255];
1860 
1861             printflags(flags, m, CurArea.msgtype, CurArea.echomail);
1862 
1863             if (*flags)
1864             {
1865                 sprintf(text, "\01FLAGS %s\r", flags);
1866                 curr = InsertAfter(curr, text);
1867             }
1868 	}
1869 
1870 	if (!SW->usetearlines || SW->usepid || CurArea.netmail)
1871 	{
1872 	    sprintf(text, "\01PID: %s %s\r", PROG, VERNUM VERPATCH);
1873 	    curr = InsertAfter(curr, text);
1874 	}
1875 
1876 	if (CurArea.eightbits && write_chrs_kludge)
1877 	{
1878 	    sprintf(text, "\01CHRS: %s 2\r", ST->output_charset);
1879 	    curr = InsertAfter(curr, text);
1880             if (ST->output_charset[0] != 'C' || ST->output_charset[1] != 'P')
1881             {
1882                 int cp;
1883 
1884                 /* codepage of this kludge is non-obvious,
1885                    add CODEPAGE kludge */
1886 
1887                 cp = get_codepage_number(ST->output_charset);
1888                 if (cp != 0)
1889                 {
1890                     sprintf(text, "\01CODEPAGE: %d\r", cp);
1891                     curr = InsertAfter(curr, text);
1892                 }
1893             }
1894 	}
1895 
1896 
1897 	/* domain gating */
1898 
1899 	if (domain_gated)
1900 	{
1901 	    sprintf(text, "\01DOMAIN %s %d:%d/%d.%d %s %d:%d/%d.%d\r",
1902 	      to.domain, to.zone, to.net, to.node, to.point, from.domain,
1903 	      from.zone, from.net, from.node, from.point);
1904 	    curr = InsertAfter(curr, text);
1905 	}
1906 
1907 	if (SW->soteot)
1908 	{
1909 	    strcpy(text, "\01SOT:\r");
1910 	    curr = InsertAfter(curr, text);
1911 	}
1912 
1913 	if (uucp_gated)
1914 	{
1915 	    int cr = 0;  /* we want to insert a \n after header info */
1916 
1917 	    if (uucp_from)
1918 	    {
1919 		sprintf(text, "From: %s\r", uucp_from);
1920 		curr = InsertAfter(curr, text);
1921 		ufrom = curr;
1922 		cr = 1;
1923 	    }
1924 
1925 	    if (uucp_to)
1926 	    {
1927 		sprintf(text, "To: %s\r", uucp_to);
1928 		curr = InsertAfter(curr, text);
1929 		uto = curr;
1930 		cr = 1;
1931 
1932                 if (ST->uucpreplyto != NULL)
1933                 {
1934                     sprintf(text, "Reply-To: %s\r", ST->uucpreplyto);
1935                     curr = InsertAfter(curr, text);
1936                     ureplyto = curr;
1937                 }
1938 	    }
1939 
1940 	    if (cr == 1)
1941 	    {
1942 		strcpy(text, "\r");
1943 		curr = InsertAfter(curr, text);
1944 		ublank = curr;
1945 	    }
1946 	}
1947 
1948 	/*
1949 	 *  Actually assign the kludges we just created to the message body
1950 	 *  (before the text).
1951 	 */
1952 
1953 	if (curr != NULL)
1954 	{
1955 	    curr->next = m->text;
1956 	    if (m->text != NULL)
1957 	    {
1958 		m->text->prev = curr;
1959 	    }
1960 
1961 	    while (curr->prev != NULL)
1962 	    {
1963 		curr = curr->prev;
1964 	    }
1965 
1966 	    m->text = curr;
1967 	}
1968     }
1969 
1970     l = m->text;
1971     while (l)
1972     {
1973 	if (l->text == NULL)
1974 	{
1975 	    l->text = xstrdup("\r");
1976 	}
1977 
1978 	if (*l->text)
1979 	{
1980 	    s = strrchr(l->text, '\n');
1981 	    if (s != NULL)
1982 	    {
1983 		*s = '\r';
1984 	    }
1985 	    else
1986 	    {
1987 		char *text;
1988 
1989 		text = xmalloc(strlen(l->text) + 5);
1990 		strcpy(text, l->text);
1991 		if (l->quote)
1992 		{
1993 		    strcat(text, "\r");
1994 		}
1995 		else
1996 		{
1997 		    if ((l->next == NULL || *(l->next->text) == '\0') &&
1998 		      text[strlen(text) - 1] != '\r')
1999 		    {
2000 			strcat(text, "\r");
2001 		    }
2002 		    else if (l->next != NULL && *(l->next->text) == '\n' &&
2003 		      text[strlen(text) - 1] != '\r')
2004 		    {
2005 			strcat(text, "\r");
2006 		    }
2007 		    else if (!m_isspace(*(text + strlen(text) - 1)))
2008 		    {
2009 			if (*(text + strlen(text) - 1) == '.')
2010 			{
2011 			    strcat(text, space_after_period(l));
2012 			}
2013 			else
2014 			{
2015 			    strcat(text, " ");
2016 			}
2017 		    }
2018 		}
2019 		release(l->text);
2020 		l->text = text;
2021 	    }
2022 	}
2023 	l = l->next;
2024     }
2025 
2026     /* find the end of the message */
2027 
2028     curr = m->text;
2029     while (curr->next != NULL)
2030     {
2031 	curr = curr->next;
2032     }
2033 
2034     if (!m->rawcopy)
2035     {
2036 	if (SW->usetearlines && SW->useoriginlines &&
2037 	    *curr->text != '\r' && CurArea.echomail)
2038 	{
2039 	    strcpy(text, "\r");
2040 	    curr = InsertAfter(curr, text);
2041 	    xblank = curr;
2042 	}
2043 
2044 	if (SW->soteot)
2045 	{
2046 	    strcpy(text, "\01EOT:\r");
2047 	    curr = InsertAfter(curr, text);
2048 	}
2049 
2050 	if (CurArea.netmail && SW->netmailvia)
2051 	{
2052 	    time_t td;
2053 	    char time_str[80];
2054 
2055 	    td = time(NULL);
2056 	    strftime(time_str, 80, "%a %b %d %Y at %H:%M UTC", gmtime(&td));
2057 	    sprintf(text, "\01Via " PROG " " VERNUM VERPATCH " %s, %s\r",
2058 	      show_address(&from), time_str);
2059 	    curr = InsertAfter(curr, text);
2060 	}
2061 
2062 	if (CurArea.echomail)
2063 	{
2064 	    if (SW->usetearlines)
2065 	    {
2066 		/* add the tearline */
2067 
2068 		if (got_tear)  /* preserve user-defined tear line */
2069 		{
2070 		    sprintf(text, "--- %s\r", tearline);
2071 		}
2072                 else
2073                 {
2074                     make_tearline(text);
2075                     strcat(text, "\r");
2076 		}
2077 
2078 		/* make sure it is not longer than 35 characters + \r*/
2079 		if (strlen(text) > tear_max + 1) /* +1 for \r */
2080 		{
2081 		    text[tear_max + 1] = '\0';
2082 		    text[tear_max] = '\r';
2083 		}
2084 
2085 		curr = InsertAfter(curr, text);
2086 		xtear = curr;
2087 	    }
2088 
2089 	    if (SW->useoriginlines)
2090 	    {
2091 		/* add the origin line */
2092 
2093 		if (!got_origin)
2094 		{
2095 		    GetOrigin(origin);
2096 		}
2097 		trans_token(origin, 79, m);
2098 		sprintf(text, " * Origin: %s (%s)\r", origin,
2099 		  SW->domainorigin ? show_address(&from) : show_4d(&from));
2100 
2101 		/* make sure it is not longer than 79 characters + \r */
2102 		i = strlen(text) - 80;
2103 		if (i > 0)
2104 		{
2105 		    s = strstr(text, " (");
2106 		    *s = 0;
2107 		    if (i > strlen(text))  /* assure data integrity */
2108 		    {
2109 			i = strlen(text);
2110 		    }
2111 		    *s = ' ';
2112 		    memmove (s - i, s, strlen(s) + 1);
2113 		}
2114 
2115 		curr = InsertAfter(curr, text);
2116 		xorigin = curr;
2117 	    }
2118 	}
2119     }
2120 
2121     /* we've made the new message up, now return it's length */
2122 
2123     l = m->text;
2124     while (l)
2125     {
2126         if (*(l->text) != '\01')
2127 	{
2128 	    ctrl = 0;
2129 	}
2130 	if (!ctrl)
2131 	{
2132             temptext = translate_text(l->text, ltable);
2133             if (temptext != NULL)
2134                 length += strlen(temptext);
2135             release(temptext);
2136 	}
2137 	l = l->next;
2138     }
2139 
2140     length++; /* account for the \0 byte */
2141 
2142     if (!m->rawcopy)
2143     {
2144 	/* remap point originated crashmail */
2145 
2146         /* if you change this if condition, don't forget to change the same
2147            conditions some lines above in the generation of FMPT also! */
2148 	if (!m->attrib.direct && !m->attrib.crash && m->from.point &&
2149 	  SW->pointnet != 0 && CurArea.netmail)
2150 	{
2151 	    m->from.net = SW->pointnet;
2152 	    m->from.node = m->from.point;
2153 	    m->from.point = 0;
2154 	}
2155 
2156 	/* do any required zone gating */
2157         if (do_zonegate)
2158 	{
2159 	    m->to.node = m->to.zone;
2160 	    m->to.zone = m->from.zone;
2161 	    m->to.net = m->from.zone;
2162 	}
2163     }
2164 
2165     if (!m->rawcopy) /* recode the header, important for Russian users */
2166     {
2167         char *tmp;
2168 
2169         tmp = translate_text(m->isfrom, ltable);
2170         do_softcrxlat(tmp);
2171         release(m->isfrom); m->isfrom = tmp;
2172 
2173         tmp = translate_text(m->isto, ltable);
2174         do_softcrxlat(tmp);
2175         release(m->isto); m->isto = tmp;
2176 
2177         tmp = translate_text(m->subj, ltable);
2178         do_softcrxlat(tmp);
2179         release(m->subj); m->subj = tmp;
2180     }
2181 
2182     abortWrite = 0;
2183     while (MsgWriteHeader(m, WR_ALL) == ERR_OPEN_MSG && !abortWrite)
2184     {
2185 	int ret;
2186 
2187 	ret = ChoiceBox(" Error! ", "Could not write message!",
2188 	  "Retry", "Cancel", NULL);
2189 
2190 	if (ret == ID_TWO)
2191 	{
2192 	    abortWrite = 1;
2193 	}
2194     }
2195 
2196     if (!abortWrite)
2197     {
2198 	l = m->text;
2199 	while (l && !abortWrite)
2200 	{
2201 	    if (l->text && *l->text != '\0')
2202 	    {
2203 		if (!m->rawcopy)
2204 		{
2205 		    temptext = translate_text(l->text, ltable);
2206                     do_softcrxlat(temptext);
2207 		    /* output CHRS translation */
2208 		}
2209 		else
2210 		{
2211 		    temptext = xstrdup(l->text);
2212 		}
2213 		while ((!abortWrite) &&
2214 		       (MsgWriteText(temptext, n, length) == FALSE))
2215 		{
2216 		    int ret;
2217 
2218 		    ret = ChoiceBox(" Error! ", "Could not write message!",
2219 				    "Retry", "Cancel", NULL);
2220 		    if (ret == ID_TWO)
2221 		    {
2222 			abortWrite = 1;
2223 		    }
2224 		}
2225 
2226 		release(temptext);
2227 	    }
2228 
2229 	    /*
2230 	     *  The \r's have to be turned back into \n's because the
2231 	     *  message might be a CC: and so be needed again.
2232 	     */
2233 
2234 	    s = strrchr(l->text, '\r');
2235 	    if (s != NULL)
2236 	    {
2237 		*s = '\n';
2238 	    }
2239 
2240 	    l = l->next;
2241 	}
2242 
2243 	MsgWriteText(NULL, n, length);
2244 	MsgClose();
2245     }
2246 
2247     CurArea.new = 1;
2248     echotoss_add(&CurArea);
2249 
2250     /*
2251      *  Clean up. If this message is a CC, then we don't want this
2252      *  temporary information to remain.
2253      */
2254 
2255     if ((uucp_from || uucp_to) && (ublank != NULL))
2256     {
2257 	deleteCrapLine(ublank);
2258     }
2259 
2260     if (uucp_from)
2261     {
2262 	release(uucp_from);
2263 	deleteCrapLine(ufrom);
2264     }
2265 
2266     if (uucp_to)
2267     {
2268 	release(uucp_to);
2269 	deleteCrapLine(uto);
2270         if (ureplyto != NULL)
2271         {
2272             deleteCrapLine(ureplyto);
2273         }
2274     }
2275 
2276     deleteCrapLine(xblank);
2277     deleteCrapLine(xtear);
2278     deleteCrapLine(xorigin);
2279 
2280 #if 0
2281     MsgUnlockArea();
2282 #endif
2283 
2284     if (abortWrite)
2285     {
2286 	return FALSE;
2287     }
2288     else
2289     {
2290 	return TRUE;
2291     }
2292 }
2293 
deleteCrapLine(LINE * crap)2294 static void deleteCrapLine(LINE * crap)
2295 {
2296     if (crap != NULL)
2297     {
2298 	if (crap->prev != NULL)
2299 	{
2300 	    crap->prev->next = crap->next;
2301 	}
2302 	if (crap->next != NULL)
2303 	{
2304 	    crap->next->prev = crap->prev;
2305 	}
2306 	release(crap->text);
2307 	release(crap);
2308     }
2309 }
2310 
2311 #ifdef OS2
2312 
2313 #include <os2.h>
2314 
setDefaultDisk(unsigned short x)2315 static unsigned long setDefaultDisk(unsigned short x)
2316 {
2317 #ifdef OS216
2318     return DosSelectDisk(x);
2319 #else
2320     return DosSetDefaultDisk(x);
2321 #endif
2322 }
2323 
changeDir(char * path)2324 static int changeDir(char *path)
2325 {
2326 #ifdef OS216
2327     return chdir(path);
2328 #else
2329     return DosSetCurrentDir((PSZ) path);
2330 #endif
2331 }
2332 
mygetcwd(char * buf,int len)2333 void mygetcwd(char *buf, int len)
2334 {
2335 #ifdef OS216
2336     getcwd(buf, len);
2337 #else
2338     unsigned long ulen;
2339     ulen = len;
2340     DosQueryCurrentDir(0, (PSZ) buf, &ulen);
2341 #endif
2342 }
2343 
2344 #else
2345 
changeDir(char * path)2346 static int changeDir(char *path)
2347 {
2348     return chdir(path);
2349 }
2350 
mygetcwd(char * buf,int len)2351 void mygetcwd(char *buf, int len)
2352 {
2353 #ifndef PACIFIC
2354     getcwd(buf, len);
2355 #else
2356     getcwd(buf);
2357 #endif
2358 }
2359 
2360 #endif
2361