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