/* * xmail - X window system interface to the mail program * * Copyright 1990,1991,1992 by National Semiconductor Corporation * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of National Semiconductor Corporation not * be used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" * WITHOUT EXPRESS OR IMPLIED WARRANTY. NATIONAL SEMICONDUCTOR CORPORATION * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Author: Michael C. Wagnitz - National Semiconductor Corporation * ** Xmail talks to mail through a pseudo terminal which is a pair of master ** and slave devices: /dev/pty?? and /dev/tty??, where ?? goes from p0 to ** zf (system dependent). The terminal is opened for both read and write. ** */ #include "global.h" #include #include #if defined(AIXV3) || defined(_IBMR2) #include #endif #if !(defined(SYSV) || defined(linux) || defined(__FreeBSD__)) || defined(clipper) #include #else #include #include #if defined(att) #include #endif #endif #if defined(sun) && defined(SVR4) #include #endif #ifndef TTYDEV #ifdef sco #define TTYDEV "/dev/ptypxx" #else /* !sco */ #ifdef hpux #define TTYDEV "/dev/pty/ptyxx" #else /* !hpux */ #define TTYDEV "/dev/ptyxx" #endif /* !sco */ #endif /* !hpux */ #endif /* !TTYDEV */ #ifndef PTYCHAR1 #ifdef sco #define PTYCHAR1 "0123456789abcdef" #else /* !sco */ #ifdef hpux #define PTYCHAR1 "zyxwvutsrqp" #else /* !hpux */ #define PTYCHAR1 "pqrstuvwxyz" #endif /* !sco */ #endif /* !hpux */ #endif /* !PTYCHAR1 */ #ifndef PTYCHAR2 #ifdef hpux #define PTYCHAR2 "fedcba9876543210" #else /* !hpux */ #define PTYCHAR2 "0123456789abcdefghijklmnopqrstuvwxyz" #endif /* !hpux */ #endif /* !PTYCHAR2 */ int mail_fd; /* mail process master tty id */ int mailpid; /* mail process id */ int mailInputId; /* mail input id */ char pseudo_tty[20]; /* ** @(#) openMaster - searches for and opens a pty master. If it finds one, ** it returns the value of the file descriptor. If not, ** it reports an error and terminates. Portions of this ** routine were stolen from X11R4 xterm get_pty() sources. */ int openMaster() { static int devindex = 0; static int letter = 0; struct stat st_buf; int master; #ifdef att (void) strcpy(pseudo_tty, "/dev/ptmx"); if ((master = open(pseudo_tty, O_RDWR)) >= 0) return(master); #else /* !att, need lots of code */ #if defined(umips) || defined(sgi) && defined (SYSV) int c; (void) strcpy(pseudo_tty, "/dev/ptc"); master = open(pseudo_tty, O_RDWR); if (master >= 0 && (fstat(master, &st_buf)) == 0) { (void) sprintf(pseudo_tty, "/dev/ttyq%d", minor(st_buf.st_rdev)); #if ! defined(sgi) if ((c = open(pseudo_tty, O_RDWR)) < 0) { (void) close (master); } else { /* got one! */ (void) close (c); return(master); } #else return(master); #endif } #else /* not (umips && SYSV) */ (void) strcpy(pseudo_tty, TTYDEV); while (PTYCHAR1[letter]) { pseudo_tty[strlen(pseudo_tty) - 2] = PTYCHAR1[letter]; pseudo_tty[strlen(pseudo_tty) - 1] = PTYCHAR2[0]; if (stat(pseudo_tty, &st_buf) == 0) while (PTYCHAR2[devindex]) { pseudo_tty[strlen(pseudo_tty) - 1] = PTYCHAR2[devindex]; if ((master = open(pseudo_tty, O_RDWR)) >= 0) return(master); devindex++; } devindex = 0; (void) letter++; } #endif /* umips || sgi && SYSV */ #endif /* att */ /* ** We were unable to allocate a pty master! Report the error and terminate. */ XtError("xmail cannot open master/slave pipe connection"); /* NOTREACHED */ } /* end - openMaster */ /* ** @(#)openSlave() - open slave side of pipe */ /* ARGSUSED */ int openSlave(master) int master; { int slave; #ifdef att char *slaveName; int grantpt(), unlockpt(); char *ptsname(); if (grantpt(master) >= 0 && unlockpt(master) >= 0 && (slaveName = ptsname(master)) != NULL && (slave = open(slaveName, O_RDWR)) >= 0 && (void) ioctl(slave, I_PUSH, "ptem") >= 0 && (void) ioctl(slave, I_PUSH, "ldterm") >= 0) return(slave); #else /* !att */ #if defined(umips) || defined(sgi) && defined(SYSV) struct stat st_buf; fstat(master, &st_buf); (void) sprintf(pseudo_tty, "/dev/ttyq%d", minor(st_buf.st_rdev)); if ((slave = open(pseudo_tty, O_RDWR)) >= 0) return(slave); /* got one! */ #else /* not (umips || sgi && SYSV) */ #if defined(sco) || defined(hpux) pseudo_tty[strlen(pseudo_tty) - 6] = 't'; #else pseudo_tty[strlen(pseudo_tty) - 5] = 't'; #endif if ((slave = open(pseudo_tty, O_RDWR)) >= 0) return(slave); #endif #endif return(-1); /* look for more master/slave pairs */ } /* openSlave */ /* ** @(#)callMail() - fork child to execute mail and attach to xmail input */ /* ARGSUSED */ void callMail(argv) char *argv[]; { #if defined(linux) || defined(__FreeBSD__) || (defined(SYSV) && !defined(clipper)) struct termios tio; #else struct sgttyb Sgtty; #endif int slave; /* file descriptor to slave pty */ for (;;) { /* find a pair, or master fails */ mail_fd = openMaster(); if ((slave = openSlave(mail_fd)) != -1) break; } /* ** Set minimal requirements for slave connection (no echo, no NL->CR, keep TABS) */ #if defined(linux) || defined(__FreeBSD__) || (defined(SYSV) && !defined(clipper)) tcgetattr(slave, &tio); tio.c_oflag &= ~(OCRNL|ONLCR|ONLRET|OXTABS); tio.c_iflag &= ~IXOFF; tio.c_iflag |= ICRNL; tio.c_lflag &= ~(ISIG|ECHO); tio.c_lflag |= ICANON; tcsetattr(slave, TCSANOW, &tio); #else (void) ioctl(slave, TIOCGETP, &Sgtty); Sgtty.sg_flags &= ~(ECHO|CRMOD|XTABS); (void) ioctl(slave, TIOCSETP, &Sgtty); #endif mailpid = fork(); if (mailpid == -1) { XtError("callMail could not fork the child process"); } else if (mailpid) { /* * Parent : close the slave side of pty * set the mail file descriptor to append mode * register mail input with X */ (void) close(slave); #ifndef linux (void) fcntl(mail_fd, F_SETFL, FAPPEND); #else (void) fcntl(mail_fd, F_SETFL, O_APPEND); #endif mailInputId = XtAddInput(mail_fd, (XtPointer)XtInputReadMask, readMail, (XtPointer)NULL); } else { /* * Child : close X connection and mail_fd side of pty * redirect stdin, stdout, stderr of mail to pty * unbuffer output data from mail * exec mail with arguments * * Use a select() call to delay starting the mail process * until our parent can close its slave side of the pipe. * Eliminates the parent hanging (for approximately 15 * seconds) on the close because the child terminated for * lack of mail before the parent could issue its close. */ int readfds, width; struct timeval timeout; (void) close(ConnectionNumber(XtDisplay(toplevel))); timeout.tv_sec = 0; timeout.tv_usec = 250000; /* 0.25 seconds */ readfds = 1 << slave; width = slave + 1; (void) select(width, (fd_set *) &readfds, (fd_set *) NULL, (fd_set *) NULL, &timeout); (void) close(mail_fd); (void) dup2(slave, 0); (void) dup2(slave, 1); (void) dup2(slave, 2); if (slave > 2) (void) close(slave); #ifndef linux (void) fcntl(1, F_SETFL, FAPPEND); #else (void) fcntl(1, F_SETFL, O_APPEND); #endif setbuf(stdout, (char *) NULL); #ifdef linux /* ANSI highlighting loses for folder buttons. */ unsetenv("TERM"); #endif (void) execvp(argv[0], argv); /* * If we fail to make contact, we must re-establish access to * the terminal screen that started us for our error message, * because we don't want to send it up the xmail pipe. * Also terminate our parent. */ if ((slave = open("/dev/tty", O_RDWR)) != -1) { (void) dup2(slave, 1); (void) dup2(slave, 2); perror(argv[0]); } (void) kill(getppid(), SIGKILL); /* kill our parent */ (void) exit(1); /* NOTREACHED */ } } /* callMail */