home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume15 / xmail / part04 / callMail.c < prev    next >
C/C++ Source or Header  |  1991-10-29  |  9KB  |  292 lines

  1. /*
  2.  * xmail - X window system interface to the mail program
  3.  *
  4.  * Copyright 1989 The University of Texas at Austin
  5.  *
  6.  * Author:    Po Cheung
  7.  * Date:    March 10, 1989
  8.  *
  9.  * Permission to use, copy, modify, and distribute this software and
  10.  * its documentation for any purpose and without fee is hereby granted,
  11.  * provided that the above copyright notice appear in all copies and that
  12.  * both that copyright notice and this permission notice appear in
  13.  * supporting documentation.  The University of Texas at Austin makes no 
  14.  * representations about the suitability of this software for any purpose.  
  15.  * It is provided "as is" without express or implied warranty.
  16.  *
  17.  * Copyright 1990,1991 by National Semiconductor Corporation
  18.  *
  19.  * Permission to use, copy, modify, and distribute this software and its
  20.  * documentation for any purpose is hereby granted without fee, provided that
  21.  * the above copyright notice appear in all copies and that both that
  22.  * copyright notice and this permission notice appear in supporting
  23.  * documentation, and that the name of National Semiconductor Corporation not
  24.  * be used in advertising or publicity pertaining to distribution of the
  25.  * software without specific, written prior permission.
  26.  *
  27.  * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
  28.  * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS"
  29.  * WITHOUT EXPRESS OR IMPLIED WARRANTY.  NATIONAL SEMICONDUCTOR CORPORATION
  30.  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  31.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
  32.  * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
  33.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  34.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  35.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  36.  * PERFORMANCE OF THIS SOFTWARE.
  37.  *
  38.  * Author:  Michael C. Wagnitz - National Semiconductor Corporation
  39.  *
  40. **  Xmail talks to mail through a pseudo terminal which is a pair of master
  41. **  and slave devices: /dev/pty?? and /dev/tty??, where ?? goes from p0 to
  42. **  zf (system dependent).  The terminal is opened for both read and write.
  43. **
  44. */
  45.  
  46. #include    "global.h"
  47. #include    <sys/stat.h>
  48. #include    <signal.h>
  49.  
  50. #if    !defined(SYSV) || defined(clipper)
  51. #include    <sgtty.h>
  52. #else
  53. #include    <sys/termio.h>
  54. #if    defined(att)
  55. #include    <sys/sysmacros.h>
  56. #include    <fcntl.h>
  57. #include    <sys/stropts.h>
  58. #endif
  59. #endif
  60.  
  61. #ifndef TTYDEV
  62. #ifdef        hpux
  63. #define TTYDEV        "/dev/pty/ptyxx"
  64. #else    /* !hpux */
  65. #define    TTYDEV        "/dev/ptyxx"
  66. #endif    /* !hpux */
  67. #endif    /* !TTYDEV */
  68.  
  69. #ifndef PTYCHAR1
  70. #ifdef        hpux
  71. #define PTYCHAR1    "zyxwvutsrqp"
  72. #else    /* !hpux */
  73. #define    PTYCHAR1    "pqrstuvwxyz"
  74. #endif    /* !hpux */
  75. #endif    /* !PTYCHAR1 */
  76.  
  77. #ifndef PTYCHAR2
  78. #ifdef        hpux
  79. #define    PTYCHAR2    "fedcba9876543210"
  80. #else    /* !hpux */
  81. #define    PTYCHAR2    "0123456789abcdef"
  82. #endif    /* !hpux */
  83. #endif    /* !PTYCHAR2 */
  84.  
  85. int                mail_fd;        /* mail process master tty id */
  86. int                mailpid;        /* mail process id */
  87. int                mailInputId;        /* mail input id */
  88. char        pseudo_tty[20];
  89.  
  90.  
  91. /*
  92. ** @(#) openMaster - searches for and opens a pty master.  If it finds one,
  93. **             it returns the value of the file descriptor.  If not,
  94. **             it reports an error and terminates.  Portions of this
  95. **             routine were stolen from X11R4 xterm get_pty() sources.
  96. */
  97. int
  98. openMaster()
  99. {
  100.  static int    devindex = 0;
  101.  static int    letter = 0;
  102.  struct    stat    st_buf;
  103.  int        master;
  104.  
  105. #ifdef att
  106.  (void) strcpy(pseudo_tty, "/dev/ptmx");
  107.  if ((master = open(pseudo_tty, O_RDWR)) >= 0)
  108.     return(master);
  109. #else /* !att, need lots of code */
  110. #if defined(umips) && defined (SYSV)
  111.  int        c;
  112.  
  113.  (void) strcpy(pseudo_tty, "/dev/ptc");
  114.  master = open(pseudo_tty, O_RDWR);
  115.  if (master >= 0 && (fstat(master, &st_buf)) == 0) {
  116.     (void) sprintf(pseudo_tty, "/dev/ttyq%d", minor(st_buf.st_rdev));
  117.     if ((c = open(pseudo_tty, O_RDWR)) < 0) {
  118.        (void) close (master);
  119.       } else {                /* got one! */
  120.        (void) close (c);
  121.        return(master);
  122.       }
  123.    }
  124. #else /* not (umips && SYSV) */
  125.  (void) strcpy(pseudo_tty, TTYDEV);
  126.  while (PTYCHAR1[letter]) {
  127.        pseudo_tty[strlen(pseudo_tty) - 2] = PTYCHAR1[letter];
  128.        pseudo_tty[strlen(pseudo_tty) - 1] = PTYCHAR2[0];
  129.  
  130.        if (stat(pseudo_tty, &st_buf) == 0)
  131.           while (PTYCHAR2[devindex]) {
  132.                 pseudo_tty[strlen(pseudo_tty) - 1] = PTYCHAR2[devindex];
  133.                 if ((master = open(pseudo_tty, O_RDWR)) >= 0)
  134.                    return(master);
  135.  
  136.                 devindex++;
  137.                }
  138.        devindex = 0;
  139.        (void) letter++;
  140.       }
  141. #endif /* umips && SYSV */
  142. #endif /* att */
  143. /*
  144. ** We were unable to allocate a pty master!  Report the error and terminate.
  145. */
  146.  XtError("xmail cannot open master/slave pipe connection");
  147.  /* NOTREACHED */
  148. } /* end - openMaster */
  149.  
  150.  
  151. /*
  152. ** @(#)openSlave() - open slave side of pipe
  153. */
  154. /* ARGSUSED */
  155. int
  156. openSlave(master)
  157. int    master;
  158. {
  159.  int        slave;
  160.  
  161. #ifdef att
  162.  char        *slaveName;
  163.  int        grantpt(), unlockpt();
  164.  char        *ptsname();
  165.  
  166.  if (grantpt(master) >= 0 &&
  167.     unlockpt(master) >= 0 &&
  168.     (slaveName = ptsname(master)) != NULL &&
  169.     (slave = open(slaveName, O_RDWR)) >= 0 &&
  170.     (void) ioctl(slave, I_PUSH, "ptem") >= 0 &&
  171.     (void) ioctl(slave, I_PUSH, "ldterm") >= 0)
  172.     return(slave);
  173. #else /* !att */
  174. #if defined(umips) && defined (SYSV)
  175.  struct    stat    st_buf;
  176.  
  177.  fstat(master, &st_buf);
  178.  (void) sprintf(pseudo_tty, "/dev/ttyq%d", minor(st_buf.st_rdev));
  179.  if ((slave = open(pseudo_tty, O_RDWR)) >= 0)
  180.     return(slave);                /* got one! */
  181. #else /* not (umips && SYSV) */
  182.  pseudo_tty[strlen(pseudo_tty) - 5] = 't';
  183.  if ((slave = open(pseudo_tty, O_RDWR)) >= 0)
  184.     return(slave);
  185. #endif
  186. #endif
  187.  return(-1);                /* look for more master/slave pairs */
  188. } /* openSlave */
  189.  
  190.  
  191. /*
  192. ** @(#)callMail() - fork child to execute mail and attach to xmail input
  193. */
  194. /* ARGSUSED */
  195. void
  196. callMail(argv)
  197. char *argv[];
  198. {
  199. #if defined(SYSV)  && !defined(clipper)
  200.  struct termio    tio;
  201. #else    
  202.  struct sgttyb    Sgtty;
  203. #endif
  204.  int        slave;            /* file descriptor to slave pty */
  205.  char        *Mailpgm;        /* name of executable Mailpgm */
  206.  
  207.  
  208.  if (! (Mailpgm = (char *)getenv("XMAILER")))    /* first looks up env var */
  209.     Mailpgm = DEFAULT_MAILER;
  210.   
  211.  for (;;) {                /* until we find a pair, or master fails */
  212.      mail_fd = openMaster();
  213.      if ((slave = openSlave(mail_fd)) != -1)
  214.         break;
  215.     }
  216. /*
  217. ** Set minimal requirements for slave connection (no echo, no NL->CR, keep TABS)
  218. */
  219. #if defined(SYSV) && !defined(clipper)
  220.  (void) ioctl(slave, TCGETA, &tio);
  221.  tio.c_oflag &= ~(OCRNL|ONLRET|TABDLY);
  222.  tio.c_oflag &= ICRNL;
  223.  tio.c_lflag &= ~(ISIG|ECHO|IXOFF);
  224.  (void) ioctl(slave, TCSETA, &tio);
  225. #else    
  226.  (void) ioctl(slave, TIOCGETP, &Sgtty);
  227.  Sgtty.sg_flags &= ~(ECHO|CRMOD|XTABS);
  228.  (void) ioctl(slave, TIOCSETP, &Sgtty);
  229. #endif
  230.  
  231.  mailpid = fork();
  232.  if (mailpid == -1) {
  233.     XtError("callMail could not fork the child process");
  234.    } else if (mailpid) { 
  235.              /* 
  236.               * Parent : close the slave side of pty
  237.               *          set the mail file descriptor to append mode
  238.               *          register mail input with X
  239.               */
  240.              (void) close(slave);
  241.              (void) fcntl(mail_fd, F_SETFL, FAPPEND);
  242.              mailInputId = XtAddInput(mail_fd, XtInputReadMask, readMail, NULL);
  243.             } else { 
  244.              /* 
  245.               * Child : close X connection and mail_fd side of pty
  246.               *         redirect stdin, stdout, stderr of mail to pty
  247.               *         unbuffer output data from mail
  248.               *         exec mail with arguments
  249.               *
  250.               *         Use a select() call to delay starting the mail process
  251.               *         until our parent can close its slave side of the pipe.
  252.               *         Eliminates the parent hanging (for approximately 15
  253.               *         seconds) on the close because the child terminated for
  254.               *         lack of mail before the parent could issue its close.
  255.               */
  256.              int        readfds, width;
  257.              struct timeval    timeout;
  258.  
  259.              (void) close(ConnectionNumber(XtDisplay(toplevel)));
  260.  
  261.              timeout.tv_sec = 0; timeout.tv_usec = 250000; /* 0.25 seconds */
  262.              readfds = 1 << slave; width = slave + 1;
  263.  
  264.              (void) select(width, (fd_set *) &readfds, (fd_set *) NULL, (fd_set *) NULL, &timeout);
  265.  
  266.              (void) close(mail_fd);
  267.              (void) dup2(slave, 0);
  268.              (void) dup2(slave, 1);
  269.              (void) dup2(slave, 2);
  270.              if (slave > 2)
  271.                  (void) close(slave);
  272.              (void) fcntl(1, F_SETFL, FAPPEND);
  273.              setbuf(stdout, (char *) NULL);
  274.              argv[0] = Mailpgm;
  275.              (void) execvp(Mailpgm, argv);
  276.              /*
  277.               * If we fail to make contact, we must re-establish access to
  278.               * the terminal screen that started us for our error message,
  279.               * because we don't want to send it up the xmail pipe.
  280.               * Also terminate our parent.
  281.               */
  282.              if ((slave = open("/dev/tty", O_RDWR)) != -1) {
  283.                 (void) dup2(slave, 1);
  284.                 (void) dup2(slave, 2);
  285.                 perror(Mailpgm);
  286.                }
  287.              (void) kill(getppid(), SIGKILL);        /* kill our parent */
  288.              (void) exit(1);
  289.              /* NOTREACHED */
  290.             }
  291. } /* callMail */
  292.