home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / mm-0.90 / send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-18  |  26.9 KB  |  1,208 lines

  1. /*
  2.  * Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  * the City of New York.  Permission is granted to any individual or
  4.  * institution to use, copy, or redistribute this software so long as it
  5.  * is not sold for profit, provided this copyright notice is retained.
  6.  */
  7.  
  8. #ifndef lint
  9. static char *rcsid = "$Header: /f/src2/encore.bin/cucca/mm/tarring-it-up/RCS/send.c,v 2.7 90/10/04 18:26:17 melissa Exp $";
  10. #endif
  11.  
  12. /*
  13.  * send.c - support for the mm send command
  14.  */ 
  15. #include "mm.h"
  16. #include "cmds.h"
  17. #include "message.h"
  18. #include "parse.h"
  19.  
  20. #define empty_addr(type) ((current->type == NULL) || \
  21.               (current->type->address == NULL) || \
  22.               (current->type->address->first == NULL))
  23.  
  24. extern string default_from, default_reply_to;
  25.  
  26. int getmsg();
  27.  
  28. char *reserved_fields[] = {
  29.     "Sender",
  30.     "Date",
  31.     "From",
  32.     nil,
  33. };
  34.  
  35. static int edited;
  36.  
  37. char *malloc(), *realloc(), *safe_strcpy(), *safe_free();
  38. headers *new_header();
  39.  
  40. mail_msg *current;
  41.  
  42. prompt_address(pstr, a) char *pstr; addresslist *a; 
  43. {
  44.     addresslist tmp;
  45.     extern int allow_aborts;
  46.     int aa;
  47.     volatile int doprev = false;
  48.  
  49.     aa = allow_aborts;
  50.     allow_aborts = true;
  51.     tmp.first = tmp.last = NULL;
  52.     cm_set_ind(false);
  53.     cmseteof();
  54.     if (cmseter ()) {            /* errors return here */
  55.     if (cmcsb._cmerr == CMxEOF) {
  56.         return CMxEOF;
  57.     }
  58.     else
  59.         doprev = true;
  60.     }
  61.     
  62.     prompt(pstr);
  63.     if (doprev) {
  64.     doprev = false;
  65.     prevcmd();
  66.     }
  67.  
  68.     cmsetrp();
  69.     parse_addresses(&tmp);
  70.     merge_addresses(a,&tmp);
  71.     cm_set_ind(true);
  72.     allow_aborts = aa;
  73. }
  74.  
  75. prompt_fcc(pstr, a)
  76. char *pstr;
  77. addresslist *a; 
  78. {
  79.     addresslist tmp;
  80.     extern int allow_aborts;
  81.     int aa;
  82.     volatile int doprev = false;
  83.     
  84.     aa = allow_aborts;
  85.     allow_aborts = true;
  86.     tmp.first = tmp.last = NULL;
  87.     cm_set_ind(false);
  88.     cmseteof();
  89.     if (cmseter ()) {            /* errors return here */
  90.     if (cmcsb._cmerr == CMxEOF) {
  91.         return CMxEOF;
  92.     }
  93.     else
  94.         doprev = true;
  95.     }
  96.     
  97.     prompt(pstr);
  98.     if (doprev) {
  99.     doprev = false;
  100.     prevcmd();
  101.     }
  102.     cmsetrp();
  103.     cmd_fcc(CMD_FCC);
  104.     merge_addresses(a,&tmp);
  105.     cm_set_ind(true);
  106.     allow_aborts = aa;
  107. }
  108.  
  109. int
  110. deliver ()
  111. {
  112.     if (current) {
  113.     if (empty_addr (to) && empty_addr (cc) && empty_addr (bcc) &&
  114.         empty_addr (fcc)) {
  115.         if (current->to == NULL) {
  116.         current->to = new_header(TO, "To", HEAD_KNOWN,current);
  117.         current->to->address = NULL;
  118.         }
  119.         if (current->to->address == NULL) {
  120.         current->to->address =
  121.             (addresslist *) malloc(sizeof(addresslist));
  122.         current->to->address->first = NULL;
  123.         current->to->address->last = NULL;
  124.         }
  125.         while (current->to->address->first == NULL)    /* gotta have it! */
  126.         prompt_address(" To: ", current->to->address);
  127.         files_to_fcc(current->to->address, current);
  128.     }
  129.     if (mode & (MM_ANSWER|MM_REPLY)) { /* mark message as answered */
  130.         if (!(cf->msgs[cf->current].flags & M_ANSWERED) &&
  131.         !(cf->flags & MF_RDONLY)) {
  132.         cf->msgs[cf->current].flags |= (M_ANSWERED|M_MODIFIED);
  133.         cf->flags |= MF_MODIFIED; /* we'll have to write out the file*/
  134.         }
  135.     }
  136.     if (sendmail(current))
  137.         free_msg(current);
  138.     else {
  139.         fprintf (stderr, "\
  140. Could not send mail.  Use SAVE-DRAFT to save a copy of this message\n");
  141.         return;
  142.     }
  143.     }
  144.     current = NULL;
  145.     mode &= ~(MM_SEND|MM_ANSWER);
  146. }
  147.  
  148. cmd_to(n)
  149. int n;
  150. {
  151.     addresslist temp;
  152.  
  153.     temp.first = temp.last = NULL;
  154.     parse_addresses(&temp);
  155.     if (!current->to) {
  156.     current->to = new_header(TO, "To", HEAD_KNOWN,current);
  157.     current->to->address = (addresslist *)malloc(sizeof (addresslist));
  158.     current->to->address->first = current->to->address->last = NULL;
  159.     }
  160.     merge_addresses(current->to->address, &temp);
  161.     files_to_fcc(current->to->address, current);
  162.  
  163. }
  164.  
  165. cmd_cc(n)
  166. int n;
  167. {
  168.     addresslist temp;
  169.  
  170.     temp.first = temp.last = NULL;
  171.     parse_addresses(&temp);
  172.     if (!current->cc) {
  173.     current->cc = new_header(CC, "Cc", HEAD_KNOWN,current);
  174.     current->cc->address = (addresslist *)malloc(sizeof(addresslist));
  175.     current->cc->address->first = current->cc->address->last = NULL;
  176.     }
  177.     merge_addresses(current->cc->address, &temp);
  178.     files_to_fcc(current->cc->address, current);
  179. }
  180.  
  181. cmd_bcc(n)
  182. int n;
  183. {
  184.     addresslist temp;
  185.  
  186.     temp.first = temp.last = NULL;
  187.     parse_addresses(&temp);
  188.     if (!current->bcc) {
  189.     current->bcc = new_header(BCC, "Bcc", HEAD_KNOWN,current);
  190.     current->bcc->address = (addresslist *)malloc(sizeof(addresslist));
  191.     current->bcc->address->first = current->bcc->address->last = NULL;
  192.     }
  193.     merge_addresses(current->bcc->address, &temp);
  194.     files_to_fcc(current->bcc->address, current);
  195. }
  196.  
  197. cmd_fcc(n)
  198. int n;
  199. {
  200.     char **filelist, **fl, **parse_filelist();
  201.  
  202.     filelist = parse_filelist(0,0,"filename",false);
  203.  
  204.     if (!current->fcc) {
  205.     current->fcc = new_header(FCC, "Fcc", HEAD_KNOWN,current);
  206.     current->fcc->address = (addresslist *)malloc(sizeof(addresslist));
  207.     current->fcc->address->first = current->fcc->address->last = NULL;
  208.     }
  209.     for(fl = filelist; fl && *fl; fl++)
  210.     add_addresslist(current->fcc->address, *fl, ADR_FILE);
  211. }
  212.  
  213.  
  214. static int esc = FALSE;
  215. char *
  216. escact(text, modified, ret) char *text; int *modified, *ret; 
  217. {
  218.     *ret = TRUE;
  219.     esc = TRUE;
  220.     return(text);
  221. }
  222.  
  223. int user_aborted = false;
  224.  
  225. char *
  226. abortaction (text, modified, ret)
  227. char *text;
  228. int *modified, *ret;
  229. {
  230.     csb oldcsb;
  231.     if (control_n_abort == SET_ASK) {
  232.     int cmdbuf[64];    char atmbuf[64], wrkbuf[64];
  233.     save_parse_context ();
  234.     oldcsb = cmcsb;
  235.     cmbufs (cmdbuf, sizeof cmdbuf / sizeof cmdbuf[0],
  236.         atmbuf, sizeof atmbuf, wrkbuf, sizeof wrkbuf);
  237.     cmact(nil);
  238.     *modified = false;
  239.     *ret = user_aborted = yesno ("Abort? ", "yes");
  240.     cmcsb = oldcsb;
  241.     restore_parse_context ();
  242.     cmcsb._cmcol = 0;        /* XXX */
  243.     }
  244.     else if (control_n_abort == SET_NEVER)
  245.     cmsti1('\016', 0);        /* XXX not quite right */
  246.     else
  247.     *ret = user_aborted = true;    /* set control-n-abort always */
  248.  
  249.     return (text);
  250. }
  251.  
  252. char *
  253. editaction(text, modified, ret) char *text; int *modified, *ret; {
  254.   mail_msg *m, *get_outgoing();
  255.  
  256.   cmxprintf ("^E\n");
  257.   *modified = TRUE;
  258.   *ret = TRUE;
  259.   m = get_outgoing();
  260.   if (m->body)
  261.     free (m->body);
  262.   m->body = safe_strcpy(text);
  263.   edit_outgoing(FALSE);
  264.   edited = true;
  265.   return (safe_strcpy(m->body));
  266. }
  267.  
  268.  
  269. /*
  270.  * GETMSG:
  271.  * parse for a message (invoking editor when necessary).
  272.  * Returns:
  273.  *    GET_ESC:      user exited paragraph parse with ESC
  274.  *    GET_CTRLD:    user exited paragraph parse with Control-D
  275.  *    GET_EDIT:    editor was invoked.
  276.  *    GET_ABORT:    user aborted.
  277.  */
  278.  
  279. int
  280. getmsg(outg)
  281. mail_msg *outg; 
  282. {
  283.     static para_actions msg_actions[] = {
  284.         { '\033', escact },        /* ESC handler */
  285.     { '\005', editaction },        /* ^E handler */
  286.     { '\016', abortaction },    /* ^N handler */
  287.         { NULL, NULL }
  288.     };
  289.     static para_data pd;
  290.     static fdb parafdb = { _CMPARA, CM_NEOF|PARA_DEF, NULL, (pdat) &pd, NULL,
  291.                 NULL, NULL };
  292.     pval parseval;
  293.     fdb *used;
  294.     int i;
  295.  
  296.     /* 
  297.      * set up ^E and ^N actions appropriately
  298.      */
  299.     for (i = 0; msg_actions[i].actionchar; i++)
  300.     if (msg_actions[i].actionchar == '\005')
  301.         msg_actions[i].actionfunc = control_e_editor ? editaction : nil;
  302.     else if (msg_actions[i].actionchar == '\016')
  303.         msg_actions[i].actionfunc = control_n_abort ? abortaction : nil;
  304.       
  305.     if (use_editor_always) {
  306.       edit_outgoing (FALSE);        /* don't parse keyword */
  307.       return (GET_EDIT);
  308.     }
  309.     pd.actions = msg_actions;
  310.     pd.buf = outg->body; 
  311.  
  312. #ifdef undef
  313.     if (terse_text_prompt)
  314.     cmxprintf (" Msg:\n");
  315.     else
  316.     cmxprintf(" Message (End with CTRL/D or ESC\n\
  317.   Use CTRL/B to insert a file, CTRL/E to enter editor, CTRL/F to run text\n\
  318.   through a filter, CTRL/K to redisplay message, CTRL/L to clear screen and\n\
  319.   redisplay, CTRL/N to abort, CTRL/P to run a program and insert output.):\n");
  320.  
  321.     if (pd.buf != NULL)
  322.       redisplast (pd.buf, terse_text_prompt ? 1 : 4); /* # of lines in msg */
  323. #endif
  324.  
  325.     if (terse_text_prompt)
  326.     prompt_for_text (" Msg:\n", pd.buf);
  327.     else
  328.     prompt_for_text (" Message (End with CTRL/D or ESC\n\
  329.   Use CTRL/B to insert a file, CTRL/E to enter editor, CTRL/F to run text\n\
  330.   through a filter, CTRL/K to redisplay message, CTRL/L to clear screen and\n\
  331.   redisplay, CTRL/N to abort, CTRL/P to run a program and insert output.):\n",
  332.              pd.buf);
  333.  
  334.     esc = FALSE;
  335.     edited = FALSE;
  336.     user_aborted = false;
  337.     parse(¶fdb,&parseval,&used);
  338.     if (parseval._pvpara != NULL) {
  339.       if (outg->body)
  340.     free (outg->body);
  341.       outg->body = safe_strcpy(parseval._pvpara);
  342.     }
  343.     if (user_aborted)
  344.       return (GET_ABORT);
  345.     if (esc)
  346.       return (GET_ESC);
  347.     if (edited)
  348.       return (GET_EDIT);
  349.     return (GET_CTRLD);
  350. }
  351.  
  352. cmd_text(n)
  353. int n;
  354. {
  355.     int ret;
  356.  
  357.     confirm();
  358.     ret = getmsg(current);
  359.     if ((escape_automatic_send && (ret == GET_ESC)) ||
  360.     (control_d_automatic_send && (ret == GET_CTRLD))) { /* send! */
  361.         deliver();
  362.     }
  363. }
  364.  
  365.  
  366. cmd_erase(n)
  367. int n;
  368. {
  369.     pval pv;
  370.     fdb *used;
  371.     int which;
  372.  
  373.     noise("message field");
  374.     parse(fdbchn(&hdr_cmd_fdb,&erase_cmd_fdb, nil),&pv, &used);
  375.     which = (int) pv._pvkey;
  376.     switch(which) {
  377.     case CMD_ALL:
  378.     confirm();
  379.     free_msg(current);
  380.     break;
  381.     case CMD_BCC:
  382.     confirm();
  383.     free_header(current,BCC);
  384.     break;
  385.     case CMD_CC:
  386.     confirm();
  387.     free_header(current,CC);
  388.     break;
  389.     case CMD_FCC:
  390.     confirm();
  391.     free_header(current,FCC);
  392.     break;
  393.     case CMD_FROM:
  394.     confirm();
  395.     free_header(current,FROM);
  396.     break;
  397.     case CMD_REPLY_TO:
  398.     confirm();
  399.     free_header(current,REPLY_TO);
  400.     break;
  401.     case CMD_IN_REPLY_TO:
  402.     confirm();
  403.     free_header(current,IN_REPLY_TO);
  404.     break;
  405.     case CMD_SUBJECT:
  406.     confirm();
  407.     free_header(current,SUBJECT);
  408.     break;
  409.     case CMD_TEXT:
  410.     confirm();
  411.     free_body();
  412.     break;
  413.     case CMD_TO:
  414.     confirm();
  415.     free_header(current,TO);
  416.     break;
  417.     case CMD_USER_HEADER:
  418.         {
  419.         static char *uh;
  420.         static fdb keyfdb = { _CMKEY };
  421.         static fdb fldfdb = { _CMFLD, CM_SDH, nil, nil, "Field name" };
  422.         if (uh) {
  423.         free(uh);
  424.         uh = nil;
  425.         }
  426.         if (user_headers) {
  427.         keyfdb._cmdat = (pdat) keylist_to_keytab(user_headers);
  428.         parse(fdbchn(&keyfdb, &fldfdb,nil),&pv,&used);
  429.         }
  430.         else 
  431.         parse(fdbchn(&fldfdb,nil), &pv,&used);
  432.         uh = safe_strcpy(atmbuf);
  433.         confirm();
  434.         free_user_header(current,uh);
  435.         free(uh);
  436.         uh = nil;
  437.     }
  438.     break;
  439.     }
  440.     
  441. }
  442.  
  443. free_msg(msg)
  444. mail_msg *msg;
  445. {
  446.     while(msg->headers) {
  447.     headers *t = msg->headers;
  448.     free_header(msg,t->type);
  449.     }
  450.     if (msg->body) {
  451.     free(msg->body);
  452.     }
  453.     msg->body = NULL;
  454. }
  455.  
  456. free_header(msg,type) 
  457. mail_msg *msg;
  458. int type;
  459. {
  460.     headers *h = msg->headers, *h1 = NULL;
  461.     while(h) {
  462.     if (h->type == type) {
  463.         if (h1)
  464.         h1->next = h->next;
  465.         else 
  466.         msg->headers = h->next;
  467.         
  468.         h->next = NULL;
  469.         h->name = safe_free(h->name);
  470.         switch(type) {
  471.         case TO:
  472.         if (h)  {
  473.             free_addresslist(h->address);
  474.             free(h->address);
  475.             h = (headers *) safe_free(h);
  476.         }
  477.         msg->to = NULL;
  478.         break;
  479.         case CC:
  480.         if (h)  {
  481.             free_addresslist(h->address);
  482.             free(h->address);
  483.             h = (headers *) safe_free(h);
  484.         }
  485.         msg->cc = NULL;
  486.         break;
  487.         case BCC:
  488.         if (h)  {
  489.             free_addresslist(h->address);
  490.             free(h->address);
  491.             h = (headers *) safe_free(h);
  492.         }
  493.         msg->bcc = NULL;
  494.         break;
  495.         case FCC:
  496.         if (h)  {
  497.             free_addresslist(h->address);
  498.             free(h->address);
  499.             h = (headers *) safe_free(h);
  500.         }
  501.         msg->fcc = NULL;
  502.         break;
  503.         case RESENT_TO:
  504.         if (h)  {
  505.             free_addresslist(h->address);
  506.             free(h->address);
  507.             h = (headers *) safe_free(h);
  508.         }
  509.         msg->resent_to = NULL;
  510.         break;
  511.         case FROM:
  512.         if (h) {
  513.             h->string = safe_free(h->string);
  514.             h = (headers *) safe_free(h);
  515.         }
  516.         msg->from = NULL;
  517.         break;
  518.         case DATE:
  519.         if (h) {
  520.             h->string = safe_free(h->string);
  521.             h = (headers *) safe_free(h);
  522.         }
  523.         msg->date = NULL;
  524.         break;
  525.         case SUBJECT:
  526.         if (h) {
  527.             h->string = safe_free(h->string);
  528.             h = (headers *) safe_free(h);
  529.         }
  530.         msg->subject = NULL;
  531.         break;
  532.         case REPLY_TO:
  533.         if (h) {
  534.             h->string = safe_free(h->string);
  535.             h = (headers *) safe_free(h);
  536.         }
  537.         msg->reply_to = NULL;
  538.         break;
  539.         case IN_REPLY_TO:
  540.         if (h) {
  541.             h->string = safe_free(h->string);
  542.             h = (headers *) safe_free(h);
  543.         }
  544.         msg->in_reply_to = NULL;
  545.         break;
  546.         case RESENT_DATE:
  547.         if (h) {
  548.             h->string = safe_free(h->string);
  549.             h = (headers *) safe_free(h);
  550.         }
  551.         msg->resent_date = NULL;
  552.         break;
  553.         case RESENT_FROM:
  554.         if (h) {
  555.             h->string = safe_free(h->string);
  556.             h = (headers *) safe_free(h);
  557.         }
  558.         msg->resent_from = NULL;
  559.         break;
  560.         case SENDER:
  561.         if (h) {
  562.             h->string = safe_free(h->string);
  563.             h = (headers *) safe_free(h);
  564.         }
  565.         msg->sender = NULL;
  566.         break;
  567.         case REFERENCES:
  568.         if (h) {
  569.             h->string = safe_free(h->string);
  570.             h = (headers *) safe_free(h);
  571.         }
  572.         msg->references = NULL;
  573.         break;
  574.         case COMMENTS:
  575.         if (h) {
  576.             h->string = safe_free(h->string);
  577.             h = (headers *) safe_free(h);
  578.         }
  579.         msg->comments = NULL;
  580.         break;
  581.         case MESSAGE_ID:
  582.         if (h) {
  583.             h->string = safe_free(h->string);
  584.             h = (headers *) safe_free(h);
  585.         }
  586.         msg->message_id = NULL;
  587.         break;
  588.         case KEYWORDS:
  589.         if (h) {
  590.             keylist free_keylist();
  591.             h->keys = free_keylist(h->keys);
  592.             h = (headers *) safe_free(h);
  593.         }
  594.         msg->keywords = NULL;
  595.         break;
  596.         case ENCRYPTED:
  597.         if (h) {
  598.             h->string = safe_free(h->string);
  599.             h = (headers *) safe_free(h);
  600.         }
  601.         msg->encrypted = NULL;
  602.         break;
  603.         case RECEIVED:
  604.         if (h) {
  605.             h->string = safe_free(h->string);
  606.             h = (headers *) safe_free(h);
  607.         }
  608.         msg->received = NULL;
  609.         break;
  610.         }
  611.         if (h1)
  612.         h = h1->next;
  613.         else 
  614.         h = msg->headers;
  615.     }
  616.     else {
  617.         h1 = h;
  618.         h = h->next;
  619.     }
  620.     }
  621.     if (msg->headers == NULL)
  622.     msg->last = NULL;
  623.     else for(h = msg->headers; h->next != NULL; h = h->next);
  624.     msg->last = h;
  625. }
  626.  
  627. free_user_header(msg,type) 
  628. mail_msg *msg;
  629. char *type;
  630. {
  631.     headers *h = msg->headers, *h1 = NULL;
  632.     while(h) {
  633.     if (h->type == USER_HEADERS && ustrcmp(h->name,type) == 0) {
  634.         if (h1)
  635.         h1->next = h->next;
  636.         else 
  637.         msg->headers = h->next;
  638.         
  639.         h->next = NULL;
  640.         h->name = safe_free(h->name);
  641.         h->string = safe_free(h->string);
  642.         h = (headers *) safe_free(h);
  643.  
  644.         if (h1)
  645.         h = h1->next;
  646.         else 
  647.         h = msg->headers;
  648.     }
  649.     else {
  650.         h1 = h;
  651.         h = h->next;
  652.     }
  653.     }
  654.     if (msg->headers == NULL)
  655.     msg->last = NULL;
  656.     else for(h = msg->headers; h->next != NULL; h = h->next);
  657.     msg->last = h;
  658. }
  659.  
  660. cmd_continue(n)
  661. int n;
  662. {
  663.     noise("sending message");
  664.     confirm();
  665.     if (current) {
  666.     mode |= MM_SEND;
  667.     }
  668.     else {
  669.     cmerr("No current Message");
  670.     }
  671. }
  672.  
  673. cmd_remove(n)
  674. int n;
  675. {
  676.     addresslist a;
  677.  
  678.     a.first = a.last = NULL;
  679.     noise("address");
  680.     parse_addresses(&a);
  681.     if (current->to)
  682.     remove_addr(current->to->address,&a);
  683.     if (current->cc)
  684.     remove_addr(current->cc->address,&a);
  685.     if (current->bcc)
  686.     remove_addr(current->bcc->address,&a);
  687.     if (current->fcc)
  688.     remove_addr(current->fcc->address,&a);
  689.     free_addresslist(&a);
  690. }    
  691.  
  692. cmd_subject(n)
  693. int n;
  694. {
  695.     char *t; 
  696.  
  697.     t = parse_text("new subject", NULL);
  698.     if (current->subject) {
  699.     free_header(current,SUBJECT);
  700.     }
  701.     current->subject = new_header(SUBJECT, "Subject", HEAD_KNOWN,current);
  702.     current->subject->string = safe_strcpy(t);
  703. }
  704.  
  705. cmd_from(n)
  706. int n;
  707. {
  708.     char *t, *create_sender();
  709.  
  710.     t = parse_text("new from field", NULL);
  711.     if (current->from == NULL) {
  712.     current->from = new_header(FROM, "From", HEAD_KNOWN,current);
  713.     }
  714.     else
  715.     free(current->from->string);
  716.     current->from->string = safe_strcpy(t);
  717.     if (current->reply_to == NULL) {    /* no reply-to field yet */
  718.         current->reply_to = new_header(REPLY_TO, "Reply-To", 
  719.                        HEAD_KNOWN,current);
  720.     if (strlen(default_reply_to) != 0) {
  721.         current->reply_to->string = malloc (strlen(default_reply_to)+1);
  722.         strcpy (current->reply_to->string, default_reply_to);
  723.     }
  724.     else {
  725.         current->reply_to->string = safe_strcpy(create_sender());
  726.     }
  727.     }
  728. }
  729.  
  730. cmd_reply_to(n)
  731. int n;
  732. {
  733.     char *t; 
  734.  
  735.     t = parse_text("new address to have replies go to",NULL);
  736.     if (current->reply_to) {
  737.     free_header(current,REPLY_TO);
  738.     }
  739.     current->reply_to = new_header(REPLY_TO, "Reply-To", HEAD_KNOWN,current);
  740.     current->reply_to->string = safe_strcpy(t);
  741. }
  742.  
  743. cmd_in_reply_to(n)
  744. int n;
  745. {
  746.     char *t; 
  747.  
  748.     t = parse_text("Line of text",NULL);
  749.     if (current->in_reply_to) {
  750.     free_header(current,IN_REPLY_TO);
  751.     }
  752.     current->in_reply_to = new_header(IN_REPLY_TO, "In-Reply-To", HEAD_KNOWN,
  753.                       current);
  754.     current->in_reply_to->string = safe_strcpy(t);
  755. }
  756.  
  757.  
  758. send_mode(msg) mail_msg *msg; {
  759.     mode |= MM_SEND;
  760.     current = msg;
  761. }
  762.  
  763. headers *
  764. new_header(type, name, flags, current)
  765. int type, flags;
  766. char *name;
  767. mail_msg *current;
  768. {
  769.     headers *x;
  770.     x = (headers *)malloc(sizeof(headers));
  771.     if (!x)
  772.     panic ("Out of memory");
  773.  
  774.     x->type = type;
  775.     x->name = safe_strcpy(name);
  776.     x->flags = flags;
  777.     x->next = NULL;
  778.     x->string = NULL;
  779.     x->address = NULL;
  780.     x->keys = NULL;
  781.     if (current->last)
  782.     current->last = current->last->next = x;
  783.     else
  784.     current->headers = current->last = x;
  785.  
  786.     switch(type) {
  787.     case TO:
  788.         current->to = x;
  789.         break;
  790.     case CC:
  791.         current->cc = x;
  792.         break;
  793.     case BCC:
  794.         current->bcc = x;
  795.         break;
  796.     case FCC:
  797.         current->fcc = x;
  798.         break;
  799.     case FROM:
  800.         current->from = x;
  801.         break;
  802.     case DATE:
  803.         current->date = x;
  804.         break;
  805.     case SUBJECT:
  806.         current->subject = x;
  807.         break;
  808.     case REPLY_TO:
  809.         current->reply_to = x;
  810.         break;
  811.     case IN_REPLY_TO:
  812.         current->in_reply_to = x;
  813.         break;
  814.     case RESENT_TO:
  815.         current->resent_to = x;
  816.         break;
  817.     case RESENT_DATE:
  818.         current->resent_date = x;
  819.         break;
  820.     case RESENT_FROM:
  821.         current->resent_from = x;
  822.         break;
  823.     case SENDER:
  824.         current->sender = x;
  825.         break;
  826.     case REFERENCES:
  827.         current->references = x;
  828.         break;
  829.     case COMMENTS:
  830.         current->comments = x;
  831.         break;
  832.     case MESSAGE_ID:
  833.         current->message_id = x;
  834.         break;
  835.     case KEYWORDS:
  836.         current->keywords = x;
  837.         break;
  838.     case ENCRYPTED:
  839.         current->encrypted = x;
  840.         break;
  841.     }
  842.     return(x);
  843. }
  844.  
  845. free_body() {
  846.     current->body = safe_free(current->body);
  847. }
  848.  
  849. set_send_defaults(msg)
  850. mail_msg *msg;
  851. {
  852.     char **list;
  853.     addresslist temp;
  854.     char *pname;
  855.     char *create_sender();
  856.     int need_replyto = FALSE;
  857.  
  858.     if (msg->from == NULL) {
  859.     new_header(FROM,"From", HEAD_KNOWN, msg);
  860.     if (strlen(default_from) != 0) {
  861.         msg->from->string = malloc (strlen(default_from)+1);
  862.         strcpy (msg->from->string, default_from);
  863.         need_replyto = TRUE;
  864.     }
  865.     else {
  866.         pname = personal_name;
  867.         if (user_name[0] != '\0') {
  868.         if (pname == NULL || pname[0] == '\0')
  869.             pname = real_personal_name;
  870.         if (pname) {
  871.             if (mailhostname) {
  872.             msg->from->string = malloc(strlen(pname)+
  873.                            strlen(user_name)+
  874.                            strlen(mailhostname) +5);
  875.             sprintf(msg->from->string, "%s <%s@%s>", pname, 
  876.                 user_name, mailhostname);
  877.             }
  878.             else {
  879.             msg->from->string = malloc(strlen(pname)+
  880.                            strlen(user_name)
  881.                            +4);
  882.             sprintf(msg->from->string, "%s <%s>", 
  883.                 pname, user_name);
  884.             }
  885.         }
  886.         else {
  887.             if (mailhostname) {
  888.             msg->from->string = malloc(strlen(user_name) +
  889.                            strlen(mailhostname) +4);
  890.             sprintf(msg->from->string, "<%s@%s>", user_name,
  891.                 mailhostname);
  892.             }
  893.             else {
  894.             msg->from->string = malloc(strlen(user_name) +3);
  895.             sprintf(msg->from->string, "<%s>", user_name);
  896.             }
  897.         }
  898.         }
  899.     }
  900.     }
  901.     if ((msg->reply_to == NULL) && 
  902.     ((default_reply_to[0] != '\0') || need_replyto)) {
  903.     new_header(REPLY_TO, "Reply-To", HEAD_KNOWN, msg);
  904.     if (default_reply_to[0] != '\0') {
  905.         msg->reply_to->string = malloc (strlen(default_reply_to)+1);
  906.         strcpy (msg->reply_to->string, default_reply_to);
  907.     }
  908.     else {
  909.         msg->reply_to->string = safe_strcpy(create_sender());
  910.     }
  911.     }
  912.     temp.first = temp.last = NULL;    /* XXX what's this used for? */
  913.     if (msg->to == NULL) {
  914.     new_header(TO, "To", HEAD_KNOWN, msg);
  915.     msg->to->address = (addresslist *) malloc(sizeof(addresslist));
  916.     msg->to->address->first = msg->to->address->last = NULL;
  917.     }
  918.     if (msg->cc == NULL) {
  919.     new_header(CC, "Cc", HEAD_KNOWN, msg);
  920.     msg->cc->address = (addresslist *) malloc(sizeof(addresslist));
  921.     msg->cc->address->first = msg->cc->address->last = NULL;
  922.     merge_addresses(msg->cc->address, &default_cc_list);
  923.     }
  924.  
  925.     if (msg->bcc == NULL) {
  926.     new_header(BCC, "Bcc", HEAD_KNOWN, msg);
  927.     msg->bcc->address = (addresslist *) malloc(sizeof(addresslist));
  928.     msg->bcc->address->first = msg->bcc->address->last = NULL;
  929.     merge_addresses(msg->bcc->address, &default_bcc_list);
  930.     }
  931.     if (msg->fcc == NULL) {
  932.     keylist df = default_fcc_list;
  933.     new_header(FCC, "Fcc", HEAD_KNOWN, msg);
  934.     msg->fcc->address = (addresslist *) malloc(sizeof(addresslist));
  935.     msg->fcc->address->first = msg->fcc->address->last = NULL;
  936.     while (df && *df) {
  937.         add_addresslist(msg->fcc->address, *df, ADR_FILE);
  938.         df++;
  939.     }
  940.     }
  941.     read_header_file(msg);
  942. }    
  943.  
  944. outgoing_keyword(key)
  945. char *key;
  946. {
  947.     keylist add_keyword();
  948.     if (current->keywords == nil) {
  949.     new_header(KEYWORDS, "Keywords", HEAD_KNOWN, current);
  950.     }
  951.     current->keywords->keys = add_keyword(key, current->keywords->keys);
  952. }
  953.  
  954. unoutgoing_keyword(key)
  955. char *key;
  956. {
  957.     keylist rem_keyword();
  958.     current->keywords->keys = rem_keyword(key,  current->keywords->keys);
  959. }
  960.  
  961. cmd_user_header(n)
  962. int n;
  963. {
  964.     char *uh;
  965.     char *data;
  966.     static fdb fldfdb = { _CMFLD, CM_SDH, nil, nil, "Field name" };
  967.     static fdb keyfdb = { _CMKEY };
  968.     headers *h;
  969.     
  970.     if (user_headers) {
  971.     keyfdb._cmdat = (pdat) keylist_to_keytab(user_headers);
  972.     parse(fdbchn(&keyfdb, &fldfdb,nil),&pv,&used);
  973.     }
  974.     else 
  975.     parse(fdbchn(&fldfdb,nil), &pv,&used);
  976.     uh = safe_strcpy(atmbuf);
  977.     data = parse_text("Line of Text", nil);
  978.     if (reserved_field(uh)) {    /* make sure it is not reserved */
  979.     char *name1;
  980.     name1 = malloc(strlen(uh)+3);
  981.     sprintf(name1,"X-%s", uh); /* reserved - add an "X-" to it */
  982.     free(uh);
  983.     uh = name1;
  984.     }
  985.     h = new_header(USER_HEADERS, uh, HEAD_UNKNOWN, current);
  986.     h->string = safe_strcpy(data);
  987.     free(uh);
  988. }
  989.  
  990. char*
  991. read_file(fname)
  992. char *fname;
  993. {
  994.     int fd;
  995.     struct stat sbuf;
  996.     char *newtext;
  997.  
  998.     if (stat(fname, &sbuf) == -1) {    /* get file length */
  999.     perror(fname);
  1000.     return (NULL);
  1001.     }
  1002.     if ((fd = open(fname, O_RDONLY,0)) < 0) { /* open file for read */
  1003.     perror(fname);
  1004.     return (NULL);
  1005.     }
  1006.     newtext = (char *) malloc (sbuf.st_size+2);
  1007.     if (read(fd, newtext, sbuf.st_size) != sbuf.st_size) {
  1008.     perror(fname);
  1009.     close (fd);
  1010.     free (newtext);
  1011.     return (NULL);
  1012.     }
  1013.     close (fd);
  1014.     if (sbuf.st_size > 1) 
  1015.     if (newtext[sbuf.st_size-1] != '\n')
  1016.         newtext[sbuf.st_size++] = '\n';
  1017.     newtext[sbuf.st_size] = '\0';        /* null terminate the text */
  1018.     return (newtext);
  1019. }
  1020.  
  1021. read_header_file(msg) 
  1022. mail_msg *msg;
  1023. {
  1024.     char *contents, *cp, *skipheader(),*name, *cp1,*bp,*text;
  1025.     headers *h;
  1026.  
  1027.     if (strcmp(header_options_file, "/dev/null") == 0) 
  1028.     return;
  1029.  
  1030.     contents = read_file(header_options_file); /* read the file */
  1031.     if (contents == nil)
  1032.     return;
  1033.  
  1034.     cp1 = contents;
  1035.     while(1) {
  1036.     if (cp1 == nil || *cp1 == '\0')
  1037.         break;
  1038.     cp = cp1;
  1039.     cp1 = skipheader(cp);        /* find the next header */
  1040.     if (cp1 == nil)
  1041.         cp1 = cp + strlen(cp);
  1042.     while(isspace(*cp) && cp != cp1) cp++;
  1043.     if (cp == cp1)
  1044.         continue;
  1045.     bp = index(cp, ':');
  1046.     if (bp == 0 || bp > cp1) {
  1047.         fprintf(stderr,"%%Illegal User Header in %s:\n '",
  1048.             header_options_file);
  1049.         fwrite(cp, sizeof (char), (cp1 - cp) -1, stderr);
  1050.         fprintf(stderr,"'\n");
  1051.     }
  1052.     else {
  1053.         name = malloc(bp - cp + 1);    /* get the field name */
  1054.         strncpy(name, cp, bp - cp);
  1055.         name[bp-cp] = '\0';
  1056.         if (reserved_field(name)) {    /* make sure it is not reserved */
  1057.         char *name1;
  1058.         name1 = malloc(strlen(name)+3);
  1059.         sprintf(name1,"X-%s", name); /* reserved - add an "X-" to it */
  1060.         free(name);
  1061.         name = name1;
  1062.         }
  1063.         bp++;            /* skip past the ':' */
  1064.         if (*bp == ' ') bp++;
  1065.         text = malloc((cp1 - bp)+1); /* get the text of the field */
  1066.         strncpy(text,bp,(cp1-bp));
  1067.         text[cp1-bp] = '\0';
  1068.         if (text[strlen(text)-1] == '\n')
  1069.         text[strlen(text)-1] = '\0';
  1070.         h = new_header(USER_HEADERS, name, HEAD_UNKNOWN, msg);
  1071.         h->string = text;
  1072.         free(name);
  1073.     }
  1074.     if (*cp1 == '\0')
  1075.         break;
  1076.     cp = cp1;
  1077.     }
  1078.     free(contents);
  1079. }
  1080.  
  1081. reserved_field(str) {
  1082.     int i;
  1083.     char *cp;
  1084.  
  1085.     
  1086.     for(i = 0; reserved_fields[i] != nil; i++) {
  1087.     cp = reserved_fields[i];
  1088.     while(isblank(*cp)) cp++;
  1089.     if (ustrcmp(cp, str) == 0) return(true);
  1090.     }
  1091.     return(false);
  1092. }
  1093.  
  1094.  
  1095. /* 
  1096.  * move ADR_FILES from the from address into the fcc field on the tomsg
  1097.  */
  1098.  
  1099. files_to_fcc(from, tomsg) 
  1100. addresslist *from;
  1101. mail_msg *tomsg;
  1102. {
  1103.     addr_unit *a, *a1;
  1104.     addresslist *fcc;
  1105.  
  1106.     if (tomsg == NULL) return;
  1107.     if (tomsg->fcc && from == tomsg->fcc->address) return;
  1108.  
  1109.     if (!tomsg->fcc) {
  1110.     tomsg->fcc = new_header(FCC, "Fcc", HEAD_KNOWN,tomsg);
  1111.     tomsg->fcc->address = (addresslist *)malloc(sizeof(addresslist));
  1112.     tomsg->fcc->address->first = tomsg->fcc->address->last = NULL;
  1113.     }
  1114.     fcc = tomsg->fcc->address;
  1115.     for(a = from->first; a != nil; ) {
  1116.     if (a->type == ADR_FILE) {
  1117.         if (a->prev)
  1118.         a->prev->next = a->next;
  1119.         if (a->next)
  1120.         a->next->prev = a->prev;
  1121.         if (from->first == a)
  1122.         from->first = a->next;
  1123.         if (from->last == a)
  1124.         from->last = a->prev;
  1125.         a1 = a->prev;
  1126.  
  1127.         a->prev = fcc->last;
  1128.         a->next = nil;
  1129.         if (fcc->last)
  1130.         fcc->last = fcc->last->next = a;
  1131.         else
  1132.         fcc->first = fcc->last = a;
  1133.  
  1134.         a = a1;
  1135.         if (a == nil)
  1136.         a = from->first;
  1137.     }
  1138.     else
  1139.         a = a->next;
  1140.     }
  1141. }
  1142.  
  1143.  
  1144. prompt_for_text(prompt, text) 
  1145. char *prompt;
  1146. char *text; 
  1147. {
  1148.   int i, li, co, cols, ov=FALSE;
  1149.   char c;
  1150.   int plen, plines = 0;
  1151.   int tlen;
  1152.  
  1153.   cmxprintf ("%s", prompt);
  1154.  
  1155.   if (text == NULL || !display_outgoing_message) /* no text yet */
  1156.     return;
  1157.  
  1158.   tlen = strlen(text);
  1159.   plen = strlen(prompt);
  1160.   for (i = 0; i < plen; i++)
  1161.     if (prompt[i] == '\n')
  1162.       plines++;
  1163.  
  1164.   li = cmcsb._cmrmx;            /* get number of lines */
  1165.   co = cmcsb._cmcmx;            /* and number of columns */
  1166.  
  1167.   li -= plines;                /* number of lines to keep at top */
  1168.  
  1169.   for (i = strlen(text)-1, cols = 0; i >= 0; i--) { /* figure out what */
  1170.     c = text[i] & 0x7f;            /*   we can display */
  1171.     if (c == '\t')
  1172.     cols = ((cols + 8) / 8) * 8;
  1173.     else 
  1174.     cols++;                /* incr column count */
  1175.     if (iscntrl(c) && !isspace(c))    /* control char takes two chars */
  1176.       cols++;                /*   to display, count the ^ */
  1177.     if (cols > co) {        
  1178.       --li;                /* we overflowed the line */
  1179.       cols = 0;                /* reset column count */
  1180.       ov = TRUE;            /* remember */
  1181.     }
  1182.     if (c == '\n') {            /* another line */
  1183.       cols = 0;                /* reset the column count */
  1184.       li--;
  1185.       ov = FALSE;
  1186.     }
  1187.     if (li == 0)            /* can't display any more lines */
  1188.       break;
  1189.   }
  1190.   if (ov && li == 0) {            /* top line doesn't fit on display */
  1191.     int p;
  1192.     p = i;
  1193.     while ((c = text[p] & 0x7f) != '\n' &&  p > 0) /* find beginning of line */
  1194.       p--;
  1195.     p += ((i - p)/co + 1) * co;
  1196.     i = p-1;                /* skip over the \n */
  1197.   }
  1198.     
  1199.   for(i++; i < tlen; i++) {    /* display the screenful */
  1200.     c = text[i] & 0x7f;
  1201.     if (iscntrl(c) && !isspace(c)) {
  1202.       cmxputc('^');            /* display control chars as */
  1203.       cmxputc(c | 0100);        /*   caret and uppercased */
  1204.     }
  1205.     else cmechx(c);
  1206.   }
  1207. }
  1208.