home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / mm-0.90 / sendmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-18  |  22.1 KB  |  873 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/sendmail.c,v 2.2 90/10/04 18:26:27 melissa Exp $";
  10. #endif
  11.  
  12. /**
  13.  **  sendmail.c - mm interface to sendmail(8)
  14.  **/
  15.  
  16. #include "mm.h"
  17. #include "message.h"
  18. #include "rd.h"
  19. #include "parse.h"
  20.  
  21. extern int append_signature;        /* VAR_MAYBE */
  22.  
  23. #ifndef FALSE
  24. #define FALSE (0)
  25. #define TRUE  (!FALSE)
  26. #endif 
  27.  
  28. #ifdef HAVE_FLEXFILENAMES
  29. #define PRE_SENDMAIL ".mm-sendmail."
  30. #define PRE_DEADLETTER ".mm-deadletter."
  31. #else
  32. #define PRE_SENDMAIL ".mm-sm"
  33. #define PRE_DEADLETTER ".mm-dl"
  34. #endif
  35.  
  36. #define INDENT 8            /* amount to indent when folding */
  37. #define ALLOCINC 20            /* increment for realloc */
  38.  
  39. #define SIGNATURE ".signature"
  40. #define sendmail_who_cmd "/usr/lib/sendmail -bv"
  41.  
  42. /*
  43.  * sendmail:
  44.  * accepts a mail_msg and forks up sendmail(8) and sends the message.
  45.  */
  46.  
  47. sendmail (m)
  48. mail_msg *m;
  49. {
  50.   FILE *tfp, *message_tempfile ();
  51.   char **argv = NULL,            /* arguments to sendmail(8) */
  52.        **Files = NULL;            /* file recipients */
  53.   int i, pid, mailit, fileit, saveit, failed = FALSE;
  54.   headers *new_header ();
  55.   char *safe_strcpy ();
  56.   char *signature = NULL, *maybe_append_signature();
  57.  
  58.   /*
  59.    * Make sure the headers are complete.  This is probably the wrong
  60.    * place to do it, but...
  61.    */
  62.  
  63.   if (!m->date) {
  64.       headers *h = m->headers, *t = m->last, *x;
  65.       m->date = x = new_header (DATE, "Date", HEAD_KNOWN, m);
  66.       x->string = safe_strcpy (rfctime ((time_t *)0));
  67.       if (t) {
  68.       /*
  69.        * XXX kludge to make Date: header appear first.
  70.        */
  71.       t->next = x->next;        /* unlink new header */
  72.       m->last = t;
  73.       x->next = h;            /* cons it to front of list */
  74.       m->headers = x;
  75.       }
  76.   }
  77.   if (!m->message_id) {
  78.       char temp[256];
  79.       extern int mm_patch_level;
  80.  
  81.       sprintf (temp, "<CMM.%d.%d.%d.%ld.%s@%s>",
  82.            mm_major_version, mm_minor_version, mm_patch_level, time(0), 
  83.            user_name, fullhostname);
  84.       m->message_id = new_header (MESSAGE_ID, "Message-ID", HEAD_KNOWN, m);
  85.       m->message_id->string = safe_strcpy (temp);
  86.   }
  87.  
  88.   /* build recipient lists */
  89.   mailit = build_recipients (&argv, &Files, m);
  90.   /* do we need to file this? */
  91.   saveit = *saved_messages_file &&
  92.       strcmp (saved_messages_file, "/dev/null") != 0;
  93.   fileit = Files || saveit;
  94.   signature = maybe_append_signature();
  95.  
  96.   /*
  97.    * Remind the user of who's on the recipient list
  98.    */
  99.   if (send_verbose && !sendmail_verbose) {
  100.     int i;
  101.  
  102.     for (i = 1; argv[i]; i++)
  103.     if (argv[i][0] != '-')
  104.         break;
  105.  
  106.     while (argv[i] != NULL) {
  107.       printf ("%s... Queued\n", argv[i]);
  108.       i++;
  109.     }
  110.   }
  111.  
  112.   if (!sendmail_verbose && !send_verbose) {
  113.     printf("Sending... "); fflush(stdout);
  114.   }
  115.  
  116.   /*
  117.    * Fire up sendmail for non-file recipients
  118.    */
  119.   if (mailit) {
  120.       extern int sendmail_background;
  121.  
  122.       tfp = message_tempfile (m, signature, true);
  123.       if (tfp) {
  124.       
  125.       fix_signals_for_fork (true);    /* reset SIGCHLD */
  126.       
  127.       pid = vfork ();
  128.       if (pid == 0) {
  129.           int n;
  130.           
  131.           (void) close (0);
  132.           (void) dup (fileno (tfp));
  133.           
  134.           for (n = 3; n < 20; ++n)
  135.           (void) close (n);
  136.           
  137.           new_process_group ();
  138.           
  139.           (void) execv (SENDMAIL, argv);
  140.           _exit (errno);
  141.       }
  142.       if (pid > 0)
  143.           if (sendmail_background)
  144.           maybe_wait_for_process (pid);
  145.           else
  146.           wait_for_process (pid);
  147.       else
  148.           fprintf (stderr, "?Could not invoke %s: %s",
  149.                SENDMAIL, errstr (errno));
  150.       
  151.       fix_signals_for_fork (false);    /* reenable SIGCHLD handler */
  152.       
  153.       fclose (tfp);
  154.       }
  155.       else
  156.       failed = true;
  157.   }
  158.  
  159.   /*
  160.    * Deliver the message to any specified files
  161.    */
  162.   if (fileit) {
  163.       tfp = message_tempfile (m, NULL, false);
  164.  
  165.       if (tfp) {
  166.       if (Files != NULL) {
  167.           if (!deliver_to_files(tfp, m, Files))
  168.           failed = true;
  169.           rewind(tfp);
  170.       }
  171.  
  172.       if (saveit) {
  173.           char *av[2];
  174.           av[0] = saved_messages_file;
  175.           av[1] = nil;
  176.  
  177.           if (!deliver_to_files (tfp, m, av))
  178.           failed = true;
  179.       }
  180.       fclose (tfp);
  181.       }
  182.       else
  183.       failed = true;
  184.   }
  185.  
  186.   if (!sendmail_verbose && !send_verbose && !failed)
  187.       printf ("Done.\n");
  188.  
  189.   if (argv) {
  190.       for (i = 0; argv[i]; i++)
  191.       free (argv[i]);
  192.       free (argv);
  193.   }
  194.   if (signature)
  195.       free (signature);
  196.   return (!failed);
  197. }
  198.  
  199.     
  200.  
  201.  
  202. /*
  203.  * write_addresses:
  204.  * write the header name (i.e "To:", "Cc:") followed by a folded list of 
  205.  * recipients to the temp file
  206.  */
  207.  
  208. write_addresses (tfp, h, expand) 
  209. FILE *tfp;
  210. headers *h;
  211. int expand;
  212. {
  213.   int c = 0;                /* count what column we are up to */
  214.   addresslist *a = h->address;        /* point at addresses */
  215.   addr_unit *oau,*au = a->first;    /* point at first address unit */
  216.   
  217.   char *addr;                /* the address string */
  218.   int i;
  219.   addr_unit *addr_to_str();
  220.   int first = TRUE;            /* true if this is the first address */
  221.   int wrote_header = FALSE;
  222.  
  223.   
  224.   if (au) {                /* we have an address unit */
  225.     fprintf (tfp, "%s:", h->name);    /* write header name */
  226.     c += strlen(h->name) + 1;        /* update column count */
  227.     wrote_header = TRUE;
  228.   }
  229.  
  230.   while (au) {
  231.     oau = au;
  232.     au = addr_to_str (au, &addr, expand); /* get next address string and */
  233.                     /* update au to next address unit */
  234.  
  235.     if (addr) {
  236.     if (!first &&            /* if not first address */
  237.         !(oau->prev->type == ADR_GROUP ||
  238.           oau->prev->type == ADR_AL_EXPAND ||
  239.           oau->type == ADR_GROUPEND))
  240.     {
  241.         fputc (',', tfp);        /* put a ',' at end of the prev addr */
  242.         c++;
  243.     }
  244.     else 
  245.         first = FALSE;
  246.                     /* >>> use term width instead <<< */
  247.     if (c + (i = strlen(addr)) + 1 > 78) {
  248.         fprintf (tfp, "\n%*s", INDENT, ""); /* end this line */
  249.         c = INDENT;            /* reset to beginning of line */
  250.                     /* (plus indentation) */
  251.     }
  252.  
  253.     fprintf (tfp, " %s", addr);    /* display the address */
  254.     c += i+1;            /* increment by address length */
  255.     }
  256.   }
  257.   if (wrote_header)
  258.     fputc('\n', tfp);            /* terminate with new line */
  259. }
  260.  
  261.  
  262. /*
  263.  * addr_to_str:
  264.  * Address takes a pointer to an address unit, and a pointer to a char
  265.  * pointer.  It creates a string containing the address as it should be 
  266.  * written in the header and sets addr to point to it.
  267.  * It returns an updated address unit pointer (skips past a group end
  268.  * if the au was pointing at a group head originally).
  269.  */
  270.  
  271. addr_unit *
  272. addr_to_str (au, addr, expand)
  273. addr_unit *au;
  274. char **addr; 
  275. int expand;
  276. {
  277.   static int saw_alias = false;
  278.   switch (au->type) {
  279.   case ADR_ADDRESS:            /* simple address */
  280.     *addr = (char *) malloc(strlen(au->data)+1);/* allocate space for addr */
  281.     strcpy (*addr, au->data);        /* copy the address string */
  282.     au = au->next;            /* move on to the next address unit */
  283.     return (au);
  284.   case ADR_GROUP:            /* address group */
  285.     *addr = (char *) malloc (strlen(au->data)+4); /* space for group name */
  286.                     /* and ": ;" */
  287.     if (!expand) {
  288.     sprintf (*addr, "%s: ;", au->data);    /* write group name */
  289.     while (au->next && au->next->type != ADR_GROUPEND)
  290.         au = au->next;            /* skip all group members */
  291.     au = au->next->next;        /* skip over group end */
  292.     return (au);
  293.     }
  294.     sprintf(*addr, "%s: ", au->data);
  295.     return(au->next);
  296.   case ADR_GROUPEND:
  297.     if (saw_alias && !expand) {
  298.     saw_alias = false;
  299.     *addr = NULL;
  300.     return(au->next);
  301.     }
  302.     if (!expand) {
  303.     fprintf (stderr, "address: Found unexpected ADR_GROUPEND\n");
  304.     return (NULL);
  305.     }
  306.     *addr = (char *) malloc(strlen(";") + 1);
  307.     strcpy(*addr, ";");
  308.     return(au->next);
  309.  case ADR_AL_EXPAND:
  310.     if (!expand) {
  311.     return(au->next);
  312.     }
  313.     else {
  314.     *addr = (char *) malloc (strlen(au->data)+3);/* space for group name */
  315.                     /* and ": " */
  316.     sprintf(*addr, "%s: ", au->data);
  317.     saw_alias = true;
  318.     return(au->next);
  319.     }
  320.   case ADR_FILE:
  321.     *addr = (char *) malloc(strlen(au->data)+2);
  322.     sprintf (*addr, "*%s", au->data);
  323.     au = au->next;
  324.     return (au);
  325.   default:
  326.     fprintf (stderr, "address: bogus type\n");
  327.     return (NULL);
  328.   }
  329. }
  330.  
  331.  
  332. /*
  333.  * write_sender:
  334.  * add a sender field of the form:
  335.  * Sender: Personal Name <username@hostname>
  336.  */
  337.  
  338. write_sender(tfp) FILE *tfp; {
  339.   char *sender, *create_sender();
  340.  
  341.   sender = create_sender();        /* create the sender header */
  342.   fprintf (tfp, "Sender: %s\n", sender); /* write out the sender */
  343. }
  344.  
  345. /*
  346.  * create_sender:
  347.  * create the sender field
  348.  */
  349.  
  350. char *
  351. create_sender()
  352. {
  353.   struct passwd *p, *getpwuid();
  354.   static char buf[256];            /* this should be large enough */
  355.                     /* (famous last words) */
  356.   if (real_personal_name != NULL)
  357.     sprintf (buf, "%s <%s@%s>", real_personal_name, user_name, 
  358.          fullhostname);
  359.   else
  360.     sprintf (buf, "%s@%s", user_name, fullhostname);
  361.   return (buf);
  362. }
  363.  
  364.  
  365.  
  366. /*
  367.  * build_recipients:
  368.  * Create an argv for sendmail(8) and a list of file recipients
  369.  * from the mail msg passed.
  370.  * Arguments:
  371.  *    char ***argvp: Pointer to argv (char **)
  372.  *    char ***Filesp: Pointer to array of file names
  373.  *    mail_msg *m: The message we are sending
  374.  * Returns:
  375.  *    Nothing.  Always returns.
  376.  */
  377.  
  378. build_recipients
  379. (argvp, Filesp, m)
  380. char ***argvp, ***Filesp;
  381. mail_msg *m;
  382. {
  383.   int argcount = 0;            /* argument count */
  384.   int filecount = 0;            /* file recipient count */
  385.   char **add_string();            /* add a string to the argv */
  386.   int i;
  387.   int smargs;
  388.  
  389.   *argvp = add_string (*argvp, &argcount, SENDMAIL); /* argv[0] prog name */
  390.   i = 0;
  391.  
  392.   /*
  393.    * Tell sendmail not to treat "." by itself as EOF
  394.    */
  395.   *argvp = add_string (*argvp, &argcount, "-oi");
  396.  
  397.   /*
  398.    * include ourself in any alias expansion
  399.    */
  400.   *argvp = add_string (*argvp, &argcount, "-om");
  401.  
  402.   /*
  403.    * If sendmail-verbose is true, add the debugging option
  404.    */
  405.   if (sendmail_verbose)
  406.     *argvp = add_string (*argvp, &argcount, "-v");
  407.  
  408.   smargs = argcount;            /* remember number of args */
  409.   if (m->resent_to) {            /* the Resent-To: list */
  410.     add_recipients (argvp, Filesp, &argcount, &filecount, m->resent_to); 
  411.   } else {
  412.     if (m->to)                /* the To: list */
  413.       add_recipients (argvp, Filesp, &argcount, &filecount, m->to); 
  414.     if (m->cc)                /* the Cc: list */
  415.       add_recipients (argvp, Filesp, &argcount, &filecount, m->cc); 
  416.     if (m->bcc)                /* the Bcc: list */
  417.       add_recipients (argvp, Filesp, &argcount, &filecount, m->bcc); 
  418.     if (m->fcc)                /* the Bcc: list */
  419.       add_recipients (argvp, Filesp, &argcount, &filecount, m->fcc); 
  420.   }
  421.  
  422.   if (argcount % ALLOCINC == 0)        /* no room for null */
  423.     *argvp = (char **) safe_realloc (*argvp, /* get more space */
  424.                   (argcount+1)*sizeof(char *)); 
  425.   (*argvp)[argcount] = NULL;        /* tie off with a null */
  426.   if (*Filesp) {
  427.     if (filecount % ALLOCINC == 0)    /* no room for null */
  428.       *Filesp = (char **) safe_realloc (*Filesp, /* get more space */
  429.                      (filecount+1)*sizeof(char *)); 
  430.     (*Filesp)[filecount] = NULL;    /* tie off with a null */
  431.   }
  432.  
  433.   return (argcount != smargs);        /* did we have recipients? */
  434. }
  435.  
  436.  
  437. /*
  438.  * add_string:
  439.  * Add a string to the argv array and update the count c.
  440.  * Returns a possibly updated char **argv.
  441.  */
  442.  
  443. char **
  444. add_string (argv, c, s) char **argv; int *c; char *s; {
  445.   if (*c % ALLOCINC == 0)        /* need more room */
  446.     argv = (char **) safe_realloc (argv,    /* get more space */
  447.                 (*c+ALLOCINC)*sizeof(char *)); 
  448.   argv[*c] = (char *) malloc (strlen(s)+1); /* space for the string */
  449.   strcpy (argv[*c], s);            /* copy the string into arg list */
  450.   (*c)++;                /* increment arg count */
  451.   return (argv);
  452. }
  453.  
  454.  
  455. /*
  456.  * add_recipients:
  457.  * Add recipients in header h to argv and update the count c
  458.  * Returns a possibly different char **argv (if it needs to realloc 
  459.  * more for more arguments).
  460.  */
  461.  
  462. add_recipients (argvp, Filesp, argcount, filecount, h) 
  463. char ***argvp, ***Filesp; 
  464. int *argcount, *filecount; headers *h; 
  465. {
  466.   addresslist *a = h->address;        /* point at addresses */
  467.   addr_unit *au = a->first;        /* point at first address unit */
  468.  
  469.   while (au) {                /* step through all addr_units */
  470.     switch (au->type) {
  471.     case ADR_ADDRESS:            /* real address */
  472.       if (*argcount % ALLOCINC == 0)    /* need more room */
  473.     *argvp = (char **) safe_realloc (*argvp, 
  474.                       (*argcount+ALLOCINC)*sizeof(char *));
  475.  
  476.       (*argvp)[*argcount] = (char *) malloc (strlen(au->data)+1);
  477.       if (au->data[0] == '\\')
  478.     strcpy ((*argvp)[*argcount], au->data+1); /* copy addr into arg list */
  479.       else
  480.     strcpy ((*argvp)[*argcount], au->data);
  481.       (*argcount)++;            /* increment arg count */
  482.       break;
  483.     case ADR_GROUP:            /* group head */
  484.     case ADR_AL_EXPAND:
  485.     case ADR_GROUPEND:            /* group end */
  486.       break;                /* do nothing, skip over */
  487.     case ADR_FILE:            /* recipient is file */
  488.       if (*filecount % ALLOCINC == 0)    /* need more room */
  489.     *Filesp = (char **) safe_realloc (*Filesp, 
  490.                        (*filecount+ALLOCINC)*sizeof(char *));
  491.       (*Filesp)[*filecount] = (char *) malloc (strlen(au->data)+1);
  492.       strcpy ((*Filesp)[*filecount], au->data); /* copy fname into list */
  493.       (*filecount)++;            /* increment file count */
  494.       break;
  495.     default:
  496.       fprintf (stderr, "add_recipients: invalid addr_unit type\n");
  497.       return;
  498.     }
  499.     au = au->next;            /* go on to the next addr_unit */
  500.   }
  501. }
  502.  
  503.  
  504. /*
  505.  * deliver_to_files:
  506.  * deliver outgoing message to files by 'copying' the message
  507.  * Note: The sendmail temp file is read into a string and a
  508.  * message struct is created.  This message struct is copied to
  509.  * all specified files.
  510.  */
  511.  
  512. deliver_to_files (tfp, m, Files)
  513. FILE *tfp;
  514. mail_msg *m;
  515. char **Files;
  516. {
  517.   int i = 0;
  518.   struct stat sbuf;
  519.   int fsize;
  520.   char *msgtext;
  521.   message msg;
  522.   int failed = 0;
  523.  
  524.   if (fstat(fileno(tfp), &sbuf) != 0) {
  525.     perror ("fstat");
  526.     return (FALSE);
  527.   }
  528.   fsize = sbuf.st_size;            /* get file size */
  529.   if ((msgtext = (char *) malloc (fsize+1)) == NULL) {
  530.     fprintf (stderr, "?Out of memory\n");
  531.     return (FALSE);
  532.   }
  533.  
  534.   /* read temp file into string */
  535.   if (fread(msgtext, sizeof(char), fsize, tfp) != fsize) {
  536.     fprintf (stderr, "?Could not reread message\n");
  537.     free (msgtext);
  538.     return (FALSE);
  539.   }
  540.   msgtext[fsize] = '\0';        /* tie off with a null */
  541.  
  542.   /* fill in required parts of message struct */
  543.   msg.text = msgtext;            /* of course! */
  544.   time (&msg.date);            /* need a date */
  545.   msg.size = strlen(msg.text);        /* message size */
  546.   msg.from = NULL;            /* no from */
  547.   msg.keywords = NULL;            /* init keywords */
  548.   get_incoming_keywords(NULL, &msg);    /* fill in keywords */
  549.   msg.keybits = 0;            /* no keybits set */
  550.   msg.flags = 0;            /* no flags */
  551.  
  552.   while (Files[i] != NULL) {        /* for all recipient files */
  553.     msgvec *df, *getdestfile();
  554.  
  555.     if (sendmail_verbose || send_verbose) {
  556.       printf ("*%s... ", Files[i]); fflush(stdout);
  557.     }
  558.     if ((df = getdestfile(Files[i],-1,false)) == NULL) { /* open the file */
  559.       failed++;
  560.       if (sendmail_verbose || send_verbose) 
  561.     printf ("Failed - file may be busy, or not in proper format\n");
  562.     }
  563.     else {
  564.       (*msg_ops[df->type].wr_msg) (df, &msg, 0, WR_COPY); /* copy the msg */
  565.       (*msg_ops[df->type].close) (df->filep); /* close the file */
  566.       free (df);
  567.       if (sendmail_verbose || send_verbose)
  568.     printf ("Sent\n");
  569.     }
  570.     i++;                /* on to the next file */
  571.   }
  572.   if (failed) {                /* failed on delivery to a file */
  573.     char dlname[MAXPATHLEN+1];
  574.     msgvec *dlf, *getdestfile();
  575.     
  576.     sprintf (dlname, "%s/%s%d", HOME, PRE_DEADLETTER, PID);
  577.     if ((dlf = getdestfile(dlname,-1,false)) == NULL) { /* open the file */
  578.       if (sendmail_verbose || send_verbose) 
  579.     printf ("Dead letter file may be busy, or not in proper format\n");
  580.     }
  581.     else {
  582.       (*msg_ops[dlf->type].wr_msg) (dlf, &msg, 0, WR_COPY);
  583.       (*msg_ops[dlf->type].close) (dlf->filep); /* close the file */
  584.       free (dlf);
  585.       printf ("Failed message saved in %s\n", dlname);
  586.     }
  587.   }
  588.   return (TRUE);
  589. }
  590.  
  591.  
  592. /*
  593.  * maybe_append_signature:
  594.  * check variable append_signature, and existence of signature file
  595.  * and possibly read it in, returning the text.
  596.  */
  597.  
  598. char *
  599. maybe_append_signature()
  600. {
  601.   char sigfile[MAXPATHLEN+1];
  602.   struct stat sbuf;
  603.   int sigsize;
  604.   char *signature = NULL;
  605.   int sfd;
  606.  
  607.   if (append_signature == SET_NO)    /* they don't want it */
  608.     return (NULL);
  609.   sprintf (sigfile, "%s/%s", HOME, SIGNATURE); /* create path */
  610.   if (stat (sigfile, &sbuf) != 0) {    /* stat the file */
  611.     if (errno != ENOENT)
  612.       perror (sigfile);
  613.     return (NULL);
  614.   }
  615.   if (append_signature == SET_ASK) {
  616.     if (!yesno ("Append signature? ", "yes"))
  617.       return (NULL);
  618.   }
  619.   /* if we get here, it was SET_ASK and they said YES or it was SET_YES */
  620.   sigsize = sbuf.st_size;        /* get size of file */
  621.   if ((signature = (char *) malloc (sigsize+2)) == NULL) { /* get mem */
  622.     fprintf (stderr, "?out of memory trying to read %s\n", sigfile);
  623.     return (NULL);
  624.   }
  625.   if ((sfd = open (sigfile, O_RDONLY, 0)) < 0) { /* open for read */
  626.     perror (sigfile);
  627.     free (signature);
  628.     return (NULL);
  629.   }
  630.   if (read (sfd, signature, sigsize) != sigsize) {
  631.     perror (sigfile);
  632.     close (sfd);
  633.     free (signature);
  634.     return (NULL);
  635.   }
  636.   if ((sigsize > 0) && (signature[sigsize-1] != '\n')) {
  637.     signature[sigsize++] = '\n';
  638.   }
  639.   signature[sigsize] = '\0';
  640.   close (sfd);
  641.   return (signature);
  642. }
  643.  
  644.  
  645. /*
  646.  * valid_from_field:
  647.  * check to see if the supplied string is a valid From: field.
  648.  */ 
  649.  
  650. valid_from_field (str)
  651. char *str;
  652. {
  653.     int result = true;
  654.     char *cp, *sender, *from, *host, *create_sender();
  655.  
  656.     sender = create_sender();
  657.     str = (char *) safe_strcpy (str);    /* our personal copy */
  658.  
  659.     if (ustrcmp (sender, str) == 0)    /* from is identical to sender  */
  660.     goto accept;
  661.  
  662.     if ((from = index (str, '<')) == NULL) /* strip out up to '<' */
  663.     from = str;
  664.     else {
  665.     from++;
  666.     if ((cp = index (from, '>')) != NULL)
  667.         *cp = '\0';            /* chop of at '>' */
  668.     }
  669.     if ((host = index (from, '@')) != NULL)
  670.     *host++ = '\0';            /* point at host string */
  671.  
  672.     if (ustrcmp (from, user_name) != 0)
  673.     goto reject;            /* incorrect user name */
  674.  
  675.     if (host == NULL)
  676.     goto accept;            /* right user, no host specified */
  677.  
  678.     if (ustrcmp (host, fullhostname) == 0 ||
  679.     ustrcmp (host, shorthostname) == 0 ||
  680.     ustrcmp (host, mailhostname) == 0)
  681.     goto accept;
  682.  
  683.  reject:
  684.   result = false;
  685.  accept:
  686.   free (str);
  687.   return result;
  688. }
  689.  
  690.  
  691. /*
  692.  * cmd_who:
  693.  */
  694.  
  695. cmd_who(n)
  696. int n;
  697. {
  698.   static fdb text_fdb = { _CMTXT, CM_SDH, nil, nil,
  699.                   "recipient name, text string" };
  700.   extern fdb aliasfdb;
  701.  
  702.   noise ("is");
  703.   aliasfdb._cmdat = (pdat) mk_alias_keys();
  704.   aliasfdb._cmdef = nil;
  705.   parse (fdbchn(&aliasfdb, &text_fdb, nil), &pv, &used);
  706.  
  707.   if (used == &text_fdb)
  708.     sendmail_who(atmbuf);
  709.   else {                /* an alias */
  710.     int i;
  711.  
  712.     i = pv._pvint;
  713.     confirm();
  714.     disp_alias(stdout, i, false, true);
  715.   }
  716.   return (true);
  717. }
  718.  
  719.  
  720. /*
  721.  * sendmail_who:
  722.  * run sendmail(8) to expand mail address 'str'
  723.  */
  724.  
  725. sendmail_who (str) char *str; {
  726.   FILE *pp, *mm_popen();
  727.   char cmd[BUFSIZ];
  728.   char buf[BUFSIZ];
  729.   int len, choplen;
  730.   
  731.   if (strlen (str) == 0)
  732.     cmerr ("No name to expand");
  733.   sprintf (cmd, "%s %s", sendmail_who_cmd, 
  734.        (strcmp (str, ".") == 0) ? user_name : str);
  735.   if ((pp = mm_popen (cmd, "r")) == NULL) { /* start up sendmail(8) */
  736.     perror ("sendmail");
  737.     return;
  738.   }
  739.   choplen = strlen("... deliverable");
  740.   while (fgets(buf, BUFSIZ, pp) != NULL) { /* while we have output from */
  741.     len = strlen(buf);            /* sendmail(8) */
  742.     buf[--len] = '\0';            /* get rid of the newline */
  743.     if (strcmp(&buf[len-choplen], "... deliverable") == 0)
  744.     buf[len-choplen] = '\0';        /* chop of deliverable msg */
  745.     printf ("%s\n", buf);
  746.   }
  747.   mm_pclose(pp);
  748. }
  749.  
  750.  
  751. /*
  752.  * cmd_route:
  753.  * set or unset mail routing (forwarding) for user.
  754.  */
  755.  
  756. cmd_route (n) 
  757. int n; 
  758. {
  759. #ifndef FORWARD_FILE
  760.   cmerr ("The ROUTE command is not supported on this system");
  761. #else
  762.   char fname[MAXPATHLEN];
  763.   char *text, *parse_text();
  764.   char *cp, *index();
  765.   FILE *fp;
  766.   int err;
  767.   extern int errno;
  768.  
  769.   noise ("mail to");
  770.   /* XXX - should probably use the address parser for this */
  771.   text = parse_text ("text string\n  or confirm to remove current routing", 
  772.              NULL);
  773.   sprintf (fname, "%s/%s", HOME, FORWARD_FILE);
  774.   if (text[0] == '\0') {        /* null text parsed */
  775.     if ((unlink (fname) != 0) && (errno != ENOENT)) {
  776.       perror (fname);
  777.       return;
  778.     }
  779.     /*
  780.      * Note this can be misleading--MM should simply call a separate
  781.      * program, to allow other databases (e.g. /usr/lib/aliases) to
  782.      * be updated and/or to determine whether some other form of mail
  783.      * forwarding is in effect.
  784.      */
  785.     printf ("Mail forwarding for %s removed.\n", user_name);
  786.     return;
  787.   }
  788.  
  789.   if ((cp = index (text, '\n')) != NULL)
  790.     *cp = '\0';
  791.   if ((fp = fopen(fname, "w")) == NULL) {
  792.     fprintf (stderr, "Could not open %s - mail forwarding not modified.\n", 
  793.          fname);
  794.     return;
  795.   }
  796.   fwrite(text, sizeof(char), strlen(text), fp);
  797.   fputc('\n', fp);
  798.   err = ferror (fp);
  799.   err |= (fclose (fp) == EOF);
  800.   if (!err) {
  801.     printf ("Mail for %s will be forwarded to %s\n", user_name, text);
  802.     return;
  803.   }
  804.   fprintf (stderr, "?Error writing %s: %s\n", fname, errstr (errno));
  805.   if (unlink (fname) != 0)
  806.       fprintf (stderr, "Could not unlink %s: %s", fname, errstr (errno));
  807.   return;
  808. #endif
  809. }
  810.  
  811. /*
  812.  * show_route:
  813.  * display current mail routing
  814.  */
  815.  
  816. show_route (verbose) 
  817. int verbose;
  818. {
  819. #ifdef FORWARD_FILE
  820.   FILE *fp;
  821.   struct stat sbuf;
  822.   char buf[BUFSIZ];
  823.   char fname[MAXPATHLEN];
  824.  
  825.   sprintf (fname, "%s/%s", HOME, FORWARD_FILE);
  826.   fp = fopen (fname, "r");
  827.   if (fp) {
  828.       int c, lastchar;
  829.       printf (" Mail for %s is forwarded to ", user_name);
  830.       
  831.       while ((c = getc (fp)) != EOF)
  832.       putchar (lastchar = c);
  833.       if (lastchar == '\n')
  834.       fflush (stdout);
  835.       else
  836.       printf ("\n");
  837.       (void) fclose (fp);
  838.   }
  839. #endif /* FORWARD_FILE */
  840. }
  841.  
  842. FILE *
  843. message_tempfile (m, signature, for_sendmail)
  844. msgvec *m;
  845. char *signature;
  846. int for_sendmail;
  847. {
  848.     char *mktempfile();
  849.     char *tfile = mktempfile (PRE_SENDMAIL, TRUE);
  850.     FILE *tfp;
  851.  
  852.     if ((tfp = fopen (tfile, "w+")) == NULL) {
  853.     fprintf (stderr, "Cannot create temp file %s: %s\n",
  854.          tfile, errstr (errno));
  855.     return 0;
  856.     }
  857.     if (chmod (tfile, 0600) != 0)
  858.     fprintf (stderr, "Cannot change permissions of %s: %s\n",
  859.          tfile, errstr (errno));
  860.  
  861.     display_header (tfp, m, FALSE, for_sendmail);
  862.     fputc ('\n', tfp);
  863.     display_text (tfp, m);        /* write out the body of the message */
  864.     if (signature) {
  865.         fputc('\n', tfp);
  866.     fwrite(signature, sizeof(char), strlen(signature), tfp);
  867.     }
  868.     fflush (tfp);
  869.     rewind (tfp);            /* rewind to beginning of file */
  870.     unlink (tfile);
  871.     return tfp;
  872. }
  873.