home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / msq31004.zip / makemsgn.c < prev    next >
C/C++ Source or Header  |  1995-07-09  |  45KB  |  1,747 lines

  1. /* MakeMsg.c
  2. **
  3. ** released into the PUBLIC DOMAIN 30 jul 1990 by jim nutt
  4. ** Changes released into the PUBLIC DOMAIN 10 jul 1994 by John Dennis
  5. **
  6. ** Routines to create new messages.
  7. */
  8.  
  9. #include "msged.h"
  10. #include "date.h"
  11. #include "main.h"
  12. #include "menu.h"
  13. #include "keys.h"
  14. #include "nshow.h"
  15. #include "template.h"
  16.  
  17. #define TEXTLEN   128
  18. #define INPLEN    60
  19.  
  20. /* prototypes */
  21.  
  22. int                       EditHeader(msg *m);
  23. static void   reply_msg(int type);
  24. static void   crosspost(msg *m);
  25. void               clear_attributes(struct _attributes *);
  26. int                editmsg(msg *m, int quote);
  27. LINE *             clearbuffer(LINE *buffer);
  28. LINE *             InsertLine(LINE *current);
  29. ADDRESS            v7lookup(char *);
  30. char *             v7lookupnode(ADDRESS *faddr, char *name);
  31. static int externalEditor(msg *m);
  32.  
  33. extern int msgederr;
  34. extern int savecc;
  35.  
  36. static msg *EdMsg;                  /* message header being edited */
  37. static int  scan_base;              /* force a scan of the msgbase */
  38. int         do_lookup = FALSE;      /* lookup thru the nodelist? */
  39. static int     editRet;
  40.  
  41.  
  42. static int   sent_msg(void)
  43. {
  44.     int ret;
  45.  
  46.     ret = ChoiceBox(" Confirm ", "Message already sent, contine?", "Ok", "Cancel", NULL);
  47.  
  48.     if (ret == ID_ONE)
  49.         return 1;
  50.  
  51.     return 0;
  52. }
  53.  
  54.  
  55. /*
  56. **
  57. ** Creates a duplicate of the passed message header, allocating
  58. ** memory for it in the process.
  59. **
  60. */
  61.  
  62. #define copystr(d, s) {if (s) d = strdup(s); else d = NULL;}
  63.  
  64. msg *  duplicatemsg(msg *from)
  65. {
  66.     msg *to;
  67.  
  68.     if ((to = calloc(1, sizeof(msg))) == NULL)
  69.         return NULL;
  70.  
  71.     *to = *from;              /* copy all the bits */
  72.  
  73.     copystr(to->isfrom,      from->isfrom);
  74.     copystr(to->isto,        from->isto);
  75.     copystr(to->subj,        from->subj);
  76.     copystr(to->to.domain,   from->to.domain);
  77.     copystr(to->from.domain, from->from.domain);
  78.     copystr(to->msgid,       from->msgid);
  79.     copystr(to->reply,       from->reply);
  80.  
  81.     to->text = NULL;
  82.  
  83.     return to;
  84. }
  85.  
  86. void  newmsg(void)
  87. {
  88.     reply_msg(MT_NEW);
  89. }
  90.  
  91. void  reply(void)
  92. {
  93.     reply_msg(MT_REP);
  94. }
  95.  
  96. void  quote(void)
  97. {
  98.     reply_msg(SW->rquote);
  99. }
  100.  
  101. void  reply_oarea(void)
  102. {
  103.     reply_msg(SW->rotharea);
  104. }
  105.  
  106. void  followup(void)
  107. {
  108.     reply_msg(SW->rfollow);
  109. }
  110.  
  111. void  replyextra(void)
  112. {
  113.     reply_msg(SW->rextra);
  114. }
  115.  
  116. static void   reply_msg(int type)
  117. {
  118.     ADDRESS tmp;
  119.     msg    *hlink   = NULL;
  120.     msg    *m       = NULL;
  121.     unsigned long   t       = CurArea.current;
  122.     unsigned long   tl      = CurArea.lastread;
  123.     unsigned long   link    = t;
  124.     int     oarea   = SW->area;
  125.     int     q       = 0;
  126.     msg     *oldmsg;                   /* contains all the old information */
  127.     unsigned long   ulink;
  128.     int     toarea, i;
  129.  
  130.     scan_base = 0;
  131.     oldmsg    = NULL;
  132.     RefreshMsg(NULL, 6);
  133.  
  134.     if ((!(type & MT_NEW) && CurArea.messages == 0) || !CurArea.status)
  135.         return;
  136.  
  137.     if (type & MT_ARC)
  138.     {
  139.         toarea = selectarea();
  140.         if (msgederr)
  141.         {
  142.             if ((type & MT_ARC) || scan_base || CurArea.msgtype == SQUISH)
  143.                 set_area(oarea);
  144.             else
  145.             {
  146.                 CurArea.current = link;
  147.                 CurArea.messages++;
  148.                 CurArea.last++;
  149.             }
  150.             return;
  151.         }
  152.     }
  153.  
  154.     if (message)
  155.         oldmsg = duplicatemsg(message);
  156.  
  157.     if (CurArea.messages == 0 || message == NULL)
  158.         if ((message = calloc(1, sizeof(msg))) == NULL)
  159.             outamemory();
  160.  
  161.     ulink = message->msgnum;
  162.  
  163.     /* we work with m, not message - the set_area() function */
  164.     /* kills message automatically */
  165.  
  166.     m       = message;
  167.     message = NULL;
  168.  
  169.     if (type & MT_REP)
  170.         m->text = clearbuffer(m->text);
  171.  
  172.     if (type & MT_NEW)
  173.         clearmsg(m);
  174.  
  175.     if (type & MT_FOL)
  176.     {
  177.         release(m->msgid);
  178.         m->msgid = m->reply;
  179.         m->reply = NULL;
  180.     }
  181.  
  182. /* Uncomment the following code if you think there is a good
  183.    reason why a REPLYID should not be generated if you do a
  184.    cross-area reply */
  185. /*    if ((type & MT_ARC) && toarea != SW->area)
  186.         release(m->msgid); */
  187.  
  188.     release(m->reply);
  189.  
  190.     if (m->msgid)
  191.     {
  192.         m->reply = m->msgid;
  193.         m->msgid = NULL;
  194.     }
  195.  
  196.     if (type & MT_FOL)
  197.     {
  198.         release(m->isfrom);
  199.         tmp = m->to;
  200.     }
  201.     else
  202.     {
  203.         if (!(type & MT_NEW))
  204.         {
  205.             release(m->isto);
  206.             m->isto = m->isfrom;
  207.         }
  208.         else
  209.             m->to.zone = CurArea.addr.zone;
  210.         tmp = m->from;
  211.     }
  212.  
  213.     m->isfrom = strdup(ST->username);
  214.  
  215.     if (type & MT_ARC)
  216.     {
  217.         set_area(toarea);
  218.         if (!CurArea.status)
  219.         {
  220.             dispose(oldmsg);
  221.             dispose(m);
  222.             set_area(oarea);
  223.             return;
  224.         }
  225.     }
  226.  
  227.     do_lookup      = (CurArea.netmail) ? TRUE : FALSE;
  228.     m->to          = tmp;
  229.     m->timestamp   = time(NULL);
  230.     m->replyto     = 0;
  231.     m->new         = 1;
  232.     m->cost        = 0;
  233.     m->times_read  = 0;
  234.     m->scanned     = 0;
  235.     m->soteot      = 0;
  236.  
  237.     if (CurArea.echomail && CurArea.messages == 0)
  238.         m->msgnum = 2;
  239.     else
  240.         m->msgnum = MsgnToUid(CurArea.messages) + 1;
  241.  
  242.  
  243.     /* find a matching destination aka from the origin zone */
  244.  
  245.     if (!(type & MT_NEW) && m->to.zone != m->from.zone)
  246.     {
  247.         for (i = 0; i < SW->aliascount; i++)
  248.         {
  249.             if (alias[i].zone == m->to.zone)
  250.             {
  251.                 m->from = alias[i];
  252.                 if (alias[i].domain)
  253.                 {
  254.                     m->from.domain = strdup(alias[i].domain);
  255.                 }
  256.                 break;
  257.             }
  258.         }
  259.         if (i == SW->aliascount)         /* we didn't find anything */
  260.         {
  261.             m->from = CurArea.addr;
  262.             if (CurArea.addr.domain)
  263.                 m->from.domain = strdup(CurArea.addr.domain);
  264.         }
  265.     }
  266.     else
  267.     {                                    /* we aren't seaching */
  268.         m->from = CurArea.addr;
  269.         if (CurArea.addr.domain)
  270.             m->from.domain = strdup(CurArea.addr.domain);
  271.     }
  272.  
  273.     if (!(type & MT_NEW) && !(type & MT_ARC))
  274.         m->replyto = link;
  275.     else
  276.         m->replyto = 0;
  277.  
  278.     clear_attributes(&m->attrib);
  279.     memset(&m->replies, 0, sizeof(m->replies));
  280.  
  281.     while (!q)
  282.     {
  283.         if (EditHeader(m) == Key_Esc)
  284.         {
  285.             if (confirm())
  286.             {
  287.                 dispose(oldmsg);
  288.                 dispose(m);
  289.  
  290.                 if (type & MT_ARC)
  291.                     set_area(oarea);
  292.  
  293.                 if (CurArea.status)
  294.                 {
  295.                     CurArea.current  = (t)  ? t  : CurArea.current;
  296.                     CurArea.lastread = (tl) ? tl : CurArea.lastread;
  297.                 }
  298.                 return;
  299.             }
  300.         }
  301.         else
  302.             q = 1;
  303.     }
  304.  
  305.     /*
  306.     ** Create the template for the message.
  307.     */
  308.  
  309.     MakeTemplateMsg(m, oldmsg, oarea, type|MT_NEW);
  310.  
  311.     if (ST->editorName != NULL)
  312.     {
  313.         editRet = externalEditor(m);
  314.     }
  315.     else
  316.     {
  317.         editRet = editmsg(m, ((type & MT_NEW)||(type & MT_REP))?0:1);
  318.     }
  319.     switch (editRet)
  320.     {
  321.         case SAVE:
  322.             save(m);
  323.             if (!(type & MT_ARC) && !(type & MT_NEW))
  324.             {
  325.                 link = UidToMsgn(ulink);
  326.                 if ((hlink = MsgReadHeader(link, RD_HEADER)) != NULL)
  327.                 {
  328.                     if (CurArea.msgtype == FIDO)
  329.                     {
  330.                         hlink->replies[0] = UidToMsgn(m->msgnum);
  331.                     }
  332.                     MsgWriteHeader(hlink, WR_HEADER);
  333.                     dispose(hlink);
  334.                 }
  335.             }
  336.             break;
  337.  
  338.         case ABORT:
  339.             scan_base = 1;
  340.             break;
  341.     }
  342.  
  343.     dispose(oldmsg);
  344.     dispose(m);
  345.  
  346.     if ((type & MT_ARC) || scan_base || CurArea.msgtype == SQUISH)
  347.     {
  348.         set_area(oarea);
  349.         CurArea.current = link; 
  350.     }
  351.     else
  352.     {
  353.         CurArea.current = link;
  354.         CurArea.messages++;
  355.         CurArea.last++;
  356.     }
  357. }
  358.  
  359.  
  360. void  change(void)
  361. {
  362.     int q  = 0;
  363.     unsigned long t = CurArea.current;
  364.  
  365.     if (CurArea.messages == 0 || !CurArea.status || !message)
  366.         return;
  367.  
  368.     if (message->attrib.sent || message->scanned)
  369.     {
  370.         if (!sent_msg())
  371.             return;
  372.     }
  373.  
  374.     message->attrib.sent   = 0;
  375.     message->attrib.orphan = 0;
  376.     message->attrib.local  = 1;
  377.     message->scanned       = 0;
  378.     message->change        = 1;
  379.     do_lookup              = FALSE;
  380.  
  381.     while (!q)
  382.     {
  383.         if (EditHeader(message) == Key_Esc)
  384.         {
  385.             if (confirm())
  386.             {
  387.                 CurArea.current = (t) ? t : CurArea.current;
  388.                 return;
  389.             }
  390.         }
  391.         else
  392.             q = 1;
  393.     }
  394.  
  395.     if (ST->editorName != NULL)
  396.     {
  397.         editRet = externalEditor(message);
  398.     }
  399.     else
  400.     {
  401.         editRet = editmsg(message, FALSE);
  402.     }
  403.     switch (editRet)
  404.     {
  405.         case SAVE:
  406.             save(message);
  407.             break;
  408.  
  409.         case ABORT:
  410.             break;
  411.     }
  412.     CurArea.current = (t) ? t : CurArea.current;
  413.     message = KillMsg(message);
  414. }
  415.  
  416.  
  417.  
  418. int ChangeAttrib(msg *m)
  419. {
  420.     WND *hWnd, *hCurr;
  421.     int  ch, done = 0;
  422.  
  423.     hCurr = Wtop();
  424.     hWnd  = WPopUp(40, 11, SBDR|SHADOW, cm[IN_BTXT], cm[IN_NTXT]);
  425.  
  426.                            /* put up some help for the befuddled user */
  427.  
  428.     WTitle(" Message Attributes ", cm[IN_NTXT]);
  429.  
  430.     WWriteStr(2, 1, cm[IN_NTXT], " P : Private      C : Crash");
  431.     WWriteStr(2, 2, cm[IN_NTXT], " A : Attached     K : Kill/Sent");
  432.     WWriteStr(2, 3, cm[IN_NTXT], " H : Hold         D : Direct");
  433.     WWriteStr(2, 4, cm[IN_NTXT], " S : Sent         R : Received");
  434.     WWriteStr(2, 5, cm[IN_NTXT], " O : Orphan       F : File Request");
  435.     WWriteStr(2, 6, cm[IN_NTXT], " E : Return Rcpt  Q : Ret Rcpt Req");
  436.     WWriteStr(2, 7, cm[IN_NTXT], " I : Audit Trail  U : Update freq");
  437.     WWriteStr(2, 8, cm[IN_NTXT], " L : Local");
  438.  
  439.     WCurr(hCurr);          /* make parent window active so we can write to it */
  440.  
  441.     ShowAttrib(m);
  442.  
  443.     while (!done)
  444.     {
  445.         ch = GetKey();
  446.         switch (ch)
  447.         {
  448.             case Key_Up:
  449.             case Key_Dwn:
  450.             case Key_Ent:
  451.             case Key_Esc:
  452.                 done = 1;           /* we return these to the caller */
  453.                 break;
  454.  
  455.             default:
  456.                 switch((toupper(ch & 0xff)))
  457.                 {
  458.                     case 'A': m->attrib.attached ^= 1; break;
  459.                     case 'P': m->attrib.private  ^= 1; break;
  460.                     case 'C': m->attrib.crash    ^= 1; break;
  461.                     case 'U': m->attrib.ureq     ^= 1; break;
  462.                     case 'F': m->attrib.freq     ^= 1; break;
  463.                     case 'K': m->attrib.killsent ^= 1; break;
  464.                     case 'H': m->attrib.hold     ^= 1; break;
  465.                     case 'D': m->attrib.direct   ^= 1; break;
  466.                     case 'Q': m->attrib.rreq     ^= 1; break;
  467.                     case 'E': m->attrib.rcpt     ^= 1; break;
  468.                     case 'R': m->attrib.recvd    ^= 1; break;
  469.                     case 'S': m->attrib.sent     ^= 1; break;
  470.                     case 'O': m->attrib.orphan   ^= 1; break;
  471.                     case 'I': m->attrib.areq     ^= 1; break;
  472.                     case 'L': m->attrib.local    ^= 1; break;
  473.                     default : break;
  474.                 }
  475.         }
  476.         ShowAttrib(m);
  477.     }
  478.  
  479.     WCurr(hWnd);
  480.     WClose(hWnd);
  481.     WCurr(hCurr);
  482.     return ch;                    /* pass the exit key back to caller */
  483. }
  484.  
  485.  
  486. /* looks up the alias list and returns the new name, and changes the passed  */
  487. /* address to the alias addres, if the passed name had a corresponding alias */
  488.  
  489. char *   alias_lookup(ADDRESS *addr, char *isto)
  490. {
  491.     int l;
  492.     char *name;
  493.  
  494.     /* search for a matching alias */
  495.  
  496.     for (l = 0; l < SW->otheraliases; l++)
  497.     {
  498.         if (!stricmp(aliaslist[l].alias,isto))
  499.             break;
  500.     }
  501.  
  502.     if (l >= SW->otheraliases)
  503.     {
  504.         return NULL;
  505.     }
  506.     else
  507.     {
  508.         name = strdup(aliaslist[l].name);
  509.  
  510.         if (aliaslist[l].addr.internet == 1)
  511.         {
  512.             *addr        = uucp_gate;
  513.             addr->domain = NULL;
  514.         }
  515.         else
  516.         {
  517.             *addr = aliaslist[l].addr;
  518.             if (aliaslist[l].addr.domain)
  519.                 addr->domain = strdup(aliaslist[l].addr.domain);
  520.             else
  521.                 addr->domain = NULL;
  522.         }
  523.     }
  524.     return name;
  525. }
  526.  
  527.  
  528. /* looks up the alias list to see if the passed alias has a subject */
  529.  
  530. char *   subj_lookup(char *isto)
  531. {
  532.     int l;
  533.     char *subj;
  534.  
  535.     for (l = 0; l < SW->otheraliases; l++)
  536.     {
  537.         if (!stricmp(aliaslist[l].alias, isto))
  538.             break;
  539.     }
  540.  
  541.     if (l >= SW->otheraliases || aliaslist[l].subj == NULL)
  542.     {
  543.         return NULL;
  544.     }
  545.  
  546.     subj = strdup(aliaslist[l].subj);
  547.  
  548.     return subj;
  549. }
  550.  
  551.  
  552. /*
  553. ** Looks up name and addresses using alias, nodelist and fido userlist
  554. ** methods.  Returns a pointer to allocated memory containing the name
  555. ** to be used, and writes to the passed address variable.
  556. **
  557. ** Modifications by: Roland Gautschi (v7 lookup code - added flexibility).
  558. */
  559.  
  560. char *  addr_lookup(char *name, ADDRESS *tmp)
  561. {
  562.     char *nname = NULL;
  563.     char  xname[73];
  564.     char  namefound[73];
  565.     int   ret;
  566.     
  567.     tmp->fidonet  = 1;
  568.     tmp->internet = 0;
  569.     tmp->bangpath = 0;
  570.     
  571.     if ((nname = alias_lookup(tmp, name)) == NULL)
  572.     {
  573.         nname = strdup(name);         /* couldn't find an alias, so.. */
  574.         strcpy(xname, name);          /* make a copy, just in case */
  575.  
  576.         if (do_lookup)
  577.         {
  578.             /*
  579.             ** Userlists are checked first, because they may have
  580.             ** overides wanted by the user.
  581.             */
  582.  
  583.             if (ST->fidolist != NULL)      /* we check the fidolist(s) */
  584.             {    
  585.                 *tmp = lookup(name, ST->fidolist);
  586.                 if ((tmp->notfound) && (ST->userlist != NULL))
  587.                 {
  588.                     *tmp = lookup(name, ST->userlist);
  589.                 }
  590.             }
  591.             else
  592.             {
  593.                 tmp->notfound = 1;
  594.             }
  595.  
  596.             if (tmp->notfound == 1 && ST->nodepath != NULL) /* try v7 elsewise */
  597.             {
  598.                 /*
  599.                 ** Check to see if an address has been entered.
  600.                 */
  601.  
  602.                 if (isdigit(xname[0]) || xname[0] ==':' || xname[0] =='/' || xname[0] =='.')
  603.                 {
  604.                     *tmp = parsenode(xname);
  605.                     if (tmp->notfound == 0)
  606.                     {
  607.                         if (v7lookupnode(tmp, xname) == NULL)
  608.                             tmp->notfound = 1;
  609.                         else
  610.                         {
  611.                             free(nname);
  612.                             nname = strdup(xname);
  613.                         }
  614.                     }
  615.                 }
  616.  
  617.                 /*
  618.                 ** If the node still hasn't been found, then
  619.                 ** lookup normally (using the entered name).
  620.                 */
  621.  
  622.                 if (tmp->notfound == 1)
  623.                 {
  624.                     *tmp = v7lookup(xname);
  625.  
  626.                     /*
  627.                     ** If we found something, copy it.
  628.                     */
  629.  
  630.                     if (tmp->notfound == 0)
  631.                     {
  632.                         if (strcmp(nname, xname) != 0)
  633.                         {
  634.                             sprintf(namefound, "%s at %s found, change?", xname, show_address(tmp));
  635.                             ret = ChoiceBox(" Change Name ", namefound, "Yes", "No", NULL);
  636.                             if (ret == ID_ONE)
  637.                             {
  638.                                 free(nname);
  639.                                 nname = strdup(xname);
  640.                             }
  641.                         }
  642.                     }
  643.                 }
  644.             }
  645.         }
  646.     }
  647.     return nname;
  648. }
  649.  
  650. void GetAddress(ADDRESS *addr, char *from, char *subj)
  651. {
  652.     char *name, *str;
  653.  
  654.     if (strlen(from) != 0)
  655.     {
  656.         do_lookup = (CurArea.netmail) ?  1 : 0;
  657.         name      = addr_lookup(from, addr);
  658.  
  659.         /*
  660.         ** Check for an Alias subject.
  661.         */
  662.  
  663.         if ((str = subj_lookup(from)) != NULL)
  664.         {
  665.             strcpy(subj, str);
  666.             release(str);
  667.         }
  668.  
  669.         /*
  670.         ** Check the name to see if it's a usenet message.
  671.         */
  672.  
  673.         if ((str = strchr(name, '@')) != NULL)
  674.         {
  675.             addr->fidonet  = 0;
  676.             addr->notfound = 0;
  677.             if (str == name)
  678.             {
  679.                 addr->bangpath = 1; str++;
  680.             }
  681.             else
  682.             {
  683.                 addr->internet = 1; str = name;
  684.             }
  685.             release(addr->domain);
  686.             addr->domain = strdup(str);
  687.         }
  688.         else
  689.         {
  690.             strcpy(from, name);
  691.         }
  692.         release(name);
  693.     }
  694. }
  695.  
  696. int ChangeName(ADDRESS *addr, char *from, char *subj, int y)
  697. {
  698.     EVT  e;
  699.     char tmp[70], tmp2[70];
  700.     int  ch, pos, done = 0, disp = 1;
  701.  
  702.     strcpy(tmp2, subj);
  703.     if (addr->internet)
  704.         strncpy(tmp, addr->domain, sizeof tmp - 1);
  705.     else
  706.     {
  707.         if (addr->bangpath)
  708.             strncat(strcpy(tmp,"@"), addr->domain, sizeof tmp - 1);
  709.         else
  710.         {
  711.             strncpy(tmp, from, sizeof tmp - 1);
  712.         }
  713.     }
  714.  
  715.     pos = strlen(tmp);
  716.  
  717.     while (!done)
  718.     {
  719.         if (addr->bangpath || addr->internet || CurArea.news || CurArea.uucp)
  720.             ch = WGetLine(7, y, 52, tmp, cm[CM_ETXT], &pos, disp, 0, disp, &e);
  721.         else
  722.             ch = WGetLine(7, y, 36, tmp, cm[CM_ETXT], &pos, disp, 0, disp, &e);
  723.  
  724.         switch (e.msgtype)
  725.         {
  726.             case WM_CHAR:
  727.                 switch (ch)
  728.                 {
  729.                     case Key_Esc:
  730.                         done = 1;
  731.                         break;
  732.  
  733.                     case Key_Up:
  734.                     case Key_Dwn:
  735.                     case Key_Rgt:
  736.                     case Key_Lft:
  737.                     case Key_Ent:
  738.                         if (strcmp(from, tmp))
  739.                         {
  740.                             if (addr->fidonet)
  741.                             {
  742.                                 if (strlen(tmp) > 36)
  743.                                     tmp[35] = '\0';
  744.                             }
  745.                             GetAddress(addr, tmp, tmp2);
  746.                             strcpy(from, tmp);
  747.                             if (strcmp(subj, tmp2))
  748.                             {
  749.                                 strcpy(subj, tmp2);
  750.                                 ShowSubject(subj);
  751.                             }
  752.                         }
  753.                         done = 1;
  754.                         break;
  755.                     default:
  756.                         break;
  757.                 }
  758.                 break;
  759.  
  760.             default:
  761.                 break;
  762.         }
  763.         disp = 0;
  764.     }
  765.     return ch;
  766. }
  767.  
  768. int ChangeAddress(ADDRESS *addr, int y, int nm_len)
  769. {
  770.     EVT  e;
  771.     char tmp[41];
  772.     int  ch, pos, done = 0, disp = 1;
  773.  
  774.     strncpy(tmp, show_address(addr), 40);
  775.     release(addr->domain);
  776.  
  777.     pos = strlen(tmp);
  778.  
  779.     while (!done)
  780.     {
  781.         ch = WGetLine(7 + nm_len + 2, y, 50 - nm_len, tmp, cm[CM_ETXT], &pos, disp, 0, disp, &e);
  782.  
  783.         switch (e.msgtype)
  784.         {
  785.             case WM_CHAR:
  786.                 switch (ch)
  787.                 {
  788.                     case Key_Esc:
  789.                         done = 1;
  790.                         break;
  791.  
  792.                     case Key_Up:
  793.                     case Key_Dwn:
  794.                     case Key_Rgt:
  795.                     case Key_Lft:
  796.                     case Key_Ent:
  797.                         *addr = parsenode(tmp);
  798.                         done  = 1;
  799.                         break;
  800.                     default:
  801.                         break;
  802.                 }
  803.                 break;
  804.  
  805.             default:
  806.                 break;
  807.         }
  808.         disp = 0;
  809.     }
  810.     return ch;
  811. }
  812.  
  813. int ChangeSubject(char *subj)
  814. {
  815.     EVT e;
  816.     struct _dta fileinfo;
  817.     char tmp[73];
  818.     int  ch, pos, ch2, done = 0, disp = 1;
  819.  
  820.     strncpy(tmp, subj, sizeof tmp - 1);
  821.  
  822.     pos = strlen(tmp);
  823.  
  824.     while (!done)
  825.     {
  826.         ch = WGetLine(7, 3, 72, tmp, cm[CM_ETXT], &pos, disp, 0, disp, &e);
  827.  
  828.         switch (e.msgtype)
  829.         {
  830.             case WM_CHAR:
  831.                 switch (ch)
  832.                 {
  833.                     case Key_Esc:
  834.                         done = 1;
  835.                         break;
  836.  
  837.                     case Key_Up:
  838.                     case Key_Dwn:
  839.                     case Key_Rgt:
  840.                     case Key_Lft:
  841.                     case Key_Ent:
  842.                         strcpy(subj, tmp);
  843.                         if (strlen(subj) > 3 && *(subj + 1) == ':' && (*(subj + 2) == '\\' || *(subj + 2) == '/'))
  844.                         {
  845.                             /*
  846.                             ** If the file doesn't exist, then ask if user wants
  847.                             ** to continue...
  848.                             */
  849.  
  850.                             if(dir_findfirst(subj, 0, &fileinfo) != 0)
  851.                             {
  852.                                 ch2 = ChoiceBox(" File? ",
  853.                                                 "File doesn't exist! Attach anyway?",
  854.                                                 "Yes",
  855.                                                 "No",
  856.                                                 NULL);
  857.  
  858.                                 if (ch2 == ID_ONE)
  859.                                 {
  860.                                     EdMsg->attrib.attached = 1;
  861.                                 }
  862.                                 else
  863.                                 {
  864.                                     /*
  865.                                     ** Continue editing..
  866.                                     */
  867.  
  868.                                     continue;
  869.                                 }
  870.                             }
  871.                             else
  872.                                 EdMsg->attrib.attached = 1;
  873.                         }
  874.                         done = 1;
  875.                         break;
  876.                     default:
  877.                         break;
  878.                 }
  879.                 break;
  880.  
  881.             default:
  882.                 break;
  883.         }
  884.         disp = 0;
  885.     }
  886.     ShowSubject(subj);
  887.     return ch;
  888. }
  889.  
  890. static char *getstring(char *buf)
  891. {
  892.     if (strlen(buf) > 0)
  893.         return strdup(buf);
  894.     else
  895.         return NULL;
  896. }
  897.  
  898. #define FD_FROM   0
  899. #define FD_FADD   1
  900. #define FD_TO     2
  901. #define FD_TADD   3
  902. #define FD_SUBJ   4
  903. #define FD_ATTR   5
  904.  
  905. int EditHeader(msg *m)
  906. {
  907.     char tmp[80], tmp2[80];
  908.     int  field = 2;
  909.     int  ch, done = 0;
  910.  
  911.     /*
  912.     ** This is naughty, but it allows the functions to
  913.     ** access the current message in those special cases.
  914.     */
  915.  
  916.     EdMsg = m;
  917.  
  918.     ShowMsgHeader(m);
  919.  
  920.     while (!done)
  921.     {
  922.         strcpy(tmp,  "");
  923.         strcpy(tmp2, "");
  924.  
  925.         switch (field)
  926.         {
  927.             case FD_FROM:
  928.                 if (m->isfrom)
  929.                 {
  930.                     strcpy(tmp,  m->isfrom);
  931.                     free(m->isfrom);
  932.                 }
  933.                 if (m->subj)
  934.                 {
  935.                     strcpy(tmp2, m->subj);
  936.                     free(m->subj);
  937.                 }
  938.                 ShowNameAddress(m->isfrom, &m->from, 1, 0, 1);
  939.                 ch = ChangeName(&m->from, tmp, tmp2, 1);
  940.                 m->isfrom = getstring(tmp);
  941.                 m->subj   = getstring(tmp2);
  942.                 ShowNameAddress(m->isfrom, &m->from, 1, 0, 1);
  943.                 break;
  944.  
  945.             case FD_FADD:
  946.                 if (CurArea.netmail && m->from.fidonet)
  947.                 {
  948.                     ch = ChangeAddress(&m->from, 
  949.                                        1, 
  950.                                        (m->isfrom) ? strlen(m->isfrom) : 0);
  951.                 }
  952.                 ShowNameAddress(m->isfrom, &m->from, 1, 0, 0);
  953.                 break;
  954.  
  955.             case FD_TO:
  956.                 if (CurArea.news)
  957.                 {
  958.                     release(m->isto);
  959.                     m->isto = strdup("All");
  960.                     m->to   = uucp_gate;
  961.                     ShowNameAddress(m->isto, &m->to, 2, 0, 1);
  962.                     ch = Key_Dwn;
  963.                     break;
  964.                 }
  965.                 else
  966.                 {
  967.                     if (m->isto)
  968.                     {
  969.                         strcpy(tmp,  m->isto);
  970.                         free(m->isto);
  971.                     }
  972.                     if (m->subj)
  973.                     {
  974.                         strcpy(tmp2, m->subj);
  975.                         free(m->subj);
  976.                     }
  977.                     ShowNameAddress(m->isto, &m->to, 2, 0, 1);
  978.                     ch = ChangeName(&m->to, tmp, tmp2, 2);
  979.                     m->isto = getstring(tmp);
  980.                     m->subj = getstring(tmp2);
  981.                     ShowNameAddress(m->isto, &m->to, 2, 0, 1);
  982.                 }
  983.                 break;
  984.  
  985.             case FD_TADD:
  986.                 if (CurArea.netmail && m->to.fidonet)
  987.                 {
  988.                     ch = ChangeAddress(&m->to, 
  989.                                        2, 
  990.                                        (m->isto) ? strlen(m->isto) : 0);
  991.                 }
  992.                 ShowNameAddress(m->isto, &m->to, 2, 0, 0);
  993.                 break;
  994.  
  995.             case FD_SUBJ:
  996.                 if (m->subj)
  997.                 {
  998.                     strcpy(tmp, m->subj);
  999.                     free(m->subj);
  1000.                 }
  1001.                 ch = ChangeSubject(tmp);
  1002.                 m->subj = getstring(tmp);
  1003.                 break;
  1004.  
  1005.             case FD_ATTR:
  1006.                 ch = ChangeAttrib(m);
  1007.                 break;
  1008.  
  1009.             default:
  1010.                 break;
  1011.         }
  1012.  
  1013.         if (ch == Key_Esc)
  1014.         {
  1015.             return ch;
  1016.         }
  1017.         else if (ch == Key_Up)
  1018.         {
  1019.             field--;
  1020.  
  1021.             if (field < 0)
  1022.                 field = 5;
  1023.  
  1024.             /*
  1025.             ** Handle the cases where going up stuffs the address showing.
  1026.             */
  1027.  
  1028.             switch (field)
  1029.             {
  1030.                 case FD_FADD:
  1031.                     ShowNameAddress(m->isto, &m->to, 2, 0, 0);
  1032.                     break;
  1033.                 case FD_ATTR:
  1034.                     ShowNameAddress(m->isfrom, &m->from, 1, 0, 0);
  1035.                     break;
  1036.                 default:
  1037.                     break;
  1038.             }
  1039.         }
  1040.         else if (ch == Key_Dwn || ch == Key_Ent)
  1041.         {
  1042.             if ((field == 5) && (ch == Key_Ent))
  1043.                 break;
  1044.  
  1045.             field++;
  1046.  
  1047.             if (field > 5)
  1048.                 field = 0;
  1049.  
  1050.             continue;
  1051.         }
  1052.     }
  1053.     if (m->to.internet || m->to.bangpath)
  1054.     {
  1055.         release(m->isto);
  1056.         m->isto = strdup(ST->uucpgate);
  1057.     }
  1058.     if (m->from.internet || m->from.bangpath)
  1059.     {
  1060.         release(m->isfrom);
  1061.         m->isfrom = strdup(ST->uucpgate);
  1062.     }
  1063.  
  1064.     ShowMsgHeader(m);        /* show the entire header */
  1065.     cursor(0);               /* turn the cursor off */
  1066.  
  1067.     return 0;
  1068. }
  1069.  
  1070.  
  1071. /* Clears all the attributes of a message, leaving Local set to TRUE */
  1072. /* not static; is called from maintmsg.c module                      */
  1073.  
  1074. void  clear_attributes(struct _attributes * h)
  1075. {
  1076.     h->recvd  = h->sent = h->attached = h->forward = h->orphan = 0;
  1077.     h->freq   = h->rreq = h->rcpt     = h->areq    = h->ureq   = 0;
  1078.  
  1079. #ifdef TURBOFIX  /* fix bug in TC++ */
  1080.     memset(h, '\0', sizeof *h); 
  1081. #endif    
  1082.     h->crash    = CurArea.crash;
  1083.     h->private  = (h->private) ? h->private : CurArea.priv;
  1084.     h->killsent = CurArea.killsent;
  1085.     h->hold     = CurArea.hold;
  1086.     h->direct   = CurArea.direct;
  1087.     h->local    = 1;
  1088. }
  1089.  
  1090.  
  1091. /* Contains the name and address of the recipient of the message */
  1092.  
  1093. typedef struct {
  1094.     char *name;
  1095.     ADDRESS addr;
  1096. } NA;
  1097.  
  1098. static void CreateNormalCC(msg *m, NA *names[])
  1099. {
  1100.     LINE *current;
  1101.     char dfn[256];
  1102.  
  1103.     int i = 0;
  1104.  
  1105.     m->text       = insline(m->text);
  1106.     m->text->text = strdup("\n");
  1107.     m->text       = insline(m->text);
  1108.  
  1109.     sprintf(dfn, "* Original to: %s at %s\n", names[i]->name, show_address(&names[i]->addr));
  1110.  
  1111.     i++;
  1112.  
  1113.     m->text->text = strdup(dfn);
  1114.  
  1115.     strcpy(dfn, "      CC'd to: ");
  1116.  
  1117.     current       = m->text;
  1118.     current       = insline(current->next);
  1119.     current->text = strdup("\n");
  1120.  
  1121.     while (names[i] != NULL)
  1122.     {
  1123.         if (strlen(names[i]->name) + strlen(dfn) >= SW->rm)
  1124.         {
  1125.             strcat(dfn,"\n");
  1126.             release(current->text);
  1127.  
  1128.             current->text = strdup(dfn);
  1129.             current       = insline(current->next);
  1130.             current->text = strdup("\n");
  1131.  
  1132.             strcpy(dfn, "               ");
  1133.         }
  1134.  
  1135.         strcat(dfn,names[i]->name);
  1136.  
  1137.         /* We want the address to appear in the list instead of "UUCP", so */
  1138.         /* we only put in the "UUCP" when we're finished with the address. */
  1139.  
  1140.         if (strchr(names[i]->name,'@') != NULL)
  1141.         {
  1142.             release(names[i]->name);
  1143.             names[i]->name = strdup(ST->uucpgate);
  1144.         }
  1145.  
  1146.         i++;
  1147.  
  1148.         if (names[i] != NULL)
  1149.             strcat(dfn,", ");
  1150.     }
  1151.  
  1152.     if (*(current->text) == '\n')
  1153.     {
  1154.         release(current->text);
  1155.         current->text = strdup(dfn);
  1156.     }
  1157. }
  1158.  
  1159. static void CreateVerboseCC(msg *m, NA *names[])
  1160. {
  1161.     int  i = 0;
  1162.     char dfn[256];
  1163.  
  1164.     m->text       = insline(m->text);
  1165.     m->text->text = strdup("\n");
  1166.  
  1167.     while (names[i] != NULL)
  1168.     {
  1169.         if (strchr(names[i]->name,'@') == NULL)
  1170.             sprintf(dfn, "     %s at %s\n", names[i]->name, show_address(&names[i]->addr));
  1171.         else
  1172.             sprintf(dfn, "     %s\n", names[i]->name);
  1173.  
  1174.         m->text       = insline(m->text);
  1175.         m->text->text = strdup(dfn);
  1176.  
  1177.         /* We want the address to appear in the list instead of "UUCP", so */
  1178.         /* we only put in the "UUCP" when we're finished with the address. */
  1179.  
  1180.         if (strchr(names[i]->name,'@') != NULL)
  1181.         {
  1182.             release(names[i]->name);
  1183.             names[i]->name = strdup(ST->uucpgate);
  1184.         }
  1185.  
  1186.         i++;
  1187.     }
  1188.     m->text       = insline(m->text);
  1189.     m->text->text = strdup(" * Message was CC:'d to:\n");
  1190. }
  1191.  
  1192.  
  1193. /*
  1194. **
  1195. ** Gets the CC:s from a response file.
  1196. **
  1197. **
  1198. */
  1199.  
  1200. static void  GetFileCCs(char *file, NA *names[], int *idx)
  1201. {
  1202.     FILE *fp;
  1203.     char  buf[256];
  1204.     char *s, *c, *t;
  1205.     int   i;
  1206.  
  1207.     i = *idx;
  1208.  
  1209.     if ((fp = fopen(file, "r")) == NULL)
  1210.         return;
  1211.  
  1212.     while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
  1213.     {
  1214.         s = buf;
  1215.         while (*s && isspace(*s)) s++;
  1216.  
  1217.         if (!*s || *s == ';')
  1218.             continue;
  1219.  
  1220.         t = s + strlen(s) - 1;
  1221.         while (t > s && isspace(*t)) t--;
  1222.  
  1223.         if (t == s)
  1224.             continue;
  1225.         else
  1226.         {
  1227.             if (*(t + 1))
  1228.                 t++;
  1229.  
  1230.             *t = '\0';
  1231.         }
  1232.  
  1233.         names[i] = calloc(1, sizeof(NA));
  1234.         if (names[i] == NULL)
  1235.             break;
  1236.  
  1237.         if ((c = strchr(s, '@')) != NULL)
  1238.         {
  1239.             /*
  1240.             ** Then we have an internet/bangpath.
  1241.             */
  1242.  
  1243.             names[i]->addr.fidonet = 0;
  1244.             if (c == s)
  1245.             {
  1246.                 names[i]->addr.bangpath = 1;
  1247.                 c++;
  1248.             }
  1249.             else
  1250.             {
  1251.                 names[i]->addr.internet = 1;
  1252.                 c = s;
  1253.             }
  1254.             names[i]->name        = strdup(c);
  1255.             names[i]->addr.domain = strdup(c);
  1256.         }
  1257.         else
  1258.         {
  1259.             c = strchr(s, '!');
  1260.  
  1261.             if (c)
  1262.             {
  1263.                 *c = '\0';
  1264.                 names[i]->addr = parsenode(++c);
  1265.                 names[i]->name = strdup(s);
  1266.             }
  1267.             else
  1268.             {
  1269.                 names[i]->name = addr_lookup(s, &names[i]->addr);
  1270.  
  1271.                 /*
  1272.                 ** UUCP address from alias?
  1273.                 */
  1274.  
  1275.                 if ((c = strchr(names[i]->name,'@')) != NULL)
  1276.                 {
  1277.                     names[i]->addr.fidonet = 0;
  1278.                     if (c == names[i]->name)
  1279.                     {
  1280.                         names[i]->addr.bangpath = 1;
  1281.                         c++;
  1282.                     }
  1283.                     else
  1284.                     {
  1285.                         names[i]->addr.internet = 1;
  1286.                         c = names[i]->name;
  1287.                     }
  1288.                     names[i]->addr.domain = strdup(c);
  1289.                 }
  1290.             }
  1291.         }
  1292.         if (names[i]->addr.notfound)
  1293.         {
  1294.             names[i]->addr = CurArea.addr;
  1295.             if (CurArea.addr.domain)
  1296.                 names[i]->addr.domain = strdup(CurArea.addr.domain);
  1297.         }
  1298.         i++;
  1299.     }
  1300.     names[i] = NULL;
  1301.     *idx     = i;
  1302.     fclose(fp);
  1303. }
  1304.  
  1305. /*
  1306. ** Saves a message,  if the the first line does not contain "cc:" or "xc:".
  1307. ** Else it continues and either makes a Carbon Copy(s) of the message or
  1308. ** Crosspost(s) of the message.
  1309. **
  1310. ** The idea here is:  first get the addresses from the cc: list, if there
  1311. ** IS one (if not, check for xc: & leave).  If so, we then make up the text
  1312. ** for the message (in a loop), then we go and save the messages using the
  1313. ** names and addresses from the cc list. Fairly involved...
  1314. */
  1315.  
  1316. void  save(msg *m)
  1317. {
  1318.     LINE  *current;
  1319.     NA    *names[128];
  1320.     int    num = 1, i;
  1321.     unsigned long  k;
  1322.     int    verbose_cc = 0;
  1323.     int    blind_cc   = 0;
  1324.     char  *s, *t, *sp;
  1325.  
  1326.     current   = m->text;
  1327.     do_lookup = TRUE;
  1328.  
  1329.     /*
  1330.     ** Crosspost?  if so, call crosspost().
  1331.     */
  1332.  
  1333.     if (!strncmpi(current->text,"xc:",3) && !CurArea.netmail)
  1334.     {
  1335.         crosspost(m);
  1336.         return;
  1337.     }
  1338.  
  1339.     current = m->text;
  1340.     s       = current->text;
  1341.  
  1342.     /*
  1343.     ** Is the msg a cc:?  if not, save & bye-bye.
  1344.     */
  1345.  
  1346.     if (!strncmpi(current->text,"bc:", 3))
  1347.     {
  1348.         blind_cc = 1;
  1349.     }
  1350.     else if (!strncmpi(current->text,"vc:", 3))
  1351.     {
  1352.         verbose_cc = 1;
  1353.     }
  1354.     else if (strncmpi(current->text,"cc:", 3))
  1355.     {
  1356.         writemsg(m);
  1357.         return;
  1358.     }
  1359.  
  1360.     release(m->reply);
  1361.     m->attrib.sent = 1;
  1362.  
  1363.     if (SW->savecc && SW->rawcc)
  1364.     {
  1365.         writemsg(m);
  1366.         m->attrib.killsent = 1;
  1367.     }
  1368.  
  1369.     memset(names, 0, sizeof names);
  1370.  
  1371.     if ((names[0] = malloc(sizeof(NA))) == NULL)
  1372.         return;
  1373.  
  1374.     m->attrib.sent = 0;
  1375.     names[0]->name = strdup(m->isto);
  1376.     names[0]->addr = m->to;
  1377.  
  1378.     if (m->to.domain)
  1379.         names[0]->addr.domain = strdup(m->to.domain);
  1380.  
  1381.     /*
  1382.     ** Get names & addresses from cc: list.
  1383.     */
  1384.  
  1385.     while (current && *s && !strncmpi(s + 1,"c:", 2))
  1386.     {
  1387.         s += 3;
  1388.         while (*s && isspace(*s)) s++;
  1389.  
  1390.         if (*s == '~')
  1391.         {
  1392.             if ((sp = strchr(s, '\n')) != NULL)
  1393.                 *sp = '\0';
  1394.  
  1395.             GetFileCCs(s + 1, names, &num);
  1396.         }
  1397.         else
  1398.         {
  1399.             while (*s != '\0' && s != NULL)
  1400.             {
  1401.                 while (*s && isspace(*s)) s++;
  1402.  
  1403.                 if (*s == '\0')
  1404.                     break;
  1405.  
  1406.                 t = strchr(s,',');             /* Get next name on line */
  1407.  
  1408.                 if (t)
  1409.                     *t = '\0';
  1410.                 else
  1411.                 {
  1412.                     t = strchr(s,'\n');
  1413.                     if (t)
  1414.                         *t = '\0';
  1415.                     else
  1416.                         t = s + strlen(s) - 1;
  1417.                 }
  1418.  
  1419.                 names[num] = calloc(1, sizeof(NA));
  1420.                 if (names[num] == NULL)
  1421.                     break;
  1422.  
  1423.                 /*
  1424.                 ** UUCP address ?
  1425.                 */
  1426.  
  1427.                 if ((sp = strchr(s,'@'))!=NULL)
  1428.                 {
  1429.                     names[num]->addr.fidonet = 0;
  1430.                     if (sp == s) {
  1431.                         names[num]->addr.bangpath = 1;
  1432.                         sp++;
  1433.                     }
  1434.                     else
  1435.                     {
  1436.                         names[num]->addr.internet = 1;
  1437.                         sp = s;
  1438.                     }
  1439.                     names[num]->name        = strdup(s);
  1440.                     names[num]->addr.domain = strdup(s);
  1441.                 }
  1442.                 else
  1443.                 {
  1444.                     sp = strchr(s,'!');  /* look for address */
  1445.  
  1446.                     if (sp)
  1447.                         *sp = '\0';
  1448.  
  1449.                     if (sp)
  1450.                     {
  1451.                         names[num]->addr = parsenode(++sp);
  1452.                         names[num]->name = strdup(s);
  1453.                     }
  1454.                     else
  1455.                     {
  1456.                         names[num]->name = addr_lookup(s, &names[num]->addr);
  1457.  
  1458.                         /*
  1459.                         ** UUCP address from alias?
  1460.                         */
  1461.  
  1462.                         if ((sp = strchr(names[num]->name,'@'))!=NULL)
  1463.                         {
  1464.                             names[num]->addr.fidonet = 0;
  1465.                             if (sp == names[num]->name) {
  1466.                                 names[num]->addr.bangpath = 1;
  1467.                                 sp++;
  1468.                             }
  1469.                             else
  1470.                             {
  1471.                                 names[num]->addr.internet = 1;
  1472.                                 sp = names[num]->name;
  1473.                             }
  1474.                             names[num]->addr.domain = strdup(sp);
  1475.                         }
  1476.                     }
  1477.                 }
  1478.                 s = ++t;
  1479.                 num++;
  1480.             }
  1481.         }
  1482.         if (current->next)
  1483.             current = current->next;
  1484.         else
  1485.         {
  1486.             i = 0;
  1487.             while (names[i] != NULL)
  1488.             {
  1489.                 if (names[i]->name)
  1490.                     free(names[i]->name);
  1491.                 if (names[i]->addr.domain)
  1492.                     free(names[i]->addr.domain);
  1493.                 free(names[i]);
  1494.  
  1495.             }
  1496.             return;
  1497.         }
  1498.  
  1499.         /*
  1500.         ** Sheesh! There's a bit of stuffing about here
  1501.         */
  1502.  
  1503.         s              = current->text;
  1504.         m->text       = current;
  1505.         release(current->prev->text);
  1506.         release(current->prev);
  1507.         current->prev = NULL;
  1508.     }
  1509.  
  1510.     /*
  1511.     ** ok, we got the names & addresses - now lets make up the message
  1512.     */
  1513.  
  1514.     names[num] = NULL;
  1515.  
  1516.     if (blind_cc == 0)
  1517.     {
  1518.         if (verbose_cc)
  1519.             CreateVerboseCC(m, names);
  1520.         else
  1521.             CreateNormalCC(m, names);
  1522.     }
  1523.  
  1524.     /*
  1525.     ** OK, now it's time to SAVE this msg with
  1526.     ** the appropriate number of names etc etc..
  1527.     */
  1528.  
  1529.     i = 0;
  1530.  
  1531.     release(m->msgid);
  1532.     k      = MsgnToUid(CurArea.messages) + 1;
  1533.     m->new = 1;
  1534.  
  1535.     while (names[i] != NULL)
  1536.     {
  1537.         release(m->isto);
  1538.         release(m->to.domain);
  1539.  
  1540.         m->isto = strdup(names[i]->name);
  1541.         m->to   = names[i]->addr;
  1542.  
  1543.         if (names[i]->addr.domain)
  1544.             m->to.domain = strdup(names[i]->addr.domain);
  1545.  
  1546.         m->msgnum = k++;      /* for *.msg bases - get the real msg num */
  1547.         writemsg(m);  
  1548.  
  1549.         if (SW->savecc && !SW->rawcc)
  1550.             m->attrib.killsent = 1;
  1551.  
  1552.         release(names[i]->name);
  1553.         release(names[i]->addr.domain);
  1554.         i++;
  1555.     }
  1556.     scan_base = TRUE;
  1557. }
  1558.  
  1559. static void   crosspost(msg *m)
  1560. {
  1561.     LINE *current;
  1562.     char *s,*t;
  1563.     char dfn[128];
  1564.     char *arean[128];
  1565.     unsigned int num = 0, i = 0, k;
  1566.  
  1567.     current = m->text;
  1568.     s = current->text;
  1569.  
  1570.     arean[num++] = strdup(CurArea.tag);
  1571.  
  1572.     while (current && *s && !strncmpi(s,"xc:",3))
  1573.     {
  1574.         s += 3;
  1575.  
  1576.         while (*s && isspace(*s)) s++;
  1577.  
  1578.         while (*s != '\0' && s != NULL)
  1579.         {
  1580.             t = strchr(s,',');
  1581.             if (t)
  1582.                 *t = '\0';
  1583.             else
  1584.             {
  1585.                 t = strchr(s,'\n');
  1586.                 if (t)
  1587.                     *t = '\0';
  1588.                 else
  1589.                     t = s + strlen(s) - 1;
  1590.             }
  1591.             while (*s && isspace(*s)) s++;
  1592.             arean[num] = strdup(strupr(s));
  1593.  
  1594.             if (arean[num++] == NULL)
  1595.                 break;
  1596.  
  1597.             s = ++t;
  1598.         }
  1599.         if (current->next)
  1600.             current = current->next;
  1601.         else
  1602.         {
  1603.             i = 0;
  1604.             while (arean[i] != NULL) free(arean[i]);
  1605.             return;
  1606.         }
  1607.         s       = current->text;
  1608.         m->text = current;
  1609.  
  1610.         if (current->prev->text)
  1611.             free(current->prev->text);
  1612.  
  1613.         free(current->prev);
  1614.         current->prev = NULL;
  1615.     }
  1616.  
  1617.     arean[num] = NULL;
  1618.  
  1619.     strcpy(dfn,"");
  1620.     m->text       = insline(m->text);
  1621.     m->text->text = strdup("\n");
  1622.     m->text       = insline(m->text);
  1623.     m->text->text = strdup("\n");
  1624.     current       = m->text;
  1625.     i             = 0;
  1626.     strcpy(dfn," * Crossposted in area ");
  1627.  
  1628.     while (arean[i] != NULL)
  1629.     {
  1630.         if (strlen(arean[i]) + 3 + strlen(dfn) >= SW->rm)
  1631.         {
  1632.             strcat(dfn,"\n");
  1633.             release(current->text);
  1634.             current->text = strdup(dfn);
  1635.             current       = insline(current->next);
  1636.             current->text = strdup("\n");
  1637.             strcpy(dfn,"                       ");
  1638.         }
  1639.         strcat(dfn, arean[i]);
  1640.         i++;
  1641.         if (arean[i] != NULL)
  1642.             strcat(dfn,", ");
  1643.     }
  1644.  
  1645.     if (*(current->text) == '\n')
  1646.     {
  1647.         release(current->text);
  1648.         current->text = strdup(dfn);
  1649.     }
  1650.  
  1651.     m->new  = 1;
  1652.     i       = 0;
  1653.     while (arean[i] != NULL)
  1654.     {
  1655.         for (k = 0; k < SW->areas; k++)
  1656.         {
  1657.             if (arealist[k].tag && !stricmp(arean[i], arealist[k].tag))
  1658.                 break;
  1659.         }
  1660.         if (k == SW->areas || !arealist[k].echomail)
  1661.         {
  1662.             release(arean[i]);
  1663.             i++;
  1664.             continue;
  1665.         }
  1666.         release(m->from.domain)
  1667.         m->from = CurArea.addr;
  1668.  
  1669.         if (CurArea.addr.domain)
  1670.             m->from.domain = strdup(CurArea.addr.domain);
  1671.  
  1672.         set_area(k);
  1673.         if (CurArea.status)
  1674.         {
  1675.             m->msgnum = MsgnToUid(CurArea.messages) + 1;
  1676.             writemsg(m);
  1677.         }
  1678.         release(arean[i]);
  1679.         i++;
  1680.     }
  1681.     scan_base = TRUE;   /* reopen the base when we get back */
  1682. }
  1683.  
  1684. static int externalEditor(msg *m)
  1685. {
  1686.     FILE *fq;
  1687.     LINE  *current;
  1688.     char cmd[200];
  1689.     WND *hWnd, *hCurr;
  1690.     char linebuf[300];
  1691.  
  1692.     current = m->text;    
  1693.     fq = fopen("msged.tmp", "w");
  1694.     if (fq != NULL)
  1695.     {
  1696.         while (current != NULL)
  1697.         {
  1698.             if (current->text != NULL)
  1699.             {
  1700.                 fputs(current->text, fq);
  1701.             }
  1702.             current = current->next;
  1703.         }
  1704.         fclose(fq);
  1705.         maxx = term.NCol;
  1706.         maxy = term.NRow;
  1707.  
  1708.         hCurr = Wtop();
  1709.         hWnd = WndOpen(0, 0, term.NCol - 1, term.NRow - 1, 
  1710.                        NBDR, 0, cm[CM_NTXT]);
  1711.  
  1712.         WCurr(hWnd);
  1713.         MouseOFF();
  1714.         cursor(1);
  1715.         sprintf(cmd, "%s msged.tmp", ST->editorName);
  1716.         system(cmd);
  1717.         cursor(0);
  1718.         MouseON();
  1719.         clearbuffer(m->text); 
  1720.         
  1721.         fq = fopen("msged.tmp", "r");
  1722.         if (fq != NULL)
  1723.         {
  1724.             while (fgets(linebuf, sizeof linebuf, fq) != NULL)
  1725.             {
  1726.                 if (current == NULL)
  1727.                 {
  1728.                     m->text = calloc(1, sizeof(LINE));
  1729.                     current = m->text; 
  1730.                 }
  1731.                 else
  1732.                 {
  1733.                     current = InsertLine(current);
  1734.                 }
  1735.                 current->text = strdup(linebuf);
  1736.             }
  1737.             fclose(fq);
  1738.         }
  1739.         WClose(hWnd);
  1740.         WCurr(hCurr);
  1741.     }
  1742.     if (current == NULL) return (ABORT);
  1743.     else return (SAVE);
  1744. }
  1745.  
  1746. /* end of file */
  1747.