# /* sender.c * * This file contains the routines that handle tha actual sending * of mail for the mail daemon program. Mail may at present be * sent by one of four methods: locally, by direct write to the * user's mail file; remotely via tftp, to hosts which support * tftp mail; remotely via smtp, to hosts which support smtp mail; * and remotely to hosts which do not support smtp * via an smtp forwarder (here, multics). * This file includes the following routines: * send_mail dispatch to the appropriate sending method * send_frwrd forward mail to a non-tftp host * send_tftp send mail to a tftp host * send_smtp send mail to an smtp host * send-error send an error message back to originator */ #include #include #include #include "rqfile.h" #include "extern.h" #include "tcode.h" /* The following macro is a true GROT to fix a problem with stdio: EINTRs are * treated as errors; and once an error occurs on a file no more I/O may be * performed on it. This macro clears the error bit in the case of an * interrupted I/O operation so I/O may continue. */ #define intrptd(fd) (errno != EINTR?FALSE:((fd)->_flag &= ~_IOERR),TRUE) extern int errno; send_mail (mlfile, rqp) /* Send the specified mail file to the user specified in the request * record. Determine where the user is located, and dispatch to the * appropriate mail sending routine. * * Returns: * NOSAVE if message successfully sent * SAVE if a retry is needed * SKIP if a fatal error has occurred * * Arguments: */ char *mlfile; /* name of mail file to send */ register struct req_rec *rqp; /* ptr. to this request record */ { char uname[NAMSIZ]; /* temp. for user name */ char hname[NAMSIZ]; /* temp. for host name */ register int status; /* send status */ get_names (rqp->rq_name, hname, uname); /* find dest. host & user */ if (local_host (hname)) status = send_local (mlfile, rqp, uname); #ifdef PMAIL else if (pmail_host (hname)) status = send_pmail (mlfile, rqp, uname); #endif else if (tftp_host (hname)) status = send_tftp (mlfile, rqp, hname, uname); else { status = send_smtp (mlfile, rqp, hname, uname, TRUE); if (status != NOSAVE) return (send_frwrd (mlfile, rqp, hname, uname)); else return (status); } if (log) printf ("Send to %s at %s, status = %d\n", uname, hname, status); switch (status) { case TOK: return (NOSAVE); case TACESS: rerror ("Access violation on file", mlfile, 0); return (SKIP); case TFNF: rerror ("Read error on file", mlfile, 0); return (SKIP); case TNOUSR: send_error (mlfile, rqp, status); return (NOSAVE); case TDSTRB: return (SAVE); case TFRWRD: default: return (rewrite (mlfile, rqp)); } } send_frwrd (mlfile, rqp, hname, uname) /* Send the specified mail file to the mail forwarder for forwarding * to its destination host. The mail forwarder (multics) uses the * user name field of the smtp request to determine to whom the * mail is to be forwarded. * Returns the termination codes status. * * Arguments: */ char *mlfile; /* name of mail file to be sent */ struct req_rec *rqp; /* pointer to request record */ char *hname; /* name of next dest. host */ char *uname; /* name of destination user */ { return (send_smtp (mlfile, rqp, frwrd_host, uname, FALSE)); } send_tftp (mlfile, rqp, hname, uname) /* Send the specified file via tftp "mail" mode to the specified user * on the specified host. Returns the tftp termination code. * * Arguments: */ char *mlfile; /* name of file to be mailed */ struct req_rec *rqp; /* pointer to request record */ char *hname; /* name of dest. host */ char *uname; /* name of dest. user */ { register int pid; /* pid of tftp request */ register int i; /* temp. index */ int status; /* tftp return status */ int termcd; /* tftp termination code */ register int waitpid; /* pid of waited-for child */ int nmatch; /* no. of scanf matches */ int pipedes[2]; /* pipe to tftp for error code */ FILE *rdfd; /* stdio file des. for pipe */ char line[NAMSIZ]; /* line for tftp output */ pipe (pipedes); if ((pid = fork ()) == -1) { printf ("maild: can't fork for tftp\n"); return (TUNDEF); } else if (pid == 0) { /* child */ close (2); /* stderr */ dup (pipedes[1]); /* set up std. err to pipe */ for (i = 3; i < MAXFILES; i++) close (i); execl (tftp, tftp, "-p", mlfile, hname, uname, "mail", 0); faterr ("can't exec tftp\n"); } rdfd = fcons (pipedes[0], "r"); close (pipedes[1]); while (fgets (line, NAMSIZ, rdfd) != NULL) { printf ("%s", line); if ((nmatch = sscanf(line, "%*[^=]=%d", &status)) == 1) break; } while (fgets (line, NAMSIZ, rdfd) != NULL) printf ("%s", line); /* empty out pipe */ fclose (rdfd); while ((waitpid = wait (&termcd)) != pid && (waitpid == -1 && errno == EINTR)) ; if (termcd == 0) status = TOK; else if (nmatch != 1) status = TUNDEF; return (status); } send_smtp (mlfile, rqp, hname, uname, dontrewrite) /* Send the specified file via smtp to the specified user * on the specified host. Returns NOSAVE, SAVE, SKIP * according to the result of the transfer (200, 400, or 500). * The dontrewrite flag will be true if the caller doesn't want * the request file rewritten on error - this is the case if, * for example, the caller is prepared to try sending the file * a different way if smtp fails. * * Arguments: */ char *mlfile; /* name of file to be mailed */ struct req_rec *rqp; /* pointer to request record */ char *hname; /* name of dest. host */ char *uname; /* name of dest. user */ int dontrewrite; /* flag - true if caller doesn't */ /* file rewritten */ { register int pid; /* pid of tftp request */ register int i; /* temp. index */ int status; /* smtp return status */ int termcd; /* smtp termination code */ register int waitpid; /* pid of waited-for child */ int nmatch; /* no. of scanf matches */ int pipedes[2]; /* pipe to smtp for error code */ FILE *rdfd; /* stdio file des. for pipe */ char line[NAMSIZ]; /* line for smtp output */ char fromnam[NAMSIZ]; /* line for from name field */ if (!get_from (mlfile, fromnam)) { printf ("can't get from address from %s\n", mlfile); return (SKIP); } strcat (uname, "@"); strcat (uname, hname); printf ("send from %s to %s:\n", fromnam, uname); pipe (pipedes); if ((pid = fork ()) == -1) { printf ("maild: can't fork for smtp\n"); return (SAVE); } else if (pid == 0) { /* child */ close (1); /* stdout */ dup (pipedes[1]); /* set up std. out to pipe */ for (i = 3; i < MAXFILES; i++) close (i); execl (smtp, smtp, mlfile, fromnam, hname, uname, "1", 0); /* run with debug for now */ faterr ("can't exec smtp\n"); } rdfd = fcons (pipedes[0], "r"); close (pipedes[1]); for (;;) { while (fgets (line, NAMSIZ, rdfd) != NULL) { printf ("%s", line); nmatch = sscanf (line, "%d", &status); } if (feof (rdfd) || !intrptd (rdfd)) break; } fclose (rdfd); while ((waitpid = wait (&termcd)) != pid && (waitpid == -1 && errno == EINTR)) ; if (termcd == 0) return (NOSAVE); else if (dontrewrite) return (SAVE); else if (nmatch != 1 || (status / 100) == 4) return (rewrite (mlfile, rqp)); else { smtp_err (mlfile, rqp, fromnam, line); return (NOSAVE); } } send_error (mlfile, rqp, status) /* This routine is called when the number of send retries for a * given mail file have been exceeded. It attempts to mail the * mail file back to its sender (who is assumed to be the owner * of the file being mailed), enclosed in a message with * subject "maild : Unable to mail the enclosed file". If * it fails, it just gives up. * * Arguments: */ char *mlfile; /* name of file being mailed */ struct req_rec *rqp; /* ptr. to request record */ int status; /* error code */ { char filen[NAMSIZ]; /* temp for "-f" option to send */ char fromname[NAMSIZ]; /* temp for "From:" field of mlfile */ char uname[NAMSIZ]; /* temp for receiver's name */ char hname[NAMSIZ]; /* temp for dest. host */ char user[NAMSIZ]; /* to see if we sent the message */ char errstr[NAMSIZ]; /* for variable length error msgs */ int pid; /* child process's id */ int stat; /* child process status */ register char *error; /* error message */ register int i; /* temp loop index */ int waitpid; /* pid of waited-for child */ if (!get_from (mlfile, fromname)) { printf ("Can't deliver error message; bad format\n"); return; } get_names (fromname, hname, uname); scan_string (uname, user, separators); if (strcmp (user, me) == 0) { printf ("Can't deliver error message\n"); return; } if (strcmp (fromname, rqp->rq_name) == 0) { printf ("can't deliver error message - no such sender\n"); return; } switch (status) { case TACESS: error = "-SSend failed: Access Violation"; break; case TNOUSR: error = strcpy(errstr,"-SSend failed: No Such User: "); strcat (error, rqp->rq_name); break; case TLTO: error = "-SSend Failed: Host Not Responding"; break; default: error = "-SSend failed: Unknown Reason"; break; } strcpy (filen, "-F"); strcat (filen, mlfile); if ((pid = fork ()) == -1) { printf ("maild: can't fork for mail send\n"); return; } else if (pid == 0) { for (i = 2; i < MAXFILES; i++) close (i); if (!log) { close (1); open (tftplog, 1); } execl ("/bin/send", "/bin/send", fromname, error, filen, 0); } while ((waitpid = wait (&stat)) != pid && waitpid != -1); } smtp_error (mlfile, rqp, fromname, err) /* This routine is called when a "500-class" smtp error occurs. * It attempts to mail the mail file back to its sender * (whose address is fromname), enclosed in a message with * subject "maild : Unable to mail the enclosed file" and the * smtp error code. If it fails, it just gives up. * * Arguments: */ char *mlfile; /* name of file being mailed */ struct req_rec *rqp; /* ptr. to request record */ char *fromname; /* return path */ char *err; /* error line from smtp */ { char filen[NAMSIZ]; /* temp for "-f" option to send */ char error[NAMSIZ]; /* temp for "-S" option to send */ char uname[NAMSIZ]; /* temp for receiver's name */ char hname[NAMSIZ]; /* temp for dest. host */ char user[NAMSIZ]; /* to see if we sent the message */ int pid; /* child process's id */ int stat; /* child process status */ register int i; /* temp loop index */ int waitpid; /* pid of waited-for child */ get_names (fromname, hname, uname); scan_string (uname, user, separators); if (strcmp (user, me) == 0) { printf ("Can't deliver error message\n"); return; } if (strcmp (fromname, rqp->rq_name) == 0) { printf ("can't deliver error message - no such sender\n"); return; } strcpy (error, "-SUnable to deliver: "); strcat (error, err); error[strlen (error) - 1] = '\0'; /* get rid of trailing \n */ strcpy (filen, "-F"); strcat (filen, mlfile); if ((pid = fork ()) == -1) { printf ("maild: can't fork for mail send\n"); return; } else if (pid == 0) { for (i = 2; i < MAXFILES; i++) close (i); if (!log) { close (1); open (tftplog, 1); } execl ("/bin/send", "/bin/send", fromname, error, filen, 0); } while ((waitpid = wait (&stat)) != pid && waitpid != -1); }