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, "e_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, "e_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