/* * Ask the user to edit file names and other data for the given * attachment. NULL is returned if no file name is given. */ static struct attachment * read_attachment_data(struct attachment *ap, unsigned number) { char prefix[80], *cp; if (ap == NULL) ap = csalloc(1, sizeof *ap); if (ap->a_msgno) { printf("#%u\tmessage %u\n", number, ap->a_msgno); return ap; } snprintf(prefix, sizeof prefix, catgets(catd, CATSET, 50, "#%u\tfilename: "), number); for (;;) { if ((ap->a_name = readtty(prefix, ap->a_name)) == NULL) break; if (access(ap->a_name, R_OK) == 0) break; perror(ap->a_name); } if (ap->a_name && (value("attachment-ask-charset") || (cp = value("sendcharsets")) != NULL && strchr(cp, ',') != NULL)) { snprintf(prefix, sizeof prefix, "#%u\tcharset: ", number); ap->a_charset = readtty(prefix, ap->a_charset); } /* * The "attachment-ask-content-*" variables are left undocumented * since they are for RFC connoisseurs only. */ if (ap->a_name && value("attachment-ask-content-type")) { if (ap->a_content_type == NULL) ap->a_content_type = mime_filecontent(ap->a_name); snprintf(prefix, sizeof prefix, "#%u\tContent-Type: ", number); ap->a_content_type = readtty(prefix, ap->a_content_type); } if (ap->a_name && value("attachment-ask-content-disposition")) { snprintf(prefix, sizeof prefix, "#%u\tContent-Disposition: ", number); ap->a_content_disposition = readtty(prefix, ap->a_content_disposition); } if (ap->a_name && value("attachment-ask-content-id")) { snprintf(prefix, sizeof prefix, "#%u\tContent-ID: ", number); ap->a_content_id = readtty(prefix, ap->a_content_id); } if (ap->a_name && value("attachment-ask-content-description")) { snprintf(prefix, sizeof prefix, "#%u\tContent-Description: ", number); ap->a_content_description = readtty(prefix, ap->a_content_description); } return ap->a_name ? ap : NULL; }
/* * Read all relevant header fields. */ int grabh(struct header *hp, int gflags) { struct termios ttybuf; #ifndef TIOCSTI struct sigaction savequit; #else # ifdef TIOCEXT int extproc; int flag; # endif /* TIOCEXT */ #endif struct sigaction savetstp; struct sigaction savettou; struct sigaction savettin; struct sigaction act; char *s; int error; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; act.sa_handler = SIG_DFL; (void)sigaction(SIGTSTP, &act, &savetstp); (void)sigaction(SIGTTOU, &act, &savettou); (void)sigaction(SIGTTIN, &act, &savettin); error = 1; #ifndef TIOCSTI ttyset = 0; #endif if (tcgetattr(fileno(stdin), &ttybuf) < 0) { warn("tcgetattr"); return(-1); } c_erase = ttybuf.c_cc[VERASE]; c_kill = ttybuf.c_cc[VKILL]; #ifndef TIOCSTI ttybuf.c_cc[VERASE] = 0; ttybuf.c_cc[VKILL] = 0; act.sa_handler = SIG_IGN; if (sigaction(SIGQUIT, &act, &savequit) == 0 && savequit.sa_handler == SIG_DFL) (void)sigaction(SIGQUIT, &savequit, NULL); #else # ifdef TIOCEXT extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0); if (extproc) { flag = 0; if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) warn("TIOCEXT: off"); } # endif /* TIOCEXT */ #endif if (gflags & GTO) { #ifndef TIOCSTI if (!ttyset && hp->h_to != NULL) ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); #endif s = readtty("To: ", detract(hp->h_to, 0)); if (s == NULL) goto out; hp->h_to = extract(s, GTO); } if (gflags & GSUBJECT) { #ifndef TIOCSTI if (!ttyset && hp->h_subject != NULL) ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); #endif s = readtty("Subject: ", hp->h_subject); if (s == NULL) goto out; hp->h_subject = s; } if (gflags & GCC) { #ifndef TIOCSTI if (!ttyset && hp->h_cc != NULL) ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); #endif s = readtty("Cc: ", detract(hp->h_cc, 0)); if (s == NULL) goto out; hp->h_cc = extract(s, GCC); } if (gflags & GBCC) { #ifndef TIOCSTI if (!ttyset && hp->h_bcc != NULL) ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); #endif s = readtty("Bcc: ", detract(hp->h_bcc, 0)); if (s == NULL) goto out; hp->h_bcc = extract(s, GBCC); } error = 0; out: (void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTTOU, &savettou, NULL); (void)sigaction(SIGTTIN, &savettin, NULL); #ifndef TIOCSTI ttybuf.c_cc[VERASE] = c_erase; ttybuf.c_cc[VKILL] = c_kill; if (ttyset) tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); (void)sigaction(SIGQUIT, &savequit, NULL); #else # ifdef TIOCEXT if (extproc) { flag = 1; if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) warn("TIOCEXT: on"); } # endif /* TIOCEXT */ #endif return(error); }
/* * Read up a header from standard input. * The source string has the preliminary contents to * be read. * */ char * readtty(char *pr, char *src) { struct sigaction act, saveint; char ch, canonb[BUFSIZ]; char *cp, *cp2; sigset_t oset; int c; fputs(pr, stdout); fflush(stdout); if (src != NULL && strlen(src) > sizeof(canonb) - 2) { puts("too long to edit"); return(src); } #ifndef TIOCSTI if (src != NULL) cp = copy(src, canonb); /* safe, bounds checked above */ else cp = copy("", canonb); fputs(canonb, stdout); fflush(stdout); #else cp = src == NULL ? "" : src; while ((c = (unsigned char)*cp++) != '\0') { if ((c_erase != _POSIX_VDISABLE && c == c_erase) || (c_kill != _POSIX_VDISABLE && c == c_kill)) { ch = '\\'; ioctl(0, TIOCSTI, &ch); } ch = c; ioctl(0, TIOCSTI, &ch); } cp = canonb; *cp = 0; #endif sigemptyset(&act.sa_mask); act.sa_flags = 0; /* Note: will not restart syscalls */ act.sa_handler = ttyint; (void)sigaction(SIGINT, &act, &saveint); act.sa_handler = ttystop; (void)sigaction(SIGTSTP, &act, NULL); (void)sigaction(SIGTTOU, &act, NULL); (void)sigaction(SIGTTIN, &act, NULL); (void)sigprocmask(SIG_UNBLOCK, &intset, &oset); clearerr(stdin); memset(cp, 0, canonb + sizeof(canonb) - cp); for (cp2 = cp; cp2 < canonb + sizeof(canonb) - 1; ) { c = getc(stdin); switch (ttysignal) { case SIGINT: ttysignal = 0; cp2 = NULL; c = EOF; /* FALLTHROUGH */ case 0: break; default: ttysignal = 0; goto redo; } if (c == EOF || c == '\n') break; *cp2++ = c; } act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; (void)sigprocmask(SIG_SETMASK, &oset, NULL); (void)sigaction(SIGTSTP, &act, NULL); (void)sigaction(SIGTTOU, &act, NULL); (void)sigaction(SIGTTIN, &act, NULL); (void)sigaction(SIGINT, &saveint, NULL); if (cp2 == NULL) return(NULL); /* user hit ^C */ *cp2 = '\0'; if (c == EOF && ferror(stdin)) { redo: cp = strlen(canonb) > 0 ? canonb : NULL; clearerr(stdin); /* XXX - make iterative, not recursive */ return(readtty(pr, cp)); } #ifndef TIOCSTI if (cp == NULL || *cp == '\0') return(src); cp2 = cp; if (!ttyset) return(strlen(canonb) > 0 ? savestr(canonb) : NULL); while (*cp != '\0') { c = (unsigned char)*cp++; if (c_erase != _POSIX_VDISABLE && c == c_erase) { if (cp2 == canonb) continue; if (cp2[-1] == '\\') { cp2[-1] = c; continue; } cp2--; continue; } if (c_kill != _POSIX_VDISABLE && c == c_kill) { if (cp2 == canonb) continue; if (cp2[-1] == '\\') { cp2[-1] = c; continue; } cp2 = canonb; continue; } *cp2++ = c; } *cp2 = '\0'; #endif if (equal("", canonb)) return(""); return(savestr(canonb)); }
int grabh(struct header *hp, int gflags) { struct termios ttybuf; sig_t saveint; sig_t savetstp; sig_t savettou; sig_t savettin; int errs; #ifndef TIOCSTI sig_t savequit; #else # ifdef TIOCEXT int extproc, flag; # endif /* TIOCEXT */ #endif /* TIOCSTI */ savetstp = signal(SIGTSTP, SIG_DFL); savettou = signal(SIGTTOU, SIG_DFL); savettin = signal(SIGTTIN, SIG_DFL); errs = 0; #ifndef TIOCSTI ttyset = 0; #endif if (tcgetattr(fileno(stdin), &ttybuf) < 0) { warn("tcgetattr(stdin)"); return (-1); } c_erase = ttybuf.c_cc[VERASE]; c_kill = ttybuf.c_cc[VKILL]; #ifndef TIOCSTI ttybuf.c_cc[VERASE] = _POSIX_VDISABLE; ttybuf.c_cc[VKILL] = _POSIX_VDISABLE; if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL) (void)signal(SIGINT, SIG_DFL); if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL) (void)signal(SIGQUIT, SIG_DFL); #else # ifdef TIOCEXT extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0); if (extproc) { flag = 0; if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) warn("TIOCEXT: off"); } # endif /* TIOCEXT */ if (setjmp(intjmp)) goto out; saveint = signal(SIGINT, ttyint); #endif if (gflags & GTO) { #ifndef TIOCSTI if (!ttyset && hp->h_to != NULL) ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); #endif hp->h_to = extract(readtty("To: ", detract(hp->h_to, 0)), GTO); } if (gflags & GSUBJECT) { #ifndef TIOCSTI if (!ttyset && hp->h_subject != NULL) ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); #endif hp->h_subject = readtty("Subject: ", hp->h_subject); } if (gflags & GCC) { #ifndef TIOCSTI if (!ttyset && hp->h_cc != NULL) ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); #endif hp->h_cc = extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); } if (gflags & GBCC) { #ifndef TIOCSTI if (!ttyset && hp->h_bcc != NULL) ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); #endif hp->h_bcc = extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); } out: (void)signal(SIGTSTP, savetstp); (void)signal(SIGTTOU, savettou); (void)signal(SIGTTIN, savettin); #ifndef TIOCSTI ttybuf.c_cc[VERASE] = c_erase; ttybuf.c_cc[VKILL] = c_kill; if (ttyset) tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); (void)signal(SIGQUIT, savequit); #else # ifdef TIOCEXT if (extproc) { flag = 1; if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) warn("TIOCEXT: on"); } # endif /* TIOCEXT */ #endif (void)signal(SIGINT, saveint); return (errs); }
char * readtty(const char *pr, char src[]) { char ch, canonb[BUFSIZ]; int c; char *cp, *cp2; fputs(pr, stdout); (void)fflush(stdout); if (src != NULL && strlen(src) > BUFSIZ - 2) { printf("too long to edit\n"); return (src); } #ifndef TIOCSTI if (src != NULL) strlcpy(canonb, src, sizeof(canonb)); else *canonb = '\0'; fputs(canonb, stdout); (void)fflush(stdout); #else cp = src == NULL ? "" : src; while ((c = *cp++) != '\0') { if ((c_erase != _POSIX_VDISABLE && c == c_erase) || (c_kill != _POSIX_VDISABLE && c == c_kill)) { ch = '\\'; ioctl(0, TIOCSTI, &ch); } ch = c; ioctl(0, TIOCSTI, &ch); } cp = canonb; *cp = '\0'; #endif cp2 = cp; while (cp2 < canonb + BUFSIZ) *cp2++ = '\0'; cp2 = cp; if (setjmp(rewrite)) goto redo; (void)signal(SIGTSTP, ttystop); (void)signal(SIGTTOU, ttystop); (void)signal(SIGTTIN, ttystop); clearerr(stdin); while (cp2 < canonb + BUFSIZ) { c = getc(stdin); if (c == EOF || c == '\n') break; *cp2++ = c; } *cp2 = '\0'; (void)signal(SIGTSTP, SIG_DFL); (void)signal(SIGTTOU, SIG_DFL); (void)signal(SIGTTIN, SIG_DFL); if (c == EOF && ferror(stdin)) { redo: cp = strlen(canonb) > 0 ? canonb : NULL; clearerr(stdin); return (readtty(pr, cp)); } #ifndef TIOCSTI if (cp == NULL || *cp == '\0') return (src); cp2 = cp; if (!ttyset) return (strlen(canonb) > 0 ? savestr(canonb) : NULL); while (*cp != '\0') { c = *cp++; if (c_erase != _POSIX_VDISABLE && c == c_erase) { if (cp2 == canonb) continue; if (cp2[-1] == '\\') { cp2[-1] = c; continue; } cp2--; continue; } if (c_kill != _POSIX_VDISABLE && c == c_kill) { if (cp2 == canonb) continue; if (cp2[-1] == '\\') { cp2[-1] = c; continue; } cp2 = canonb; continue; } *cp2++ = c; } *cp2 = '\0'; #endif if (equal("", canonb)) return (NULL); return (savestr(canonb)); }
static char * readtty(const char *pr, char *src) { char canonb[LINESIZE]; char *cp, *cp2; int c; #ifdef TIOCSTI char ch; #endif (void)fputs(pr, stdout); (void)fflush(stdout); if (src != NULL && strlen(src) > sizeof(canonb) - 2) { (void)printf("too long to edit\n"); return src; } #ifndef TIOCSTI if (src != NULL) cp = copy(src, canonb); else cp = copy(__UNCONST(""), canonb); c = *cp; (void)fputs(canonb, stdout); (void)fflush(stdout); #else cp = src == NULL ? __UNCONST("") : src; while ((c = *cp++) != '\0') { if ((c_erase != _POSIX_VDISABLE && c == c_erase) || (c_kill != _POSIX_VDISABLE && c == c_kill)) { ch = '\\'; (void)ioctl(0, TIOCSTI, &ch); } ch = c; (void)ioctl(0, TIOCSTI, &ch); } cp = canonb; *cp = '\0'; #endif clearerr(stdin); cp2 = cp; while (cp2 < canonb + sizeof(canonb) - 1) { c = getc(stdin); sig_check(); if (c == EOF) { if (feof(stdin)) (void)putc('\n', stdout); break; } if (c == '\n') break; *cp2++ = c; } *cp2 = '\0'; if (c == EOF && ferror(stdin)) { cp = strlen(canonb) > 0 ? canonb : NULL; clearerr(stdin); return readtty(pr, cp); } #ifndef TIOCSTI if (cp == NULL || *cp == '\0') return src; if (ttyset == 0) return strlen(canonb) > 0 ? savestr(canonb) : NULL; /* * Do erase and kill. */ cp2 = cp; while (*cp != '\0') { c = *cp++; if (c_erase != _POSIX_VDISABLE && c == c_erase) { if (cp2 == canonb) continue; if (cp2[-1] == '\\') { cp2[-1] = c; continue; } cp2--; continue; } if (c_kill != _POSIX_VDISABLE && c == c_kill) { if (cp2 == canonb) continue; if (cp2[-1] == '\\') { cp2[-1] = c; continue; } cp2 = canonb; continue; } *cp2++ = c; } *cp2 = '\0'; #endif if (canonb[0] == '\0') return __UNCONST(""); return savestr(canonb); }
/* * Read all relevant header fields. * Returns 0 on success; 1 if there was an error or signal. */ PUBLIC int grabh(struct header *hp, int gflags) { sig_t volatile old_sigint; int retval; #ifndef USE_EDITLINE struct termios ttybuf; # if defined(TIOCSTI) && defined(TIOCEXT) int extproc; # endif if (save_erase_and_kill(&ttybuf)) return -1; # if defined(TIOCSTI) && defined(TIOCEXT) extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0); if (extproc) { int flag; flag = 0; if (ioctl(fileno(stdin), TIOCEXT, &flag) == -1) warn("TIOCEXT: off"); } # endif #endif /* USE_EDITLINE */ sig_check(); old_sigint = sig_signal(SIGINT, tty_sigint); /* return here if we detect a SIGINT */ if ((retval = setjmp(tty_jmpbuf)) != 0) { (void)putc('\n', stdout); goto out; } /* * Do this irrespective of whether the initial string is empty. * Otherwise, the editing is inconsistent. */ disable_erase_and_kill(&ttybuf); if (gflags & GTO) { hp->h_to = extract(readtty("To: ", detract(hp->h_to, 0)), GTO); } if (gflags & GSUBJECT) { hp->h_subject = readtty("Subject: ", hp->h_subject); } if (gflags & GCC) { hp->h_cc = extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); } if (gflags & GBCC) { hp->h_bcc = extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); } if (gflags & GSMOPTS) { hp->h_smopts = shextract(readtty("Smopts: ", detract(hp->h_smopts, 0)), GSMOPTS); } #ifdef MIME_SUPPORT if (gflags & GSMOPTS) { /* XXX - Use a new flag for this? */ if (hp->h_attach) { struct attachment *ap; int i; i = 0; for (ap = hp->h_attach; ap; ap = ap->a_flink) i++; (void)printf("Attachment%s: %d\n", i > 1 ? "s" : "", i); } } #endif out: restore_erase_and_kill(&ttybuf); #ifndef USE_EDITLINE # if defined(TIOCSTI) && defined(TIOCEXT) if (extproc) { int flag; flag = 1; if (ioctl(fileno(stdin), TIOCEXT, &flag) == -1) warn("TIOCEXT: on"); } # endif #endif (void)sig_signal(SIGINT, old_sigint); sig_check(); return retval; }