home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / binmail / binmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-25  |  14.0 KB  |  773 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)delivermail.c    4.36 (Berkeley) 4/21/89";
  3. static char  rcsid[] = "@(#)$Id: binmail.c,v 4.36.0.2 1991/06/25 23:55:57 paul Exp $";
  4. #endif
  5.  
  6. #include <sys/param.h>
  7. #include <sys/stat.h>
  8. #include <sys/file.h>
  9.  
  10. #include <ctype.h>
  11. #include <stdio.h>
  12. #include <pwd.h>
  13. #include <utmp.h>
  14. #include <signal.h>
  15. #include <setjmp.h>
  16. #include <sysexits.h>
  17. #include "pathnames.h"
  18.  
  19.     /* copylet flags */
  20. #define REMOTE        1        /* remote mail, add rmtmsg */
  21. #define ORDINARY    2
  22. #define ZAP        3        /* zap header and trailing empty line */
  23. #define    FORWARD        4
  24.  
  25. #define    LSIZE        256
  26. #define    MAXLET        300        /* maximum number of letters */
  27. #define    MAILMODE    0600        /* mode of created mail */
  28.  
  29. char    line[LSIZE];
  30. char    resp[LSIZE];
  31. struct let {
  32.     long    adr;
  33.     char    change;
  34. } let[MAXLET];
  35. int    nlet    = 0;
  36. char    lfil[50];
  37. long    iop, time();
  38. char    *getenv();
  39. char    *index();
  40. char    lettmp[] = _PATH_TMP;
  41. char    maildir[] = _PATH_MAILDIR;
  42. char    mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  43. char    dead[] = "dead.letter";
  44. char    forwmsg[] = " forwarded\n";
  45. FILE    *tmpf;
  46. FILE    *malf;
  47. char    my_name[60];
  48. char    *getlogin();
  49. int    error;
  50. int    changed;
  51. int    forward;
  52. char    from[] = "From ";
  53. long    ftell();
  54. int    delex();
  55. char    *ctime();
  56. int    flgf;
  57. int    flgp;
  58. int    delflg = 1;
  59. int    hseqno;
  60. jmp_buf    sjbuf;
  61. int    rmail;
  62.  
  63. main(argc, argv)
  64. char **argv;
  65. {
  66.     register int i;
  67.     char *name;
  68.     struct passwd *pwent;
  69.  
  70.     if (!(name = getlogin()) || !*name || !(pwent = getpwnam(name)) ||
  71.         getuid() != pwent->pw_uid) 
  72.         pwent = getpwuid(getuid());
  73.     strncpy(my_name, pwent ? pwent->pw_name : "???", sizeof(my_name)-1);
  74.     if (setjmp(sjbuf))
  75.         done();
  76.     for (i=SIGHUP; i<=SIGTERM; i++)
  77.         setsig(i, delex);
  78.     i = mkstemp(lettmp);
  79.     tmpf = fdopen(i, "r+");
  80.     if (i < 0 || tmpf == NULL)
  81.         panic("mail: %s: cannot open for writing", lettmp);
  82.     /*
  83.      * This protects against others reading mail from temp file and
  84.      * if we exit, the file will be deleted already.
  85.      */
  86.     unlink(lettmp);
  87.     if (argv[0][0] == 'r')
  88.         rmail++;
  89.     if (argv[0][0] != 'r' &&    /* no favors for rmail*/
  90.        (argc == 1 || argv[1][0] == '-' && !any(argv[1][1], "rhd")))
  91.         printmail(argc, argv);
  92.     else
  93.         bulkmail(argc, argv);
  94.     done();
  95. }
  96.  
  97. setsig(i, f)
  98. int i;
  99. int (*f)();
  100. {
  101.     if (signal(i, SIG_IGN) != SIG_IGN)
  102.         signal(i, f);
  103. }
  104.  
  105. any(c, str)
  106.     register int c;
  107.     register char *str;
  108. {
  109.  
  110.     while (*str)
  111.         if (c == *str++)
  112.             return(1);
  113.     return(0);
  114. }
  115.  
  116. printmail(argc, argv)
  117.     char **argv;
  118. {
  119.     int flg, i, j, print;
  120.     char *p, *getarg();
  121.     struct stat statb;
  122. #if defined(MH_LCK_BEL)
  123.     int lk_fd;
  124.     extern int lkopen(), lkclose();
  125. #endif /* MH_LCK_BEL */
  126.  
  127.     setuid(getuid());
  128.     cat(mailfile, maildir, my_name);
  129. #ifdef notdef
  130.     if (stat(mailfile, &statb) >= 0
  131.         && (statb.st_mode & S_IFMT) == S_IFDIR) {
  132.         strcat(mailfile, "/");
  133.         strcat(mailfile, my_name);
  134.     }
  135. #endif
  136.     for (; argc > 1; argv++, argc--) {
  137.         if (argv[1][0] != '-')
  138.             break;
  139.         switch (argv[1][1]) {
  140.  
  141.         case 'p':
  142.             flgp++;
  143.             /* fall thru... */
  144.         case 'q':
  145.             delflg = 0;
  146.             break;
  147.  
  148.         case 'f':
  149.             if (argc >= 3) {
  150.                 strcpy(mailfile, argv[2]);
  151.                 argv++, argc--;
  152.             }
  153.             break;
  154.  
  155.         case 'b':
  156.             forward = 1;
  157.             break;
  158.  
  159.         default:
  160.             panic("unknown option %c", argv[1][1]);
  161.             /*NOTREACHED*/
  162.         }
  163.     }
  164. #if defined(LOCKF_FLOCK)
  165.     /*
  166.          * We can't get a lock on a file that
  167.          * isn't opened for writing - sigh!
  168.          */
  169.         malf = fopen(mailfile, "r+");
  170. #else
  171.     malf = fopen(mailfile, "r");
  172. #endif /* LOCKF_FLOCK */
  173.     if (malf == NULL) {
  174.         printf("No mail.\n");
  175.         return;
  176.     }
  177. #if defined(MH_LCK_BEL)
  178.     lk_fd = lkopen(mailfile, O_RDONLY);
  179. #endif /* MH_LCK_BEL */
  180.     flock(fileno(malf), LOCK_SH);
  181.     copymt(malf, tmpf);
  182.     fclose(malf);            /* implicit unlock */
  183. #if defined(MH_LCK_BEL)
  184.     (void) lkclose(lk_fd, mailfile);
  185. #endif /* MH_LCK_BEL */
  186.     fseek(tmpf, 0L, L_SET);
  187.  
  188.     changed = 0;
  189.     print = 1;
  190.     for (i = 0; i < nlet; ) {
  191.         j = forward ? i : nlet - i - 1;
  192.         if (setjmp(sjbuf)) {
  193.             print = 0;
  194.         } else {
  195.             if (print)
  196.                 copylet(j, stdout, ORDINARY);
  197.             print = 1;
  198.         }
  199.         if (flgp) {
  200.             i++;
  201.             continue;
  202.         }
  203.         setjmp(sjbuf);
  204.         fputs("? ", stdout);
  205.         fflush(stdout);
  206.         if (fgets(resp, LSIZE, stdin) == NULL)
  207.             break;
  208.         switch (resp[0]) {
  209.  
  210.         default:
  211.             printf("usage\n");
  212.         case '?':
  213.             print = 0;
  214.             printf("q\tquit\n");
  215.             printf("x\texit without changing mail\n");
  216.             printf("p\tprint\n");
  217.             printf("s[file]\tsave (default mbox)\n");
  218.             printf("w[file]\tsame without header\n");
  219.             printf("-\tprint previous\n");
  220.             printf("d\tdelete\n");
  221.             printf("+\tnext (no delete)\n");
  222.             printf("m user\tmail to user\n");
  223.             printf("! cmd\texecute cmd\n");
  224.             break;
  225.  
  226.         case '+':
  227.         case 'n':
  228.         case '\n':
  229.             i++;
  230.             break;
  231.         case 'x':
  232.             changed = 0;
  233.         case 'q':
  234.             goto donep;
  235.         case 'p':
  236.             break;
  237.         case '^':
  238.         case '-':
  239.             if (--i < 0)
  240.                 i = 0;
  241.             break;
  242.         case 'y':
  243.         case 'w':
  244.         case 's':
  245.             flg = 0;
  246.             if (resp[1] != '\n' && resp[1] != ' ') {
  247.                 printf("illegal\n");
  248.                 flg++;
  249.                 print = 0;
  250.                 continue;
  251.             }
  252.             if (resp[1] == '\n' || resp[1] == '\0') {
  253.                 p = getenv("HOME");
  254.                 if (p != 0)
  255.                     cat(resp+1, p, "/mbox");
  256.                 else
  257.                     cat(resp+1, "", "mbox");
  258.             }
  259.             for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) {
  260.                 malf = fopen(lfil, "a");
  261.                 if (malf == NULL) {
  262.                     printf("mail: %s: cannot append\n",
  263.                         lfil);
  264.                     flg++;
  265.                     continue;
  266.                 }
  267.                 copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY);
  268.                 fclose(malf);
  269.             }
  270.             if (flg)
  271.                 print = 0;
  272.             else {
  273.                 let[j].change = 'd';
  274.                 changed++;
  275.                 i++;
  276.             }
  277.             break;
  278.         case 'm':
  279.             flg = 0;
  280.             if (resp[1] == '\n' || resp[1] == '\0') {
  281.                 i++;
  282.                 continue;
  283.             }
  284.             if (resp[1] != ' ') {
  285.                 printf("invalid command\n");
  286.                 flg++;
  287.                 print = 0;
  288.                 continue;
  289.             }
  290.             for (p = resp+1; (p = getarg(lfil, p)) != NULL; )
  291.                 if (!sendmail(j, lfil, my_name))
  292.                     flg++;
  293.             if (flg)
  294.                 print = 0;
  295.             else {
  296.                 let[j].change = 'd';
  297.                 changed++;
  298.                 i++;
  299.             }
  300.             break;
  301.         case '!':
  302.             system(resp+1);
  303.             printf("!\n");
  304.             print = 0;
  305.             break;
  306.         case 'd':
  307.             let[j].change = 'd';
  308.             changed++;
  309.             i++;
  310.             if (resp[1] == 'q')
  311.                 goto donep;
  312.             break;
  313.         }
  314.     }
  315.    donep:
  316.     if (changed)
  317.         copyback();
  318. }
  319.  
  320. /* copy temp or whatever back to /usr/spool/mail */
  321. copyback()
  322. {
  323.     register int i, c;
  324.     long oldmask;
  325.     int fd, new = 0;
  326.     struct stat stbuf;
  327. #if defined(MH_LCK_BEL)
  328.     int lk_fd;
  329.     extern int lkopen(), lkclose();
  330. #endif /* MH_LCK_BEL */
  331.  
  332.     oldmask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)|sigmask(SIGQUIT));
  333.     fd = open(mailfile, O_RDWR | O_CREAT, MAILMODE);
  334.     if (fd >= 0) {
  335. #if defined(MH_LCK_BEL)
  336.         lk_fd = lkopen(mailfile, O_RDWR);
  337. #endif /* MH_LCK_BEL */
  338.         flock(fd, LOCK_EX);
  339.         malf = fdopen(fd, "r+");
  340.     }
  341.     if (fd < 0 || malf == NULL)
  342.         panic("can't rewrite %s", lfil);
  343.     fstat(fd, &stbuf);
  344.     if (stbuf.st_size != let[nlet].adr) {    /* new mail has arrived */
  345.         fseek(malf, let[nlet].adr, L_SET);
  346.         fseek(tmpf, let[nlet].adr, L_SET);
  347.         while ((c = getc(malf)) != EOF)
  348.             putc(c, tmpf);
  349.         let[++nlet].adr = stbuf.st_size;
  350.         new = 1;
  351.         fseek(malf, 0L, L_SET);
  352.     }
  353.     ftruncate(fd, 0L);
  354.     for (i = 0; i < nlet; i++)
  355.         if (let[i].change != 'd')
  356.             copylet(i, malf, ORDINARY);
  357.     fclose(malf);        /* implict unlock */
  358. #if defined(MH_LCK_BEL)
  359.     (void) lkclose(lk_fd, mailfile);
  360. #endif /* MH_LCK_BEL */
  361.     if (new)
  362.         printf("New mail has arrived.\n");
  363.     sigsetmask(oldmask);
  364. }
  365.  
  366. /* copy mail (f1) to temp (f2) */
  367. copymt(f1, f2)
  368.     FILE *f1, *f2;
  369. {
  370.     long nextadr;
  371.  
  372.     nlet = nextadr = 0;
  373.     let[0].adr = 0;
  374.     while (fgets(line, LSIZE, f1) != NULL) {
  375.         if (isfrom(line))
  376.             let[nlet++].adr = nextadr;
  377.         nextadr += strlen(line);
  378.         fputs(line, f2);
  379.     }
  380.     let[nlet].adr = nextadr;    /* last plus 1 */
  381. }
  382.  
  383. copylet(n, f, type)
  384.     FILE *f;
  385. {
  386.     int ch;
  387.     long k;
  388.     char hostname[MAXHOSTNAMELEN];
  389.  
  390.     fseek(tmpf, let[n].adr, L_SET);
  391.     k = let[n+1].adr - let[n].adr;
  392.     while (k-- > 1 && (ch = getc(tmpf)) != '\n')
  393.         if (type != ZAP)
  394.             putc(ch, f);
  395.     switch (type) {
  396.  
  397.     case REMOTE:
  398.         gethostname(hostname, sizeof (hostname));
  399.         fprintf(f, " remote from %s\n", hostname);
  400.         break;
  401.  
  402.     case FORWARD:
  403.         fprintf(f, forwmsg);
  404.         break;
  405.  
  406.     case ORDINARY:
  407.         putc(ch, f);
  408.         break;
  409.  
  410.     case ZAP:
  411.         break;
  412.  
  413.     default:
  414.         panic("Bad letter type %d to copylet.", type);
  415.     }
  416.     while (k-- > 1) {
  417.         ch = getc(tmpf);
  418.         putc(ch, f);
  419.     }
  420.     if (type != ZAP || ch != '\n')
  421.         putc(getc(tmpf), f);
  422. }
  423.  
  424. isfrom(lp)
  425. register char *lp;
  426. {
  427.     register char *p;
  428.  
  429.     for (p = from; *p; )
  430.         if (*lp++ != *p++)
  431.             return(0);
  432.     return(1);
  433. }
  434.  
  435. bulkmail(argc, argv)
  436. char **argv;
  437. {
  438.     char *truename;
  439.     int first;
  440.     register char *cp;
  441.     char *newargv[1000];
  442.     register char **ap;
  443.     register char **vp;
  444.     int dflag;
  445.  
  446.     dflag = 0;
  447.     delflg = 0;
  448.     if (argc < 1) {
  449.         fprintf(stderr, "puke\n");
  450.         return;
  451.     }
  452.     for (vp = argv, ap = newargv + 1; (*ap = *vp++) != 0; ap++)
  453.         if (ap[0][0] == '-' && ap[0][1] == 'd')
  454.             dflag++;
  455.     if (!dflag) {
  456.         /* give it to sendmail, rah rah! */
  457.         unlink(lettmp);
  458.         ap = newargv+1;
  459.         if (rmail)
  460.             *ap-- = "-s";
  461.         *ap = "-sendmail";
  462.         setuid(getuid());
  463.         execv(_PATH_SENDMAIL, ap);
  464.         perror(_PATH_SENDMAIL);
  465.         exit(EX_UNAVAILABLE);
  466.     }
  467.  
  468.     truename = 0;
  469.     line[0] = '\0';
  470.  
  471.     /*
  472.      * When we fall out of this, argv[1] should be first name,
  473.      * argc should be number of names + 1.
  474.      */
  475.  
  476.     while (argc > 1 && *argv[1] == '-') {
  477.         cp = *++argv;
  478.         argc--;
  479.         switch (cp[1]) {
  480.         case 'r':
  481.             if (argc <= 1)
  482.                 usage();
  483.             truename = argv[1];
  484.             fgets(line, LSIZE, stdin);
  485.             if (strncmp("From", line, 4) == 0)
  486.                 line[0] = '\0';
  487.             argv++;
  488.             argc--;
  489.             break;
  490.  
  491.         case 'h':
  492.             if (argc <= 1)
  493.                 usage();
  494.             hseqno = atoi(argv[1]);
  495.             argv++;
  496.             argc--;
  497.             break;
  498.  
  499.         case 'd':
  500.             break;
  501.         
  502.         default:
  503.             usage();
  504.         }
  505.     }
  506.     if (argc <= 1)
  507.         usage();
  508.     if (truename == 0)
  509.         truename = my_name;
  510.     time(&iop);
  511.     fprintf(tmpf, "%s%s %s", from, truename, ctime(&iop));
  512.     iop = ftell(tmpf);
  513.     flgf = first = 1;
  514.     for (;;) {
  515.         if (first) {
  516.             first = 0;
  517.             if (*line == '\0' && fgets(line, LSIZE, stdin) == NULL)
  518.                 break;
  519.         } else {
  520.             if (fgets(line, LSIZE, stdin) == NULL)
  521.                 break;
  522.         }
  523.         if (*line == '.' && line[1] == '\n' && isatty(fileno(stdin)))
  524.             break;
  525.         if (isfrom(line))
  526.             putc('>', tmpf);
  527.         fputs(line, tmpf);
  528.         flgf = 0;
  529.     }
  530.     putc('\n', tmpf);
  531.     nlet = 1;
  532.     let[0].adr = 0;
  533.     let[1].adr = ftell(tmpf);
  534.     if (flgf)
  535.         return;
  536.     while (--argc > 0)
  537.         if (!sendmail(0, *++argv, truename))
  538.             error++;
  539.     if (error && safefile(dead)) {
  540.         setuid(getuid());
  541.         malf = fopen(dead, "w");
  542.         if (malf == NULL) {
  543.             printf("mail: cannot open %s\n", dead);
  544.             fclose(tmpf);
  545.             return;
  546.         }
  547.         copylet(0, malf, ZAP);
  548.         fclose(malf);
  549.         printf("Mail saved in %s\n", dead);
  550.     }
  551.     fclose(tmpf);
  552. }
  553.  
  554. sendrmt(n, name)
  555. char *name;
  556. {
  557.     FILE *rmf, *popen();
  558.     register char *p;
  559.     char rsys[64], cmd[64];
  560.     register pid;
  561.     int sts;
  562.  
  563. #ifdef notdef
  564.     if (any('^', name)) {
  565.         while (p = index(name, '^'))
  566.             *p = '!';
  567.         if (strncmp(name, "researc", 7)) {
  568.             strcpy(rsys, "research");
  569.             if (*name != '!')
  570.                 --name;
  571.             goto skip;
  572.         }
  573.     }
  574. #endif
  575.     for (p=rsys; *name!='!'; *p++ = *name++)
  576.         if (*name=='\0')
  577.             return(0);    /* local address, no '!' */
  578.     *p = '\0';
  579.     if (name[1]=='\0') {
  580.         printf("null name\n");
  581.         return(0);
  582.     }
  583. skip:
  584.     if ((pid = fork()) == -1) {
  585.         fprintf(stderr, "mail: can't create proc for remote\n");
  586.         return(0);
  587.     }
  588.     if (pid) {
  589.         while (wait(&sts) != pid) {
  590.             if (wait(&sts)==-1)
  591.                 return(0);
  592.         }
  593.         return(!sts);
  594.     }
  595.     setuid(getuid());
  596.     if (any('!', name+1))
  597.         (void)sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
  598.     else
  599.         (void)sprintf(cmd, "uux - %s!rmail %s", rsys, name+1);
  600.     if ((rmf=popen(cmd, "w")) == NULL)
  601.         exit(1);
  602.     copylet(n, rmf, REMOTE);
  603.     exit(pclose(rmf) != 0);
  604. }
  605.  
  606. usage()
  607. {
  608.  
  609.     fprintf(stderr, "Usage: mail [ -f ] people . . .\n");
  610.     error = EX_USAGE;
  611.     done();
  612. }
  613.  
  614. #include <sys/socket.h>
  615. #include <netinet/in.h>
  616. #include <netdb.h>
  617.  
  618. notifybiff(msg)
  619.     char *msg;
  620. {
  621.     static struct sockaddr_in addr;
  622.     static int f = -1;
  623.  
  624.     if (addr.sin_family == 0) {
  625.         struct hostent *hp = gethostbyname("localhost");
  626.         struct servent *sp = getservbyname("biff", "udp");
  627.  
  628.         if (hp && sp) {
  629.             addr.sin_family = hp->h_addrtype;
  630.             bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
  631.             addr.sin_port = sp->s_port;
  632.         }
  633.     }
  634.     if (addr.sin_family) {
  635.         if (f < 0)
  636.             f = socket(AF_INET, SOCK_DGRAM, 0);
  637.         if (f >= 0)
  638.             sendto(f, msg, strlen(msg)+1, 0, &addr, sizeof (addr));
  639.     }
  640. }
  641.  
  642. sendmail(n, name, fromaddr)
  643.     int n;
  644.     char *name, *fromaddr;
  645. {
  646.     char file[256];
  647.     int mask, fd;
  648.     struct passwd *pw;
  649. #ifdef notdef
  650.     struct stat statb;
  651. #endif
  652.     char buf[128];
  653. #if defined(MH_LCK_BEL)
  654.     int lk_fd;
  655.     extern int lkopen(), lkclose();
  656. #endif /* MH_LCK_BEL */
  657.  
  658.     if (*name=='!')
  659.         name++;
  660.     if (any('!', name))
  661.         return (sendrmt(n, name));
  662.     if ((pw = getpwnam(name)) == NULL) {
  663.         printf("mail: can't send to %s\n", name);
  664.         return(0);
  665.     }
  666.     cat(file, maildir, name);
  667. #ifdef notdef
  668.     if (stat(file, &statb) >= 0 && (statb.st_mode & S_IFMT) == S_IFDIR) {
  669.         strcat(file, "/");
  670.         strcat(file, name);
  671.     }
  672. #endif
  673.     if (!safefile(file))
  674.         return(0);
  675.     fd = open(file, O_WRONLY | O_CREAT, MAILMODE);
  676.     if (fd >= 0) {
  677. #if defined(MH_LCK_BEL)
  678.         lk_fd = lkopen(mailfile, O_RDWR);
  679. #endif /* MH_LCK_BEL */
  680.         flock(fd, LOCK_EX);
  681.         malf = fdopen(fd, "a");
  682.     }
  683.     if (fd < 0 || malf == NULL) {
  684.         close(fd);
  685.         printf("mail: %s: cannot append\n", file);
  686.         return(0);
  687.     }
  688.     fchown(fd, pw->pw_uid, pw->pw_gid);
  689.     (void)sprintf(buf, "%s@%ld\n", name, ftell(malf));
  690.     copylet(n, malf, ORDINARY);
  691.     fclose(malf);
  692. #if defined(MH_LCK_BEL)
  693.     (void) lkclose(lk_fd, mailfile);
  694. #endif /* MH_LCK_BEL */
  695.  
  696.     notifybiff(buf);
  697.     return(1);
  698. }
  699.  
  700. delex(i)
  701. {
  702.     if (i != SIGINT) {
  703.         setsig(i, SIG_DFL);
  704.         sigsetmask(sigblock(0L) &~ sigmask(i));
  705.     }
  706.     putc('\n', stderr);
  707.     if (delflg)
  708.         longjmp(sjbuf, 1);
  709.     if (error == 0)
  710.         error = i;
  711.     done();
  712. }
  713.  
  714. done()
  715. {
  716.  
  717.     unlink(lettmp);
  718.     exit(error);
  719. }
  720.  
  721. cat(to, from1, from2)
  722.     char *to, *from1, *from2;
  723. {
  724.     register char *cp, *dp;
  725.  
  726.     cp = to;
  727.     for (dp = from1; *cp = *dp++; cp++)
  728.         ;
  729.     for (dp = from2; *cp++ = *dp++; )
  730.         ;
  731. }
  732.  
  733. /* copy p... into s, update p */
  734. char *
  735. getarg(s, p)
  736.     register char *s, *p;
  737. {
  738.     while (*p == ' ' || *p == '\t')
  739.         p++;
  740.     if (*p == '\n' || *p == '\0')
  741.         return(NULL);
  742.     while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
  743.         *s++ = *p++;
  744.     *s = '\0';
  745.     return(p);
  746. }
  747.  
  748. safefile(f)
  749.     char *f;
  750. {
  751.     struct stat statb;
  752.  
  753.     if (lstat(f, &statb) < 0)
  754.         return (1);
  755.     if (statb.st_nlink != 1 || (statb.st_mode & S_IFMT) == S_IFLNK) {
  756.         fprintf(stderr,
  757.             "mail: %s has more than one link or is a symbolic link\n",
  758.             f);
  759.         return (0);
  760.     }
  761.     return (1);
  762. }
  763.  
  764. panic(msg, a1, a2, a3)
  765.     char *msg;
  766. {
  767.  
  768.     fprintf(stderr, "mail: ");
  769.     fprintf(stderr, msg, a1, a2, a3);
  770.     fprintf(stderr, "\n");
  771.     done();
  772. }
  773.