1 /*
2 * MAKEMSGN.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 * Routines to create new messages.
8 */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include "mctype.h"
15 #include <time.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18
19 #ifndef UNIX /* UNIX only uses system(), and that is in stdlib.h */
20 #include <process.h>
21 #endif
22
23 #ifdef MSDOS
24 #include <dos.h>
25 #ifdef PACIFIC
26 #include <sys.h>
27 #else
28 #endif
29 #endif
30
31 #include "addr.h"
32 #include "nedit.h"
33 #include "msged.h"
34 #include "winsys.h"
35 #include "menu.h"
36 #include "dialogs.h"
37 #include "memextra.h"
38 #include "nshow.h"
39 #include "areas.h"
40 #include "readmail.h"
41 #include "keys.h"
42 #include "template.h"
43 #include "main.h"
44 #include "wrap.h"
45 #include "screen.h"
46 #include "userlist.h"
47 #include "vsevops.h"
48 #include "dirute.h"
49 #include "makemsgn.h"
50 #include "strextra.h"
51 #include "group.h"
52 #include "timezone.h"
53
54 #ifdef MSDOS
55 #ifdef USE_CRITICAL
56 #include "critical.h"
57 #endif
58 #if !defined(NODOSSWAP) && !defined(__FLAT__)
59 #include "spawn.h"
60 #endif
61 #endif
62
63 #define TEXTLEN 128
64 #define INPLEN 60
65
66 /* prototypes */
67
68 static void reply_msg(int type);
69 static void crosspost(msg * m);
70 static int externalEditor(msg * m);
71
72 extern int savecc;
73
74 static msg *EdMsg; /* message header being edited */
75 static int scan_base; /* force a scan of the msgbase */
76 int do_lookup = FALSE; /* lookup thru the nodelist? */
77 static int editRet;
78
sent_msg(void)79 static int sent_msg(void)
80 {
81 int rc;
82 rc = ChoiceBox("", "WARNING: This message has already been sent! Continue?", "Yes", "No", NULL);
83 return rc == ID_ONE ? 1 : 0;
84 }
85
86 /*
87 * Creates a duplicate of the passed message header, allocating
88 * memory for it in the process.
89 */
90
91 #define copystr(d, s) { if (s) { d = xstrdup(s); } else { d = NULL; } }
92
duplicatemsg(msg * from)93 msg *duplicatemsg(msg * from)
94 {
95 msg *to;
96
97 to = xcalloc(1, sizeof *to);
98
99 *to = *from; /* copy all the bits */
100
101 copystr(to->isfrom, from->isfrom);
102 copystr(to->isto, from->isto);
103 copystr(to->subj, from->subj);
104 copystr(to->to.domain, from->to.domain);
105 copystr(to->from.domain, from->from.domain);
106 copystr(to->msgid, from->msgid);
107 copystr(to->reply, from->reply);
108 copystr(to->replyarea, from->replyarea);
109 copystr(to->charset_name, from->charset_name);
110
111 to->text = NULL;
112
113 return to;
114 }
115
newmsg(void)116 void newmsg(void)
117 {
118 reply_msg(MT_NEW);
119 }
120
reply(void)121 void reply(void)
122 {
123 reply_msg(MT_REP);
124 }
125
quote(void)126 void quote(void)
127 {
128 if (message && message->replyarea)
129 {
130 reply_msg(SW->rotharea);
131 }
132 else
133 {
134 reply_msg(SW->rquote);
135 }
136 }
137
reply_oarea(void)138 void reply_oarea(void)
139 {
140 reply_msg(SW->rotharea);
141 }
142
followup(void)143 void followup(void)
144 {
145 reply_msg(SW->rfollow);
146 }
147
replyextra(void)148 void replyextra(void)
149 {
150 reply_msg(SW->rextra);
151 }
152
findArea(char * tag)153 static int findArea(char *tag)
154 {
155 int i = 0;
156 int areano;
157
158 while (i < SW->groupareas)
159 {
160 areano = group_getareano(i);
161 if (areano >= 0 &&
162 !stricmp(arealist[group_getareano(i)].tag, tag))
163 {
164 break;
165 }
166 i++;
167 }
168
169 if (i == SW->groupareas)
170 {
171 i = 0;
172 }
173
174 return i;
175 }
176
reply_msg(int type)177 static void reply_msg(int type)
178 {
179 FIDO_ADDRESS tmp;
180 msg *hlink;
181 msg *m;
182 unsigned long t = CurArea.current;
183 unsigned long tl = CurArea.lastread;
184 unsigned long link = t;
185 int oarea = SW->grouparea;
186 int ogroup = SW->group;
187 int q = 0;
188 msg *oldmsg; /* contains all the old information */
189 unsigned long ulink;
190 int toarea = 0, i;
191 int count; /* for robot names */
192
193 scan_base = 0;
194 oldmsg = NULL;
195
196 if (type & MT_NEW)
197 {
198 RefreshMsg(NULL, 6);
199 }
200
201 if ((!(type & MT_NEW) && CurArea.messages == 0) || !CurArea.status)
202 {
203 return;
204 }
205
206 group_set_group(0); /* allow crossposts etc. pp. into all areas, and not
207 only into areas of current group */
208
209 if (type & MT_ARC)
210 {
211 toarea = SW->grouparea;
212 if (message && message->replyarea)
213 {
214 toarea = findArea(message->replyarea);
215 }
216 toarea = selectarea("Answer In Area", toarea);
217 if (msgederr)
218 {
219 /* This code at this place is COMPLETE bullshit. No message has
220 ever been written, and no prior call to set_area has
221 taken place! It should be removed, but first I want to study if
222 there are any side effects of it's removal.
223
224 if ((type & MT_ARC) || scan_base || CurArea.msgtype == SQUISH)
225 {
226 set_area(oarea);
227 }
228 else
229 {
230 CurArea.current = link;
231 CurArea.messages++;
232 CurArea.last++;
233 }
234
235 */
236
237 group_set_group(ogroup);
238
239 return;
240 }
241 }
242
243 if (message)
244 {
245 oldmsg = duplicatemsg(message);
246 }
247
248 if (CurArea.messages == 0 || message == NULL)
249 {
250 message = xcalloc(1, sizeof *message);
251 }
252
253 ulink = message->msgnum;
254
255 /*
256 * We work with m, not message - the set_area() function kills
257 * message automatically.
258 */
259
260 m = message;
261 message = NULL;
262
263 if (type & MT_REP)
264 {
265 m->text = clearbuffer(m->text);
266 }
267
268 if (type & MT_NEW)
269 {
270 clearmsg(m);
271 }
272
273 if (type & MT_FOL)
274 {
275 release(m->msgid);
276 m->msgid = m->reply;
277 m->reply = NULL;
278 }
279
280 release(m->reply);
281
282 if (m->msgid)
283 {
284 m->reply = m->msgid;
285 m->msgid = NULL;
286 }
287 if (type & MT_FOL)
288 {
289 release(m->isfrom);
290 tmp = m->to;
291 }
292 else
293 {
294 if (!(type & MT_NEW))
295 {
296 release(m->isto);
297 m->isto = m->isfrom;
298 }
299 else
300 {
301 m->to.zone = CurArea.addr.zone;
302 }
303 tmp = m->from;
304 }
305
306 m->isfrom = xstrdup(ST->username);
307
308 if (type & MT_ARC)
309 {
310 set_area(toarea);
311 if (!CurArea.status)
312 {
313 dispose(oldmsg);
314 dispose(m);
315 group_set_group(ogroup);
316 set_area(oarea);
317 return;
318 }
319 }
320
321 /* TE: Only do lookup when composing a new message. Don't lookup
322 when replying to an exisiting message, because we suppose that the
323 sender wants the answer to the AKA that he is using. */
324 do_lookup = (CurArea.netmail && (type & MT_NEW)) ? TRUE : FALSE;
325 m->to = tmp;
326 m->timestamp = time(NULL);
327 if (SW->tzutc)
328 {
329 m->timezone = tz_my_offset();
330 m->has_timezone = 1;
331 }
332 m->replyto = 0;
333 m->new = 1;
334 m->cost = 0;
335 m->times_read = 0;
336 m->scanned = 0;
337 m->soteot = 0;
338 m->time_arvd = 0;
339
340 if (CurArea.echomail && CurArea.messages == 0)
341 {
342 m->msgnum = 2;
343 }
344 else
345 {
346 m->msgnum = MsgnToUid(CurArea.messages) + 1;
347 }
348
349 /* find a origin aka matching the destination zone for netmails */
350
351 m->from = CurArea.addr;
352 if (CurArea.addr.domain)
353 {
354 m->from.domain = xstrdup(CurArea.addr.domain);
355 }
356
357 if ((CurArea.netmail) && (!(type & MT_NEW)))
358 {
359 akamatch(&(m->from), &(m->to));
360 }
361
362 if (m->to.internet || m->to.bangpath)
363 {
364 char *oldptr = m->to.domain;
365 m->to.domain = compose_internet_address(m->to.domain, m->isto);
366 release(oldptr);
367 release(m->isto);
368 }
369
370 if (!(type & MT_NEW) && !(type & MT_ARC))
371 {
372 m->replyto = link;
373 }
374 else
375 {
376 m->replyto = 0;
377 }
378
379 clear_attributes(&m->attrib);
380 memset(m->replies, 0, sizeof(m->replies));
381
382 while (!q)
383 {
384 if (EditHeader(m) == Key_Esc)
385 {
386 if (confirm("Cancel?"))
387 {
388 dispose(oldmsg);
389
390 group_set_group(ogroup);
391 dispose(m);
392
393 if (type & MT_ARC)
394 set_area(oarea);
395
396 if (CurArea.status)
397 {
398 CurArea.current = (t) ? t : CurArea.current;
399 CurArea.lastread = (tl) ? tl : CurArea.lastread;
400 }
401 return;
402 }
403 }
404 else
405 {
406 q = 1;
407 }
408 }
409
410 /*
411 * Create the template for the message. Will not include template
412 * if being sent to robotnames. Modified by Kieran Haughey, Andrew
413 * Clarke.
414 */
415
416 if (user_list[0].robotname == NULL)
417 {
418 user_list[0].robotname = "AreaFix"; /* default */
419 }
420 count = 0;
421 for (i = 0; i < MAXUSERS; i++)
422 {
423 if (user_list[i].robotname == NULL || m->isto == NULL)
424 {
425 break;
426 }
427 if (stricmp(user_list[i].robotname, m->isto) == 0)
428 {
429 count++;
430 }
431 }
432
433 if (!(type & MT_NEW))
434 {
435 RefreshMsg(NULL, 6);
436 }
437
438 if (count == 0)
439 {
440 MakeTemplateMsg(m, oldmsg, group_getareano(oarea), type | MT_NEW);
441 }
442
443 if (ST->editorName != NULL)
444 {
445 editRet = externalEditor(m);
446 }
447 else
448 {
449 editRet = editmsg(m, ((type & MT_NEW) || (type & MT_REP)) ? 0 : 1);
450 }
451
452 switch (editRet)
453 {
454 case SAVE:
455 save(m);
456 if (!(type & MT_ARC) && !(type & MT_NEW))
457 {
458 link = UidToMsgn(ulink);
459 if (CurArea.msgtype != QUICK)
460 {
461 /* somewhere is leaking so i turned it off for QBBS */
462
463 if ((hlink = MsgReadHeader(link, RD_HEADER)) != NULL)
464 {
465 if (CurArea.msgtype == FIDO)
466 {
467 hlink->replies[0] = UidToMsgn(m->msgnum);
468 }
469 MsgWriteHeader(hlink, WR_HEADER);
470 dispose(hlink);
471 }
472 }
473 }
474 break;
475
476 case ABORT:
477 ChoiceBox("", "Message was aborted.", " Ok ", NULL, NULL);
478 scan_base = 1;
479 break;
480 }
481
482 dispose(oldmsg);
483 dispose(m);
484
485 group_set_group(ogroup);
486
487 if ((type & MT_ARC) || scan_base || CurArea.msgtype == SQUISH)
488 {
489 set_area(oarea);
490 CurArea.current = link;
491 }
492 else
493 {
494 CurArea.current = link;
495 CurArea.messages++;
496 CurArea.last++;
497 }
498 }
499
change(void)500 void change(void)
501 {
502 int q = 0;
503 unsigned long t = CurArea.current;
504 int oarea = SW->grouparea;
505 int ogroup = SW->group;
506
507 if (CurArea.messages == 0 || !CurArea.status || !message)
508 return;
509
510 if (message->attrib.sent || message->scanned)
511 {
512 if (!sent_msg())
513 {
514 return;
515 }
516 }
517
518 message->attrib.sent = 0;
519 message->attrib.orphan = 0;
520 message->attrib.local = 1;
521 message->scanned = 0;
522 do_lookup = FALSE;
523
524 if (message->to.internet || message->to.bangpath)
525 {
526 char *oldptr = message->to.domain;
527 message->to.domain = compose_internet_address(message->to.domain,
528 message->isto);
529 release(oldptr);
530 release(message->isto);
531 }
532
533 while (!q)
534 {
535 if (EditHeader(message) == Key_Esc)
536 {
537 if (confirm("Cancel?"))
538 {
539 if (t)
540 {
541 CurArea.current = t;
542 }
543 return;
544 }
545 }
546 else
547 {
548 q = 1;
549 }
550 }
551
552 if (ST->editorName != NULL)
553 {
554 editRet = externalEditor(message);
555 }
556 else
557 {
558 editRet = editmsg(message, FALSE);
559 }
560
561 switch (editRet)
562 {
563 case SAVE:
564 save(message);
565 break;
566
567 case ABORT:
568 ChoiceBox("", "Message was aborted.", " Ok ", NULL, NULL);
569 break;
570 }
571
572 group_set_group(ogroup);
573
574 if (scan_base) /* While changing, CC:s and XC:s could occur. */
575 {
576 set_area(oarea);
577 }
578
579 if (t)
580 {
581 CurArea.current = t;
582 }
583 message = KillMsg(message);
584 }
585
ChangeAttrib(msg * m)586 int ChangeAttrib(msg * m)
587 {
588 WND *hWnd, *hCurr;
589 int ch, done = 0;
590
591 hCurr = WndTop();
592 hWnd = WndPopUp(62, 13, SBDR | SHADOW, cm[IN_BTXT], cm[IN_NTXT]);
593
594 /* put up some help for the befuddled user */
595
596 WndTitle(" Message Attributes (Alt-Z: erase all)", cm[IN_NTXT]);
597
598 WndWriteStr(2, 0, cm[IN_NTXT], "Private <Alt-P> Crash <Alt-C>");
599 WndWriteStr(2, 1, cm[IN_NTXT], "File Attach <Alt-A> Kill/Sent <Alt-K>");
600 WndWriteStr(2, 2, cm[IN_NTXT], "Hold <Alt-H> Direct <Alt-D>");
601 WndWriteStr(2, 3, cm[IN_NTXT], "Sent <Alt-S> Received <Alt-R>");
602 WndWriteStr(2, 4, cm[IN_NTXT], "Orphan <Alt-O> File Request <Alt-F>");
603 WndWriteStr(2, 5, cm[IN_NTXT], "Return Rcpt <Alt-E> Return Rcpt Request <Alt-Q>");
604 WndWriteStr(2, 6, cm[IN_NTXT], "Audit Request <Alt-I> File Update Request <Alt-U>");
605 WndWriteStr(2, 7, cm[IN_NTXT], "Local <Alt-L> Intransit (Forward) <Alt-T>");
606 WndWriteStr(2, 8, cm[IN_NTXT], "Kill File when Sent <Alt-X> Truncate File w. S. <Alt-Y>");
607 WndWriteStr(2, 9, cm[IN_NTXT], "Archive when Sent <Alt-J> Immediate Delivery <Alt-V>");
608 WndWriteStr(2,10, cm[IN_NTXT], "Lock <Alt-W> Confirm Rcpt Req <Alt-M>");
609 WndWriteStr(2,11, cm[IN_NTXT], "Route via Zone Gate <Alt-G> Route via Hub <Alt-B>");
610 /* WndWriteStr(2,12, cm[IN_NTXT], " Zap (erase) all attributes <Alt-Z> "); */
611
612 WndCurr(hCurr); /* make parent window active so we can write to it */
613
614 ShowAttrib(m);
615
616 while (!done)
617 {
618 ch = GetKey();
619 switch (ch)
620 {
621 case Key_Up:
622 case Key_Dwn:
623 case Key_Ent:
624 case Key_Esc:
625 done = 1; /* we return these to the caller */
626 break;
627
628 case Key_A_A:
629 m->attrib.attach ^= 1;
630 break;
631
632 case Key_A_P:
633 m->attrib.priv ^= 1;
634 break;
635
636 case Key_A_C:
637 m->attrib.crash ^= 1;
638 break;
639
640 case Key_A_U:
641 m->attrib.ureq ^= 1;
642 break;
643
644 case Key_A_F:
645 m->attrib.freq ^= 1;
646 break;
647
648 case Key_A_K:
649 m->attrib.killsent ^= 1;
650 break;
651
652 case Key_A_H:
653 m->attrib.hold ^= 1;
654 break;
655
656 case Key_A_D:
657 m->attrib.direct ^= 1;
658 break;
659
660 case Key_A_Q:
661 m->attrib.rreq ^= 1;
662 break;
663
664 case Key_A_E:
665 m->attrib.rcpt ^= 1;
666 break;
667
668 case Key_A_R:
669 m->attrib.rcvd ^= 1;
670 break;
671
672 case Key_A_S:
673 m->attrib.sent ^= 1;
674 break;
675
676 case Key_A_O:
677 m->attrib.orphan ^= 1;
678 break;
679
680 case Key_A_I:
681 m->attrib.areq ^= 1;
682 break;
683
684 case Key_A_L:
685 m->attrib.local ^= 1;
686 break;
687
688 case Key_A_T:
689 m->attrib.forward ^= 1;
690 break;
691
692 case Key_A_X:
693 m->attrib.kfs ^= 1;
694 break;
695
696 case Key_A_Y:
697 m->attrib.tfs ^= 1;
698 break;
699
700 case Key_A_J:
701 m->attrib.as ^= 1;
702 break;
703
704 case Key_A_V:
705 m->attrib.immediate ^= 1;
706 break;
707
708 case Key_A_W:
709 m->attrib.lock ^= 1;
710 break;
711
712 case Key_A_M:
713 m->attrib.cfm ^= 1;
714 break;
715
716 case Key_A_G:
717 m->attrib.zon ^= 1;
718 break;
719
720 case Key_A_B:
721 m->attrib.hub ^= 1;
722 break;
723
724
725 case Key_A_Z:
726 m->attrib.attach = 0;
727 m->attrib.priv = 0;
728 m->attrib.crash = 0;
729 m->attrib.ureq = 0;
730 m->attrib.freq = 0;
731 m->attrib.killsent = 0;
732 m->attrib.hold = 0;
733 m->attrib.direct = 0;
734 m->attrib.rreq = 0;
735 m->attrib.rcpt = 0;
736 m->attrib.rcvd = 0;
737 m->attrib.sent = 0;
738 m->attrib.orphan = 0;
739 m->attrib.areq = 0;
740 m->attrib.local = 0;
741 m->attrib.forward = 0;
742 m->attrib.kfs = 0;
743 m->attrib.as = 0;
744 m->attrib.immediate = 0;
745 m->attrib.tfs = 0;
746 m->attrib.lock = 0;
747 m->attrib.cfm = 0;
748 m->attrib.zon = 0;
749 m->attrib.hub = 0;
750 m->scanned = 0;
751 break;
752
753 default:
754 switch ((toupper(ch & 0xff)))
755 {
756 case 'A':
757 m->attrib.attach ^= 1;
758 break;
759
760 case 'P':
761 m->attrib.priv ^= 1;
762 break;
763
764 case 'C':
765 m->attrib.crash ^= 1;
766 break;
767
768 case 'U':
769 m->attrib.ureq ^= 1;
770 break;
771
772 case 'F':
773 m->attrib.freq ^= 1;
774 break;
775
776 case 'K':
777 m->attrib.killsent ^= 1;
778 break;
779
780 case 'H':
781 m->attrib.hold ^= 1;
782 break;
783
784 case 'D':
785 m->attrib.direct ^= 1;
786 break;
787
788 case 'Q':
789 m->attrib.rreq ^= 1;
790 break;
791
792 case 'E':
793 m->attrib.rcpt ^= 1;
794 break;
795
796 case 'R':
797 m->attrib.rcvd ^= 1;
798 break;
799
800 case 'S':
801 m->attrib.sent ^= 1;
802 break;
803
804 case 'O':
805 m->attrib.orphan ^= 1;
806 break;
807
808 case 'I':
809 m->attrib.areq ^= 1;
810 break;
811
812 case 'L':
813 m->attrib.local ^= 1;
814 break;
815
816 case 'T':
817 m->attrib.forward ^= 1;
818 break;
819
820 case 'X':
821 m->attrib.kfs ^= 1;
822 break;
823
824 case 'Y':
825 m->attrib.tfs ^= 1;
826 break;
827
828 case 'J':
829 m->attrib.as ^= 1;
830 break;
831
832 case 'V':
833 m->attrib.immediate ^= 1;
834 break;
835
836 case 'W':
837 m->attrib.lock ^= 1;
838 break;
839
840 case 'M':
841 m->attrib.cfm ^= 1;
842 break;
843
844 case 'G':
845 m->attrib.zon ^= 1;
846 break;
847
848 case 'B':
849 m->attrib.hub ^= 1;
850 break;
851
852 case 'Z':
853 m->attrib.attach = 0;
854 m->attrib.priv = 0;
855 m->attrib.crash = 0;
856 m->attrib.ureq = 0;
857 m->attrib.freq = 0;
858 m->attrib.killsent = 0;
859 m->attrib.hold = 0;
860 m->attrib.direct = 0;
861 m->attrib.rreq = 0;
862 m->attrib.rcpt = 0;
863 m->attrib.rcvd = 0;
864 m->attrib.sent = 0;
865 m->attrib.orphan = 0;
866 m->attrib.areq = 0;
867 m->attrib.local = 0;
868 m->attrib.forward = 0;
869 m->attrib.kfs = 0;
870 m->attrib.as = 0;
871 m->attrib.immediate = 0;
872 m->attrib.tfs = 0;
873 m->attrib.lock = 0;
874 m->attrib.cfm = 0;
875 m->attrib.zon = 0;
876 m->attrib.hub = 0;
877 m->scanned = 0;
878 break;
879
880 default:
881 break;
882 }
883 }
884 ShowAttrib(m);
885 }
886
887 WndCurr(hWnd);
888 WndClose(hWnd);
889 WndCurr(hCurr);
890 return ch; /* pass the exit key back to caller */
891 }
892
893 /*
894 * Looks up the alias list and returns the new name, and changes the
895 * passed address to the alias addres, if the passed name had a
896 * corresponding alias.
897 */
898
alias_lookup(FIDO_ADDRESS * addr,char * isto)899 static char *alias_lookup(FIDO_ADDRESS * addr, char *isto)
900 {
901 int l;
902 char *name;
903
904 /* search for a matching alias */
905
906 for (l = 0; l < SW->otheraliases; l++)
907 {
908 if (!stricmp(aliaslist[l].alias, isto))
909 {
910 break;
911 }
912 }
913
914 if (l >= SW->otheraliases)
915 {
916 return NULL;
917 }
918 else
919 {
920 name = xstrdup(aliaslist[l].name);
921 addr->domain = NULL;
922 *addr = aliaslist[l].addr;
923 if (aliaslist[l].addr.domain != NULL)
924 {
925 addr->domain = xstrdup(aliaslist[l].addr.domain);
926 }
927
928 /* if (aliaslist[l].addr.internet == 1)
929 {
930 *addr = uucp_gate;
931 addr->domain = NULL;
932 }
933 else
934 {
935 *addr = aliaslist[l].addr;
936 if (aliaslist[l].addr.domain)
937 {
938 addr->domain = xstrdup(aliaslist[l].addr.domain);
939 }
940 else
941 {
942 addr->domain = NULL;
943 }
944 } */
945 }
946 return name;
947 }
948
949 /*
950 * Looks up the alias list to see if the passed alias has a subject.
951 */
952
subj_lookup(char * isto)953 char *subj_lookup(char *isto)
954 {
955 int l;
956
957 for (l = 0; l < SW->otheraliases; l++)
958 {
959 if (!stricmp(aliaslist[l].alias, isto))
960 {
961 break;
962 }
963 }
964
965 if (l >= SW->otheraliases || aliaslist[l].subj == NULL)
966 {
967 return NULL;
968 }
969
970 return xstrdup(aliaslist[l].subj);
971 }
972
973 /*
974 * Looks up name and addresses using alias, nodelist and fido userlist
975 * methods. Returns a pointer to allocated memory containing the name
976 * to be used, and writes to the passed address variable.
977 *
978 * Modifications by: Roland Gautschi (V7 lookup code - added flexibility).
979 */
980
addr_lookup(char * name,FIDO_ADDRESS * tmp)981 static char *addr_lookup(char *name, FIDO_ADDRESS * tmp)
982 {
983 char *nname;
984 char xname[73];
985 char namefound[73];
986 char userlistname[73];
987 int ret;
988
989 tmp->fidonet = 1;
990 tmp->internet = 0;
991 tmp->bangpath = 0;
992
993 if ((nname = alias_lookup(tmp, name)) == NULL)
994 {
995 nname = xstrdup(name); /* couldn't find an alias, so.. */
996 strcpy(xname, name); /* make a copy, just in case */
997
998 if (do_lookup)
999 {
1000 /*
1001 * Userlists are checked first, because they may have overides
1002 * wanted by the user.
1003 */
1004
1005 if (ST->fidolist != NULL)
1006 {
1007 strcpy (userlistname, name);
1008 *tmp = lookup(userlistname, ST->fidolist);
1009 if ((tmp->notfound) && (ST->userlist != NULL))
1010 {
1011 *tmp = lookup(userlistname, ST->userlist);
1012 }
1013 if (!tmp->notfound)
1014 {
1015 release(nname);
1016 nname = xstrdup(userlistname);
1017 }
1018 }
1019 else
1020 {
1021 tmp->notfound = 1;
1022 }
1023
1024 if (tmp->notfound == 1 && ST->nodepath != NULL)
1025 {
1026 /* Check to see if an address has been entered. */
1027
1028 if (m_isdigit(xname[0]) || xname[0] == ':' ||
1029 xname[0] == '/' || xname[0] == '.')
1030 {
1031 *tmp = parsenode(xname);
1032 if (tmp->notfound == 0)
1033 {
1034 if (v7lookupnode(tmp, xname) == NULL)
1035 {
1036 tmp->notfound = 1;
1037 }
1038 else
1039 {
1040 xfree(nname);
1041 nname = xstrdup(xname);
1042 }
1043 }
1044 }
1045
1046 /*
1047 * If the node still hasn't been found, then lookup
1048 * normally (using the entered name).
1049 */
1050
1051 if (tmp->notfound == 1)
1052 {
1053 *tmp = v7lookup(xname);
1054
1055 /* If we found something, copy it. */
1056
1057 if (tmp->notfound == 0)
1058 {
1059 if (strcmp(nname, xname) != 0)
1060 {
1061 sprintf(namefound, "%s at %s found, change?",
1062 xname, show_address(tmp));
1063 ret = ChoiceBox(" Change Name ", namefound,
1064 "Yes", "No", NULL);
1065 if (ret == ID_ONE)
1066 {
1067 xfree(nname);
1068 nname = xstrdup(xname);
1069 }
1070 }
1071 }
1072 }
1073 }
1074 }
1075 }
1076
1077 return nname;
1078 }
1079
GetAddress(FIDO_ADDRESS * addr,char * from,char * subj)1080 static void GetAddress(FIDO_ADDRESS * addr, char *from, char *subj)
1081 {
1082 char *name, *str;
1083
1084 if (do_lookup && (!CurArea.netmail))
1085 {
1086 do_lookup = FALSE;
1087 }
1088
1089 name = addr_lookup(from, addr);
1090
1091 /* Check for an Alias subject. */
1092
1093 if ((str = subj_lookup(from)) != NULL)
1094 {
1095 strcpy(subj, str);
1096 release(str);
1097 }
1098
1099 /* Check the name to see if it's a usenet message. */
1100
1101 str = strchr(name, '@');
1102 if (str != NULL && (CurArea.netmail && CurArea.uucp))
1103 {
1104 addr->fidonet = 0;
1105 addr->notfound = 0;
1106 if (str == name)
1107 {
1108 addr->bangpath = 1;
1109 str++;
1110 }
1111 else
1112 {
1113 addr->internet = 1;
1114 str = name;
1115 }
1116 release(addr->domain);
1117 addr->domain = xstrdup(str);
1118 strcpy(from, str);
1119 }
1120 else if (str!=NULL && (CurArea.news || CurArea.uucp))
1121 {
1122 parse_internet_address(name, NULL, &str);
1123 strcpy(from, str);
1124 }
1125 else
1126 {
1127 strcpy(from, name);
1128 }
1129 release(name);
1130 }
1131
ChangeName(FIDO_ADDRESS * addr,char * from,char * subj,int y)1132 static int ChangeName(FIDO_ADDRESS * addr, char *from, char *subj, int y)
1133 {
1134 EVT e;
1135 char tmp[73], tmp2[73];
1136 static int disp;
1137 int ch = 0, pos, done = 0;
1138
1139 strcpy(tmp2, subj);
1140 tmp[0] = '\0';
1141 if (addr->internet && addr->domain != NULL)
1142 {
1143 strncpy(tmp, addr->domain, sizeof tmp - 1);
1144 }
1145 else
1146 {
1147 if (addr->bangpath && addr->domain != NULL)
1148 {
1149 strncat(strcpy(tmp, "@"), addr->domain, sizeof tmp - 1);
1150 }
1151 else
1152 {
1153 if (from != NULL)
1154 {
1155 strncpy(tmp, from, sizeof tmp - 1);
1156 }
1157 }
1158 }
1159
1160 pos = strlen(tmp);
1161 disp = 1;
1162
1163 while (!done)
1164 {
1165 if (addr->bangpath || addr->internet || CurArea.news || CurArea.uucp)
1166 {
1167 ch = WndGetLine(8, y, maxx - 28, tmp, cm[CM_ETXT], &pos, disp, 0, disp, &e);
1168 }
1169 else
1170 {
1171 ch = WndGetLine(8, y, 36, tmp, cm[CM_ETXT], &pos, disp, 0, disp, &e);
1172 }
1173
1174 switch (e.msgtype)
1175 {
1176 case WND_WM_CHAR:
1177 switch (ch)
1178 {
1179 case Key_Esc:
1180 done = 1;
1181 break;
1182
1183 case Key_Up:
1184 case Key_Dwn:
1185 case Key_Rgt:
1186 case Key_Lft:
1187 case Key_Ent:
1188 if (addr->fidonet)
1189 {
1190 if (strlen(tmp) > 36)
1191 {
1192 tmp[35] = '\0';
1193 }
1194 }
1195 GetAddress(addr, tmp, tmp2);
1196 strcpy(from, tmp);
1197 if (strcmp(subj, tmp2))
1198 {
1199 strcpy(subj, tmp2);
1200 ShowSubject(subj);
1201 }
1202 done = 1;
1203 break;
1204
1205 default:
1206 break;
1207 }
1208 break;
1209
1210 default:
1211 break;
1212 }
1213 disp = 0;
1214 }
1215
1216 return ch;
1217 }
1218
ChangeAddress(FIDO_ADDRESS * addr,int y,int nm_len)1219 int ChangeAddress(FIDO_ADDRESS * addr, int y, int nm_len)
1220 {
1221 EVT e;
1222 char tmp[41];
1223 int ch, pos, done = 0, disp = 1;
1224
1225 strncpy(tmp, show_address(addr), 40);
1226 release(addr->domain);
1227
1228 pos = strlen(tmp);
1229
1230 while (!done)
1231 {
1232 ch = WndGetLine(8 + nm_len + 2, y, 50 - nm_len, tmp, cm[CM_ETXT], &pos, disp, 0, disp, &e);
1233
1234 switch (e.msgtype)
1235 {
1236 case WND_WM_CHAR:
1237 switch (ch)
1238 {
1239 case Key_Esc:
1240 done = 1;
1241 break;
1242
1243 case Key_Up:
1244 case Key_Dwn:
1245 case Key_Rgt:
1246 case Key_Lft:
1247 case Key_Ent:
1248 *addr = parsenode(tmp);
1249 done = 1;
1250 break;
1251
1252 default:
1253 break;
1254 }
1255 break;
1256
1257 default:
1258 break;
1259 }
1260 disp = 0;
1261 }
1262
1263 return ch;
1264 }
1265
ChangeSubject(char * subj)1266 int ChangeSubject(char *subj)
1267 {
1268 EVT e;
1269 struct _dta fileinfo;
1270 char tmp[73];
1271 int ch, pos, ch2, done = 0, disp = 1;
1272
1273 strncpy(tmp, subj, sizeof tmp - 1);
1274
1275 pos = strlen(tmp);
1276
1277 while (!done)
1278 {
1279 ch = WndGetLine(8, 3, 72, tmp, cm[CM_ETXT], &pos, disp, 0, disp, &e);
1280
1281 switch (e.msgtype)
1282 {
1283 case WND_WM_CHAR:
1284 switch (ch)
1285 {
1286 case Key_Esc:
1287 done = 1;
1288 break;
1289
1290 case Key_Up:
1291 case Key_Dwn:
1292 case Key_Rgt:
1293 case Key_Lft:
1294 case Key_Ent:
1295 strcpy(subj, tmp);
1296 if (strlen(subj) > 3 && *(subj + 1) == ':' &&
1297 (*(subj + 2) == '\\' || *(subj + 2) == '/'))
1298 {
1299 /*
1300 * If the file doesn't exist, then ask if user wants
1301 * to continue...
1302 */
1303
1304 if (dir_findfirst(subj, DIR_NORMAL, &fileinfo) != 0)
1305 {
1306 ch2 = ChoiceBox("", "WARNING: File doesn't exist! Attach anyway?",
1307 "Yes", "No", NULL);
1308
1309 if (ch2 == ID_ONE)
1310 {
1311 EdMsg->attrib.attach = 1;
1312 }
1313 else
1314 {
1315 /* continue editing */
1316 continue;
1317 }
1318 }
1319 else
1320 {
1321 EdMsg->attrib.attach = 1;
1322 }
1323 }
1324 done = 1;
1325 break;
1326
1327 default:
1328 break;
1329 }
1330 break;
1331
1332 default:
1333 break;
1334 }
1335 disp = 0;
1336 }
1337 ShowSubject(subj);
1338 return ch;
1339 }
1340
getstring(char * buf)1341 static char *getstring(char *buf)
1342 {
1343 if (strlen(buf) > 0)
1344 {
1345 return xstrdup(buf);
1346 }
1347 else
1348 {
1349 return NULL;
1350 }
1351 }
1352
construct_uucpname(const char * cpdomain)1353 char *construct_uucpname(const char *cpdomain)
1354 {
1355 if (strcmp(ST->uucpgate, "*") != 0)
1356 {
1357 return xstrdup(ST->uucpgate);
1358 }
1359 else
1360 {
1361 char *cpname;
1362
1363 parse_internet_address(cpdomain, NULL, &cpname);
1364 return cpname;
1365 }
1366 }
1367
1368 #define FD_FROM 0
1369 #define FD_FADD 1
1370 #define FD_TO 2
1371 #define FD_TADD 3
1372 #define FD_SUBJ 4
1373 #define FD_ATTR 5
1374
EditHeader(msg * m)1375 int EditHeader(msg * m)
1376 {
1377 char tmp[80], tmp2[80];
1378 int field = 2;
1379 int ch = 0, done = 0;
1380
1381 /*
1382 * This is naughty, but it allows the functions to access the
1383 * current message in those special cases.
1384 */
1385
1386 EdMsg = m;
1387
1388 ShowMsgHeader(m);
1389
1390 while (!done)
1391 {
1392 strcpy(tmp, "");
1393 strcpy(tmp2, "");
1394
1395 switch (field)
1396 {
1397 case FD_FROM:
1398 ShowNameAddress(m->isfrom, &m->from, 1, 0, 1);
1399 if (m->isfrom)
1400 {
1401 strcpy(tmp, m->isfrom);
1402 release(m->isfrom);
1403 }
1404 if (m->subj)
1405 {
1406 strcpy(tmp2, m->subj);
1407 release(m->subj);
1408 }
1409 ch = ChangeName(&m->from, tmp, tmp2, 1);
1410 m->isfrom = getstring(tmp);
1411 m->subj = getstring(tmp2);
1412
1413 if (m->from.internet || m->from.bangpath)
1414 {
1415 char *oldname=m->isfrom;
1416
1417 m->isfrom = construct_uucpname(m->isfrom);
1418 release (oldname);
1419
1420 }
1421 ShowNameAddress(m->isfrom, &m->from, 1, 0, 1);
1422 break;
1423
1424 case FD_FADD:
1425 if (CurArea.netmail && m->from.fidonet)
1426 {
1427 ch = ChangeAddress(&m->from, 1,
1428 (m->isfrom) ? strlen(m->isfrom) : 0);
1429 m->from.dontmatch = 1; /* no more aka matching here, please */
1430 }
1431 ShowNameAddress(m->isfrom, &m->from, 1, 0, 0);
1432 break;
1433
1434 case FD_TO:
1435 if (CurArea.news)
1436 {
1437 release(m->isto);
1438 m->isto = xstrdup("All");
1439 m->to = uucp_gate;
1440 ch = Key_Dwn;
1441 }
1442 else
1443 {
1444 ShowNameAddress(m->isto, &m->to, 2, 0, 1);
1445 if (m->isto)
1446 {
1447 strcpy(tmp, m->isto);
1448 release(m->isto);
1449 }
1450 if (m->subj)
1451 {
1452 strcpy(tmp2, m->subj);
1453 release(m->subj);
1454 }
1455 ch = ChangeName(&m->to, tmp, tmp2, 2);
1456 m->isto = getstring(tmp);
1457 m->subj = getstring(tmp2);
1458 }
1459
1460 /* generate the UUCP user name, if e-mail address was entered */
1461 if (m->to.internet || m->to.bangpath)
1462 {
1463 char *oldname = m->isto;
1464
1465 m->isto = construct_uucpname(m->isto);
1466 release(oldname);
1467 }
1468
1469 ShowNameAddress(m->isto, &m->to, 2, 0, 1);
1470 break;
1471
1472 case FD_TADD:
1473 if (CurArea.netmail && m->to.fidonet)
1474 {
1475 ch = ChangeAddress(&m->to, 2, (m->isto) ? strlen(m->isto) : 0);
1476 }
1477
1478 /* AKA matching, only for netmails */
1479 if (CurArea.netmail)
1480 {
1481 if (akamatch(&(m->from), &(m->to)))
1482 {
1483 /* we found a better address, redisplay it */
1484 ShowNameAddress(m->isfrom, &m->from, 1, 0, 0);
1485 }
1486 }
1487 break;
1488
1489 case FD_SUBJ:
1490 if (m->subj)
1491 {
1492 strcpy(tmp, m->subj);
1493 release(m->subj);
1494 }
1495 ch = ChangeSubject(tmp);
1496 m->subj = getstring(tmp);
1497 break;
1498
1499 case FD_ATTR:
1500 ch = ChangeAttrib(m);
1501 break;
1502
1503 default:
1504 break;
1505 }
1506
1507 if (ch == Key_Esc)
1508 {
1509 done = 1;
1510 }
1511 else if (ch == Key_Up)
1512 {
1513 field--;
1514
1515 if (field < 0)
1516 {
1517 field = 5;
1518 }
1519
1520 /* Handle the cases where going up stuffs the address showing. */
1521
1522 switch (field)
1523 {
1524 case FD_FADD:
1525 ShowNameAddress(m->isto, &m->to, 2, 0, 0);
1526 break;
1527
1528 case FD_ATTR:
1529 ShowNameAddress(m->isfrom, &m->from, 1, 0, 0);
1530 break;
1531
1532 default:
1533 break;
1534 }
1535 }
1536 else if (ch == Key_Dwn || ch == Key_Ent)
1537 {
1538 if (field == 5 && ch == Key_Ent)
1539 {
1540 break;
1541 }
1542
1543 field++;
1544
1545 if (field > 5)
1546 {
1547 field = 0;
1548 }
1549
1550 continue;
1551 }
1552 }
1553
1554 ShowMsgHeader(m);
1555 cursor(0);
1556
1557 return 0;
1558 }
1559
1560 /*
1561 * Clears all the attributes of a message, leaving Local set to TRUE.
1562 * Not static; is called from maintmsg.c module.
1563 */
1564
clear_attributes(struct _attributes * h)1565 void clear_attributes(struct _attributes *h)
1566 {
1567 memset(h, '\0', sizeof *h);
1568 h->crash = CurArea.crash;
1569 h->priv = CurArea.priv;
1570 h->killsent = CurArea.killsent;
1571 h->hold = CurArea.hold;
1572 h->direct = CurArea.direct;
1573 h->local = 1;
1574 }
1575
1576 /* Contains the name and address of the recipient of the message */
1577
1578 typedef struct
1579 {
1580 char *name;
1581 FIDO_ADDRESS addr;
1582 }
1583 NA;
1584
CreateNormalCC(msg * m,NA * names[])1585 static void CreateNormalCC(msg * m, NA * names[])
1586 {
1587 LINE *current;
1588 char dfn[256];
1589
1590 int i = 0;
1591
1592 m->text = lineins(m->text);
1593 m->text->text = xstrdup("\n");
1594 m->text = lineins(m->text);
1595
1596 sprintf(dfn, "* Original to: %s\n", names[i]->name);
1597
1598 i++;
1599
1600 m->text->text = xstrdup(dfn);
1601
1602 strcpy(dfn, "* Carbon Copies: ");
1603
1604 current = m->text;
1605 current = lineins(current->next);
1606 current->text = xstrdup("\n");
1607
1608 while (names[i] != NULL)
1609 {
1610 if (strlen(names[i]->name) + strlen(dfn) >= SW->rm)
1611 {
1612 strcat(dfn, "\n");
1613 release(current->text);
1614
1615 current->text = xstrdup(dfn);
1616 current = lineins(current->next);
1617 current->text = xstrdup("\n");
1618
1619 strcpy(dfn, " ");
1620 }
1621 strcat(dfn, names[i]->name);
1622
1623 i++;
1624
1625 if (names[i] != NULL)
1626 {
1627 strcat(dfn, ", ");
1628 }
1629 }
1630
1631 if (*(current->text) == '\n')
1632 {
1633 release(current->text);
1634 current->text = xstrdup(dfn);
1635 }
1636 }
1637
CreateVerboseCC(msg * m,NA * names[])1638 static void CreateVerboseCC(msg * m, NA * names[])
1639 {
1640 int i = 0;
1641 char dfn[256];
1642
1643 m->text = lineins(m->text);
1644 m->text->text = xstrdup("\n");
1645
1646 while (names[i] != NULL)
1647 {
1648 if (strchr(names[i]->name, '@') == NULL)
1649 {
1650 sprintf(dfn, " %s at %s\n", names[i]->name, show_address(&names[i]->addr));
1651 }
1652 else
1653 {
1654 sprintf(dfn, " %s\n", names[i]->name);
1655 }
1656
1657 m->text = lineins(m->text);
1658 m->text->text = xstrdup(dfn);
1659
1660 i++;
1661 }
1662
1663 m->text = lineins(m->text);
1664 m->text->text = xstrdup("* Carbon Copies to:\n");
1665 }
1666
1667 /*
1668 * Gets the CC:s from a response file.
1669 */
1670
GetFileCCs(char * file,NA * names[],int * idx)1671 static void GetFileCCs(char *file, NA * names[], int *idx)
1672 {
1673 FILE *fp;
1674 char buf[256];
1675 char *s, *c, *t;
1676 int i;
1677
1678 i = *idx;
1679
1680 fp = fopen(file, "r");
1681 if (fp == NULL)
1682 {
1683 return;
1684 }
1685
1686 while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
1687 {
1688 s = buf;
1689 while (*s && m_isspace(*s))
1690 {
1691 s++;
1692 }
1693
1694 if (!*s || *s == ';')
1695 {
1696 continue;
1697 }
1698
1699 t = s + strlen(s) - 1;
1700 while (t > s && m_isspace(*t))
1701 {
1702 t--;
1703 }
1704
1705 if (t == s)
1706 {
1707 continue;
1708 }
1709 else
1710 {
1711 if (*(t + 1))
1712 {
1713 t++;
1714 }
1715 *t = '\0';
1716 }
1717
1718 names[i] = xcalloc(1, sizeof(NA));
1719
1720 if ((c = strchr(s, '@')) != NULL)
1721 {
1722 /* Then we have an internet/bangpath. */
1723
1724 names[i]->addr.fidonet = 0;
1725 if (c == s)
1726 {
1727 names[i]->addr.bangpath = 1;
1728 c++;
1729 }
1730 else
1731 {
1732 names[i]->addr.internet = 1;
1733 c = s;
1734 }
1735 names[i]->name = xstrdup(c);
1736 names[i]->addr.domain = xstrdup(c);
1737 }
1738 else
1739 {
1740 c = strchr(s, '!');
1741
1742 if (c)
1743 {
1744 *c = '\0';
1745 names[i]->addr = parsenode(++c);
1746 names[i]->name = xstrdup(s);
1747 }
1748 else
1749 {
1750 names[i]->name = addr_lookup(s, &names[i]->addr);
1751
1752 /* UUCP address from alias? */
1753
1754 if ((c = strchr(names[i]->name, '@')) != NULL)
1755 {
1756 names[i]->addr.fidonet = 0;
1757 if (c == names[i]->name)
1758 {
1759 names[i]->addr.bangpath = 1;
1760 c++;
1761 }
1762 else
1763 {
1764 names[i]->addr.internet = 1;
1765 c = names[i]->name;
1766 }
1767 names[i]->addr.domain = xstrdup(c);
1768 }
1769 }
1770 }
1771
1772 if (names[i]->addr.notfound)
1773 {
1774 names[i]->addr = CurArea.addr;
1775 if (CurArea.addr.domain)
1776 {
1777 names[i]->addr.domain = xstrdup(CurArea.addr.domain);
1778 }
1779 }
1780 i++;
1781 }
1782 names[i] = NULL;
1783 *idx = i;
1784 fclose(fp);
1785 }
1786
1787 /*
1788 * Saves a message if the first line does not contain "CC:" or "XC:",
1789 * else it continues and either makes a carbon copy (or copies) or
1790 * crosspost(s) of the message.
1791 *
1792 * The idea here is: First get the addresses from the CC: list, if there
1793 * is one (if not, check for XC: and leave). If so, we then make up the
1794 * text for the message (in a loop), then we go and save the messages using
1795 * the names and addresses from the CC: list.
1796 */
1797
save(msg * m)1798 void save(msg * m)
1799 {
1800 LINE *current;
1801 NA *names[128];
1802 int num = 1, i;
1803 unsigned long k;
1804 int verbose_cc = 0;
1805 int blind_cc = 0;
1806 char *s, *t, *sp;
1807
1808 current = m->text;
1809 do_lookup = TRUE;
1810
1811 /* if (m->new) */
1812 {
1813 if (!strncmpi(current->text, "xc:", 3) && !CurArea.netmail)
1814 {
1815 if (m == message)
1816 {
1817 message = NULL;
1818 scan_base = 1;
1819 }
1820 crosspost(m);
1821 return;
1822 }
1823 }
1824 current = m->text;
1825 s = current->text;
1826
1827 if (!strncmpi(current->text, "bc:", 3))
1828 {
1829 blind_cc = 1;
1830 }
1831 else if (!strncmpi(current->text, "hc:", 3))
1832 {
1833 blind_cc = 1;
1834 }
1835 else if (!strncmpi(current->text, "vc:", 3))
1836 {
1837 verbose_cc = 1;
1838 }
1839 else if (strncmpi(current->text, "cc:", 3))
1840 {
1841 writemsg(m);
1842 scan_base = TRUE;
1843 return;
1844 }
1845 release(m->reply);
1846
1847 memset(names, 0, sizeof names);
1848
1849 names[0] = xmalloc(sizeof(NA));
1850
1851 names[0]->addr = m->to;
1852 if (m->to.internet || m->to.bangpath)
1853 {
1854 names[0]->name = compose_internet_address(m->to.domain, m->isto);
1855 names[0]->addr = m->to;
1856 names[0]->addr.domain = xstrdup(names[0]->name);
1857 }
1858 else
1859 {
1860 names[0]->name = xstrdup(m->isto);
1861 if (m->to.domain)
1862 {
1863 names[0]->addr.domain = xstrdup(m->to.domain);
1864 }
1865 }
1866
1867 m->attrib.sent = 1;
1868 if (SW->savecc && SW->rawcc)
1869 {
1870 writemsg(m);
1871 m->attrib.killsent = 1;
1872 }
1873 m->attrib.sent = 0;
1874
1875
1876 /* Get names and addresses from CC: list. */
1877
1878 while (current && *s && !strncmpi(s + 1, "c:", 2))
1879 {
1880 s += 3;
1881 while (*s && m_isspace(*s))
1882 {
1883 s++;
1884 }
1885
1886 if (*s == '~')
1887 {
1888 sp = strchr(s, '\n');
1889 if (sp != NULL)
1890 {
1891 *sp = '\0';
1892 }
1893 GetFileCCs(s + 1, names, &num);
1894 }
1895 else
1896 {
1897 while (*s != '\0' && s != NULL)
1898 {
1899 while (*s && m_isspace(*s))
1900 {
1901 s++;
1902 }
1903 if (*s == '\0')
1904 {
1905 break;
1906 }
1907
1908 /* get next name on line */
1909
1910 t = strchr(s, ',');
1911
1912 if (t)
1913 {
1914 *t = '\0';
1915 }
1916 else
1917 {
1918 t = strchr(s, '\n');
1919 if (t)
1920 {
1921 *t = '\0';
1922 }
1923 else
1924 {
1925 t = s + strlen(s) - 1;
1926 }
1927 }
1928
1929 names[num] = xcalloc(1, sizeof(NA));
1930
1931 /* UUCP address? */
1932
1933 if ((sp = strchr(s, '@')) != NULL)
1934 {
1935 names[num]->addr.fidonet = 0;
1936 if (sp == s)
1937 {
1938 names[num]->addr.bangpath = 1;
1939 }
1940 else
1941 {
1942 names[num]->addr.internet = 1;
1943 }
1944 names[num]->name = xstrdup(s);
1945 names[num]->addr.domain = xstrdup(s);
1946 }
1947 else
1948 {
1949 /* look for address */
1950
1951 sp = strchr(s, '!');
1952
1953 if (sp)
1954 {
1955 *sp = '\0';
1956 }
1957
1958 if (sp)
1959 {
1960 names[num]->addr = parsenode(++sp);
1961 names[num]->name = xstrdup(s);
1962 }
1963 else
1964 {
1965 names[num]->name = addr_lookup(s, &names[num]->addr);
1966
1967 /* UUCP address from alias? */
1968
1969 sp = strchr(names[num]->name, '@');
1970 if (sp != NULL)
1971 {
1972 names[num]->addr.fidonet = 0;
1973 if (sp == names[num]->name)
1974 {
1975 names[num]->addr.bangpath = 1;
1976 sp++;
1977 }
1978 else
1979 {
1980 names[num]->addr.internet = 1;
1981 sp = names[num]->name;
1982 }
1983 names[num]->addr.domain = xstrdup(sp);
1984 }
1985 }
1986 }
1987 s = ++t;
1988 num++;
1989 }
1990 }
1991 if (current->next)
1992 {
1993 current = current->next;
1994 }
1995 else
1996 {
1997 i = 0;
1998 while (names[i] != NULL)
1999 {
2000 if (names[i]->name)
2001 {
2002 release(names[i]->name);
2003 }
2004 if (names[i]->addr.domain)
2005 {
2006 release(names[i]->addr.domain);
2007 }
2008 release(names[i]);
2009 }
2010 return;
2011 }
2012
2013 s = current->text;
2014 m->text = current;
2015 release(current->prev->text);
2016 release(current->prev);
2017 current->prev = NULL;
2018 }
2019
2020 names[num] = NULL;
2021
2022 if (blind_cc == 0)
2023 {
2024 if (verbose_cc)
2025 {
2026 CreateVerboseCC(m, names);
2027 }
2028 else
2029 {
2030 CreateNormalCC(m, names);
2031 }
2032 }
2033
2034 i = 0;
2035
2036 release(m->msgid);
2037 k = MsgnToUid(CurArea.messages) + 1;
2038 m->new = 1;
2039
2040 while (names[i] != NULL)
2041 {
2042 release(m->isto);
2043 release(m->to.domain);
2044
2045 m->to = names[i]->addr;
2046
2047 if (names[i]->addr.domain)
2048 {
2049 m->to.domain = xstrdup(names[i]->addr.domain);
2050 }
2051
2052 if (names[i]->addr.internet || names[i]->addr.bangpath)
2053 {
2054 m->isto = construct_uucpname(m->to.domain);
2055 }
2056 else
2057 {
2058 m->isto = xstrdup(names[i]->name);
2059 }
2060
2061
2062 /* for *.msg bases - get the real msg num */
2063
2064 m->msgnum = k++;
2065 writemsg(m);
2066
2067 if (SW->savecc && !SW->rawcc)
2068 {
2069 m->attrib.killsent = 1;
2070 }
2071
2072 release(names[i]->name);
2073 release(names[i]->addr.domain);
2074 i++;
2075 }
2076
2077 scan_base = TRUE;
2078 }
2079
crosspost(msg * m)2080 static void crosspost(msg * m)
2081 {
2082 LINE *current;
2083 char *s, *t;
2084 char dfn[128];
2085 char *arean[128];
2086 unsigned int num = 0, i, k;
2087
2088 current = m->text;
2089 s = current->text;
2090
2091 arean[num] = xstrdup(CurArea.tag);
2092 num++;
2093
2094 while (current && *s && !strncmpi(s, "xc:", 3))
2095 {
2096 s += 3;
2097
2098 while (*s && m_isspace(*s))
2099 {
2100 s++;
2101 }
2102
2103 while (*s != '\0' && s != NULL)
2104 {
2105 t = strchr(s, ',');
2106 if (t)
2107 {
2108 *t = '\0';
2109 }
2110 else
2111 {
2112 t = strchr(s, '\n');
2113 if (t)
2114 {
2115 *t = '\0';
2116 }
2117 else
2118 {
2119 t = s + strlen(s) - 1;
2120 }
2121 }
2122 while (*s && m_isspace(*s))
2123 {
2124 s++;
2125 }
2126 arean[num] = xstrdup(strupr(s));
2127
2128 if (arean[num++] == NULL)
2129 {
2130 break;
2131 }
2132
2133 s = ++t;
2134 }
2135 if (current->next)
2136 {
2137 current = current->next;
2138 }
2139 else
2140 {
2141 i = 0;
2142 while (arean[i] != NULL)
2143 {
2144 release(arean[i++]);
2145 }
2146 return;
2147 }
2148 s = current->text;
2149 m->text = current;
2150
2151 if (current->prev->text)
2152 {
2153 release(current->prev->text);
2154 }
2155
2156 release(current->prev);
2157 current->prev = NULL;
2158 }
2159
2160 arean[num] = NULL;
2161
2162 if (strncmpi(s, "cc:", 3) != 0)
2163 {
2164 m->text = lineins(m->text);
2165 m->text->text = xstrdup("\n");
2166 current = m->text;
2167 i = 0;
2168 strcpy(dfn, " * Crossposted in area ");
2169
2170 while (arean[i] != NULL)
2171 {
2172 if (strlen(arean[i]) + 3 + strlen(dfn) >= SW->rm)
2173 {
2174 strcat(dfn, "\n");
2175 release(current->text);
2176 current->text = xstrdup(dfn);
2177 current = lineins(current->next);
2178 current->text = xstrdup("\n");
2179 strcpy(dfn, " ");
2180 }
2181 strcat(dfn, arean[i]);
2182 i++;
2183 if (arean[i] != NULL)
2184 {
2185 strcat(dfn, ", ");
2186 }
2187 }
2188
2189 if (*(current->text) == '\n')
2190 {
2191 release(current->text);
2192 strcat(dfn,"\n");
2193 current->text = xstrdup(dfn);
2194 }
2195 }
2196
2197 i = 0;
2198 while (arean[i] != NULL)
2199 {
2200 for (k = 0; k < SW->areas; k++)
2201 {
2202 if (arealist[k].tag && !stricmp(arean[i], arealist[k].tag))
2203 {
2204 break;
2205 }
2206 }
2207 if (k == SW->areas || !arealist[k].echomail)
2208 {
2209 release(arean[i]);
2210 i++;
2211 continue;
2212 }
2213 set_nongrouped_area(k);
2214 release(m->from.domain);
2215 m->from = CurArea.addr;
2216
2217 if (CurArea.addr.domain)
2218 {
2219 m->from.domain = xstrdup(CurArea.addr.domain);
2220 }
2221
2222 if (CurArea.status)
2223 {
2224 if (i > 0)
2225 {
2226 m->new = 1;
2227 }
2228
2229 if (m->new)
2230 {
2231 m->msgnum = MsgnToUid(CurArea.messages) + 1;
2232 }
2233
2234 if (strncmpi(s, "cc:", 3) == 0)
2235 {
2236 save(m);
2237 }
2238 else
2239 {
2240 writemsg(m);
2241 }
2242 }
2243 release(arean[i]);
2244 i++;
2245 }
2246 scan_base = TRUE; /* reopen the base when we get back */
2247 }
2248
spawn_command(char * cmdline)2249 static void spawn_command(char *cmdline)
2250 {
2251 #if defined(MSDOS) && !defined(NODOSSWAP) && !defined(__FLAT__)
2252 int rc;
2253 char swapfn[PATHLEN];
2254 char **envp = environ, **env, *envbuf, *envptr, *ep;
2255 int swapping = USE_ALL | HIDE_FILE | DONT_SWAP_ENV;
2256 int envlen = 0;
2257
2258 if (envp != NULL)
2259 {
2260 for (env = envp; *env != NULL; env++)
2261 {
2262 envlen += strlen(*env) + 1;
2263 }
2264 }
2265
2266 if (envlen)
2267 {
2268 envlen = (envlen + 32) & 0xfff0;
2269 envbuf = xmalloc(envlen);
2270 envptr = envbuf;
2271
2272 if (FP_OFF(envptr) & 0x0f)
2273 {
2274 envptr += 16 - (FP_OFF(envptr) & 0x0f);
2275 }
2276
2277 ep = envptr;
2278
2279 for (env = envp; *env != NULL; env++)
2280 {
2281 strcpy(ep, *env);
2282 ep = ep + strlen(*env) + 1;
2283 }
2284 *ep = 0;
2285 }
2286 if (ST->swap_path)
2287 {
2288 sprintf(swapfn, "%s\\%s", ST->swap_path, SWAP_FILENAME);
2289 }
2290 else
2291 {
2292 strcpy(swapfn, SWAP_FILENAME);
2293 }
2294
2295 rc = prep_swap(swapping, swapfn);
2296
2297 if (rc > -1)
2298 {
2299 rc = do_spawn(swapping, ST->comspec, cmdline, envlen, envptr);
2300 }
2301 else
2302 {
2303 fprintf(stderr, "\nError occured during do_spawn(); rc=%d. Press Enter to return...", rc);
2304 while (GetKey() != 13)
2305 {
2306 }
2307 }
2308 #else
2309 system(cmdline);
2310 #endif
2311 }
2312
externalEditor(msg * m)2313 static int externalEditor(msg * m)
2314 {
2315 FILE *fq;
2316 LINE *current;
2317 static char cmd[200];
2318 WND *hWnd, *hCurr;
2319 static char linebuf[1000];
2320 size_t linelen;
2321 int hardquote, linenum;
2322 static char tmpfnm[] = "msged.tmp";
2323 int doformat, statready;
2324 struct stat ostat, nstat;
2325
2326 doformat = SW->extformat;
2327 hardquote = 0;
2328 current = m->text;
2329 fq = fopen(tmpfnm, "w");
2330 if (fq != NULL)
2331 {
2332 while (current != NULL)
2333 {
2334 if (current->text != NULL)
2335 {
2336 fputs(current->text, fq);
2337 }
2338 current = current->next;
2339 }
2340 fclose(fq);
2341 statready = stat(tmpfnm, &ostat) == 0;
2342
2343 maxx = term.NCol;
2344 maxy = term.NRow;
2345
2346 hCurr = WndTop();
2347 hWnd = WndOpen(0, 0, term.NCol - 1, term.NRow - 1, NBDR, 0, cm[CM_NTXT]);
2348 WndCurr(hWnd);
2349 MouseOFF();
2350 cursor(1);
2351
2352 #if defined(MSDOS) && !defined(NODOSSWAP) && !defined(__FLAT__)
2353 sprintf(cmd, "/c %s %s", ST->editorName, tmpfnm);
2354 #else
2355 sprintf(cmd, "%s %s", ST->editorName, tmpfnm);
2356 #endif
2357 spawn_command(cmd);
2358
2359 cursor(0);
2360 MouseON();
2361 WndClose(hWnd);
2362 WndCurr(hCurr);
2363
2364 if (statready && stat(tmpfnm, &nstat) == 0 &&
2365 ostat.st_mtime == nstat.st_mtime && ostat.st_size == nstat.st_size)
2366 {
2367 /*
2368 * Old and new timestamps and file sizes are identical, so no
2369 * modifications were performed.
2370 */
2371 return ABORT;
2372 }
2373
2374 m->text = clearbuffer(m->text);
2375
2376 fq = fopen(tmpfnm, "r");
2377 if (fq != NULL)
2378 {
2379 linenum = 0;
2380 while (fgets(linebuf, sizeof linebuf, fq) != NULL)
2381 {
2382 linenum++;
2383 if (*(linebuf + strlen(linebuf) - 1) != '\n')
2384 {
2385 strcat(linebuf, "\n");
2386 }
2387 if (current == NULL)
2388 {
2389 m->text = xcalloc(1, sizeof(LINE));
2390 current = m->text;
2391 }
2392 else
2393 {
2394 current = InsertLine(current);
2395 }
2396 if (doformat)
2397 {
2398 if (!hardquote)
2399 {
2400 linelen = strlen(linebuf);
2401
2402 if (strcmp(linebuf, "<<\n") == 0)
2403 {
2404 /* begin temporary hardquoting */
2405 if (linenum == 1)
2406 {
2407 *linebuf = '\0';
2408 }
2409 else
2410 {
2411 strcpy(linebuf, "\n");
2412 }
2413 hardquote = 1;
2414 }
2415 else if (linebuf[linelen - 2] == '<' && linebuf[linelen - 3] == '<')
2416 {
2417 /*
2418 * The following checks for << at end of line
2419 * and replaces them with CR and \0.
2420 */
2421 linebuf[linelen - 3] = '\r';
2422 linebuf[linelen - 2] = '\0';
2423 }
2424 else
2425 {
2426 /*
2427 * If not a quote and not prefixed with a
2428 * 'special' character and greater than
2429 * width - 30? then remove CR
2430 */
2431
2432 if (linelen > term.NCol - 30 && !isquote(linebuf) &&
2433 !strchr("\01 !@#$%^&*~-_+=:;,./", *linebuf))
2434 {
2435 linebuf[linelen - 1] = '\0';
2436 }
2437 }
2438 }
2439 else
2440 {
2441 if (strcmp(linebuf, "<<\n") == 0)
2442 {
2443 /* end temporary hardquoting */
2444 strcpy(linebuf, "\n");
2445 hardquote = 0;
2446 }
2447 }
2448 }
2449 current->text = xstrdup(linebuf);
2450 }
2451 fclose(fq);
2452 }
2453 }
2454
2455 if (current == NULL)
2456 {
2457 return ABORT;
2458 }
2459
2460 return SAVE;
2461 }
2462
2463