/***********************************************************************1* *2* This software is part of the BSD package *3*Copyright (c) 1978-2006 The Regents of the University of California an*4* *5* Redistribution and use in source and binary forms, with or *6* without modification, are permitted provided that the following *7* conditions are met: *8* *9* 1. Redistributions of source code must retain the above *10* copyright notice, this list of conditions and the *11* following disclaimer. *12* *13* 2. Redistributions in binary form must reproduce the above *14* copyright notice, this list of conditions and the *15* following disclaimer in the documentation and/or other *16* materials provided with the distribution. *17* *18* 3. Neither the name of The Regents of the University of California*19* names of its contributors may be used to endorse or *20* promote products derived from this software without *21* specific prior written permission. *22* *23* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *24* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *25* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *26* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *27* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS *28* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *29* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED *30* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *31* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *32* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *33* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *34* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *35* POSSIBILITY OF SUCH DAMAGE. *36* *37* Redistribution and use in source and binary forms, with or without *38* modification, are permitted provided that the following conditions *39* are met: *40* 1. Redistributions of source code must retain the above copyright *41* notice, this list of conditions and the following disclaimer. *42* 2. Redistributions in binary form must reproduce the above copyright *43* notice, this list of conditions and the following disclaimer in *44* the documentation and/or other materials provided with the *45* distribution. *46* 3. Neither the name of the University nor the names of its *47* contributors may be used to endorse or promote products derived *48* from this software without specific prior written permission. *49* *50* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" *51* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *52* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *53* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS *54* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *55* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *56* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *57* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *58* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *59* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *60* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *61* SUCH DAMAGE. *62* *63* Kurt Shoens (UCB) *64* gsf *65* *66***********************************************************************/67#pragma prototyped68/*69* Mail -- a mail program70*71* Interactive header editing.72*/7374#include "mailx.h"7576/*77* tty stuff swiped from ksh78*/7980#ifdef _hdr_termios81# include <termios.h>82# if __sgi__ || sgi /* special hack to eliminate ^M problem */83# ifndef ECHOCTL84# define ECHOCTL ECHOE85# endif /* ECHOCTL */86# ifndef CNSUSP87# define CNSUSP CNSWTCH88# endif /* CNSUSP */89# endif /* sgi */90# ifdef _NEXT_SOURCE91# define _lib_tcgetattr 192# define _lib_tcgetpgrp 193# endif /* _NEXT_SOURCE */94#else95# if defined(_sys_termios) && defined(_lib_tcgetattr)96# include <sys/termios.h>97# define _hdr_termios98# else99# undef _sys_termios100# endif /* _sys_termios */101#endif /* _hdr_termios */102103#ifdef _hdr_termios104# undef _hdr_sgtty105# undef tcgetattr106# undef tcsetattr107# undef tcgetpgrp108# undef tcsetpgrp109# undef cfgetospeed110# ifndef TCSANOW111# define TCSANOW TCSETS112# define TCSADRAIN TCSETSW113# define TCSAFLUSH TCSETSF114# endif /* TCSANOW */115/* The following corrects bugs in some implementations */116# if defined(TCSADFLUSH) && !defined(TCSAFLUSH)117# define TCSAFLUSH TCSADFLUSH118# endif /* TCSADFLUSH */119# ifndef _lib_tcgetattr120# undef tcgetattr121# define tcgetattr(fd,tty) ioctl(fd, TCGETS, tty)122# undef tcsetattr123# define tcsetattr(fd,action,tty) ioctl(fd, action, tty)124# undef cfgetospeed125# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)126# endif /* _lib_tcgetattr */127# undef TIOCGETC128# if SHOPT_OLDTERMIO /* use both termios and termio */129# ifdef _hdr_termio130# include <termio.h>131# else132# ifdef _sys_termio133# include <sys/termio.h>134# define _hdr_termio 1135# else136# undef SHOPT_OLDTERMIO137# endif /* _sys_termio */138# endif /* _hdr_termio */139# endif /* SHOPT_OLDTERMIO */140#else141# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)142# undef SHOPT_OLDTERMIO143# ifdef _hdr_termio144# include <termio.h>145# else146# ifdef _sys_termio147# include <sys/termio.h>148# define _hdr_termio 1149# endif /* _sys_termio */150# endif /* _hdr_termio */151# ifdef _hdr_termio152# define termios termio153# undef TIOCGETC154# define tcgetattr(fd,tty) ioctl(fd, TCGETA, tty)155# define tcsetattr(fd,action,tty) ioctl(fd, action, tty)156157# ifdef _sys_bsdtty158# include <sys/bsdtty.h>159# endif /* _sys_bsdtty */160# else161# ifdef _hdr_sgtty162# include <sgtty.h>163# ifndef LPENDIN164# ifdef _sys_nttyio165# include <sys/nttyio.h>166# endif /* _sys_nttyio */167# endif /* LPENDIN */168# define termios sgttyb169# ifdef TIOCSETN170# undef TCSETAW171# endif /* TIOCSETN */172# ifdef TIOCGETP173# define tcgetattr(fd,tty) ioctl(fd, TIOCGETP, tty)174# define tcsetattr(fd,action,tty) ioctl(fd, action, tty)175# else176# define tcgetattr(fd,tty) gtty(fd, tty)177# define tcsetattr(fd,action,tty) stty(fd, tty)178# endif /* TIOCGETP */179# endif /* _hdr_sgtty */180# endif /* hdr_termio */181182# ifndef TCSANOW183# ifdef TCSETAW184# define TCSANOW TCSETA185# ifdef u370186/* delays are too long, don't wait for output to drain */187# define TCSADRAIN TCSETA188# else189# define TCSADRAIN TCSETAW190# endif /* u370 */191# define TCSAFLUSH TCSETAF192# else193# ifdef TIOCSETN194# define TCSANOW TIOCSETN195# define TCSADRAIN TIOCSETN196# define TCSAFLUSH TIOCSETP197# endif /* TIOCSETN */198# endif /* TCSETAW */199# endif /* TCSANOW */200#endif /* _hdr_termios */201202/* set ECHOCTL if driver can echo control charaters as ^c */203#ifdef LCTLECH204# ifndef ECHOCTL205# define ECHOCTL LCTLECH206# endif /* !ECHOCTL */207#endif /* LCTLECH */208#ifdef LNEW_CTLECH209# ifndef ECHOCTL210# define ECHOCTL LNEW_CTLECH211# endif /* !ECHOCTL */212#endif /* LNEW_CTLECH */213#ifdef LNEW_PENDIN214# ifndef PENDIN215# define PENDIN LNEW_PENDIN216# endif /* !PENDIN */217#endif /* LNEW_PENDIN */218#ifndef ECHOCTL219# ifndef VEOL220# define RAWONLY 1221# endif /* !VEOL */222#endif /* !ECHOCTL */223224/*225* Output label on wfd and return next char on rfd with no echo.226* Return < -1 is -(signal + 1).227*/228229int230ttyquery(int rfd, int wfd, const char* label)231{232register int r;233int n;234unsigned char c;235struct termios old;236struct termios tty;237238if (!label)239n = 0;240else if (n = strlen(label))241write(wfd, label, n);242tcgetattr(rfd, &old);243tty = old;244tty.c_cc[VTIME] = 0;245tty.c_cc[VMIN] = 1;246tty.c_lflag &= ~(ICANON|ECHO|ECHOK|ISIG);247tcsetattr(rfd, TCSADRAIN, &tty);248if ((r = read(rfd, &c, 1)) == 1) {249if (c == old.c_cc[VEOF])250r = -1;251else if (c == old.c_cc[VINTR])252r = -(SIGINT + 1);253else if (c == old.c_cc[VQUIT])254r = -(SIGQUIT + 1);255else if (c == '\r')256r = '\n';257else258r = c;259}260tcsetattr(rfd, TCSADRAIN, &old);261if (n) {262write(wfd, "\r", 1);263while (n-- > 0)264write(wfd, " ", 1);265write(wfd, "\r", 1);266}267return r;268}269270/*271* Edit buf on rfd,wfd with label.272* Do not backspace over label.273*/274275int276ttyedit(int rfd, int wfd, const char* label, char* buf, size_t size)277{278register int r;279register int last = strlen(buf);280unsigned char c;281struct termios old;282struct termios tty;283284size--;285if (label)286write(wfd, label, strlen(label));287if (last)288write(wfd, buf, last);289tcgetattr(rfd, &old);290tty = old;291tty.c_cc[VTIME] = 0;292tty.c_cc[VMIN] = 1;293tty.c_lflag &= ~(ICANON|ECHO|ECHOK|ISIG);294tcsetattr(rfd, TCSADRAIN, &tty);295for (;;) {296if ((r = read(rfd, &c, 1)) <= 0)297break;298if (c == old.c_cc[VERASE]) {299if (last == 0)300write(wfd, "\a", 1);301else {302write(wfd, "\b \b", 3);303last--;304}305}306else if (c == old.c_cc[VKILL]) {307memset(buf, '\b', last);308write(wfd, buf, last);309memset(buf, ' ', last);310write(wfd, buf, last);311memset(buf, '\b', last);312write(wfd, buf, last);313last = 0;314}315else if (c == old.c_cc[VEOF]) {316r = last;317break;318}319else if (c == old.c_cc[VINTR]) {320r = -(SIGINT + 1);321break;322}323else if (c == old.c_cc[VQUIT]) {324r = -(SIGQUIT + 1);325break;326}327else if (last > size) {328r = -1;329break;330}331else {332if (c == '\r')333c = '\n';334buf[last++] = c;335write(wfd, &buf[last - 1], 1);336if (c == '\n') {337r = --last;338break;339}340r = last;341}342}343tcsetattr(rfd, TCSADRAIN, &old);344if (r >= 0)345buf[last] = 0;346return r;347}348349/*350* Edit the fields in type.351*/352353void354grabedit(struct header* hp, unsigned long type)355{356register char* s;357register const struct lab* lp;358int r;359sig_t saveint;360sig_t savequit;361char buf[LINESIZE];362363fflush(stdout);364if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)365signal(SIGINT, SIG_DFL);366if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)367signal(SIGQUIT, SIG_DFL);368r = 0;369for (lp = state.hdrtab; lp->name; lp++)370if (type & lp->type) {371if (!(s = detract(hp, lp->type)))372s = "";373if (strlen(s) >= sizeof(buf)) {374note(0, "%sfield too long to edit", lp->name);375continue;376}377strcpy(buf, s);378if ((r = ttyedit(0, 1, lp->name, buf, sizeof(buf))) < 0)379break;380headclear(hp, lp->type);381extract(hp, lp->type, buf);382}383if (saveint != SIG_DFL)384signal(SIGINT, saveint);385if (savequit != SIG_DFL)386signal(SIGQUIT, savequit);387if (r < -1)388kill(0, -(r + 1));389}390391392