|
|
1.1 root 1: #ident "@(#)tty.c 1.4 'attmail mail(1) command'"
2: #ident "@(#)mailx:tty.c 1.9.2.1"
3: /* Copyright (c) 1984 AT&T */
4: /* All Rights Reserved */
5:
6: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
7: /* The copyright notice above does not evidence any */
8: /* actual or intended publication of such source code. */
9:
10: #ident "@(#)mailx:tty.c 1.9"
11: /*
12: * mailx -- a modified version of a University of California at Berkeley
13: * mail program
14: *
15: * Generally useful tty stuff.
16: */
17:
18: #include "rcv.h"
19:
20: #ifdef USG_TTY
21: #include <sys/termio.h>
22:
23: static void Echo();
24: static int countcol();
25: static void outstr();
26: static char *readtty();
27: static void resetty();
28: static void rubout();
29: static int savetty();
30: static int setty();
31:
32: static int c_erase; /* Current erase char */
33: static int c_kill; /* Current kill char */
34: static int c_intr; /* interrupt char */
35: static int c_quit; /* quit character */
36: static int c_word; /* Current word erase char */
37: static int Col; /* current output column */
38: static int Pcol; /* end column of prompt string */
39: static int Out; /* file descriptor of stdout */
40: static struct termio savtty, ttybuf;
41: static char canonb[LINESIZE]; /* canonical buffer for input */
42: /* processing */
43: static int erasing; /* we are erasing characters */
44:
45: #ifdef SIGCONT
46: # ifdef preSVr4
47: typedef int sig_atomic_t; /* syntax, please -- adb */
48: # endif
49: static sig_atomic_t hadcont; /* Saw continue signal */
50: /*ARGSUSED*/
51: static void
52: ttycont(s)
53: {
54: hadcont++;
55: }
56:
57: /*ARGSUSED*/
58: static void
59: ttystop(s)
60: {
61: resetty();
62: kill(mypid, SIGSTOP);
63: }
64: #endif
65:
66: /*
67: * Read all relevant header fields.
68: */
69:
70: grabh(hp, gflags, subjtop)
71: register struct header *hp;
72: {
73: #ifdef SIGCONT
74: void (*savecont)();
75: void (*savestop)();
76: #endif
77: if (savetty())
78: return -1;
79: #ifdef SIGCONT
80: # ifdef preSVr4
81: savecont = sigset(SIGCONT, ttycont);
82: savestop = sigset(SIGTSTP, ttycont);
83: # else
84: {
85: struct sigaction nsig, osig;
86: nsig.sa_handler = ttycont;
87: sigemptyset(&nsig.sa_mask);
88: nsig.sa_flags = 0;
89: (void) sigaction(SIGCONT, &nsig, &osig);
90: savecont = osig.sa_handler;
91: nsig.sa_handler = ttystop;
92: sigemptyset(&nsig.sa_mask);
93: nsig.sa_flags = 0;
94: (void) sigaction(SIGTSTP, &nsig, &osig);
95: savestop = osig.sa_handler;
96: }
97: # endif
98: #endif
99: if (gflags & GSUBJECT && subjtop) {
100: hp->h_subject = readtty("Subject: ", hp->h_subject);
101: if (hp->h_subject != NOSTR)
102: hp->h_seq++;
103: }
104: if (gflags & GTO) {
105: hp->h_to = addto(NOSTR, readtty("To: ", hp->h_to));
106: if (hp->h_to != NOSTR)
107: hp->h_seq++;
108: }
109: if (gflags & GCC) {
110: hp->h_cc = addto(NOSTR, readtty("Cc: ", hp->h_cc));
111: if (hp->h_cc != NOSTR)
112: hp->h_seq++;
113: }
114: if (gflags & GBCC) {
115: hp->h_bcc = addto(NOSTR, readtty("Bcc: ", hp->h_bcc));
116: if (hp->h_bcc != NOSTR)
117: hp->h_seq++;
118: }
119: if (gflags & GSUBJECT && !subjtop) {
120: hp->h_subject = readtty("Subject: ", hp->h_subject);
121: if (hp->h_subject != NOSTR)
122: hp->h_seq++;
123: }
124: #ifdef SIGCONT
125: # ifdef preSVr4
126: (void) sigset(SIGCONT, savecont);
127: (void) sigset(SIGTSTP, savestop);
128: # else
129: {
130: struct sigaction nsig;
131: nsig.sa_handler = savecont;
132: sigemptyset(&nsig.sa_mask);
133: nsig.sa_flags = SA_RESTART;
134: (void) sigaction(SIGCONT, &nsig, (struct sigaction*)0);
135: nsig.sa_handler = savestop;
136: (void) sigaction(SIGTSTP, &nsig, (struct sigaction*)0);
137: }
138: # endif
139: #endif
140: return(0);
141: }
142:
143: /*
144: * Read up a header from standard input.
145: * The source string has the preliminary contents to
146: * be read.
147: *
148: */
149:
150: static char *
151: readtty(pr, src)
152: char pr[], src[];
153: {
154: int c;
155: register char *cp, *cp2;
156:
157: erasing = 0;
158: fflush(stdout);
159: Col = 0;
160: outstr(pr);
161: Pcol = Col;
162: if (src != NOSTR && strlen(src) > LINESIZE - 2) {
163: printf("too long to edit\n");
164: return(src);
165: }
166: if (setty())
167: return(src);
168: cp2 = src==NOSTR ? "" : src;
169: for (cp=canonb; *cp2; cp++, cp2++)
170: *cp = *cp2;
171: *cp = '\0';
172: outstr(canonb);
173:
174: for (;;) {
175: fflush(stdout);
176: #ifdef SIGCONT
177: hadcont = 0;
178: #endif
179: c = getc(stdin);
180:
181: if (c==c_erase) {
182: if (cp > canonb)
183: if (cp[-1]=='\\' && !erasing) {
184: *cp++ = (char)c;
185: Echo(c);
186: } else {
187: rubout(--cp);
188: }
189: } else if (c==c_kill) {
190: if (cp > canonb && cp[-1]=='\\') {
191: *cp++ = (char)c;
192: Echo(c);
193: } else while (cp > canonb) {
194: rubout(--cp);
195: }
196: } else if (c==c_word) {
197: if (cp > canonb)
198: if (cp[-1]=='\\' && !erasing) {
199: *cp++ = (char)c;
200: Echo(c);
201: } else {
202: while (--cp >= canonb)
203: if (!isspace(*cp))
204: break;
205: else
206: rubout(cp);
207: while (cp >= canonb)
208: if (!isspace(*cp))
209: rubout(cp--);
210: else
211: break;
212: if (cp < canonb)
213: cp = canonb;
214: else if (*cp)
215: cp++;
216: }
217: } else if (c==EOF || ferror(stdin) || c==c_intr || c==c_quit) {
218: #ifdef SIGCONT
219: if (hadcont) {
220: (void) setty();
221: outstr("(continue)\n");
222: Col = 0;
223: outstr(pr);
224: *cp = '\0';
225: outstr(canonb);
226: clearerr(stdin);
227: continue;
228: }
229: #endif
230: resetty();
231: savedead(c==c_quit? SIGQUIT: SIGINT);
232: } else switch (c) {
233: case '\n':
234: case '\r':
235: resetty();
236: putchar('\n');
237: fflush(stdout);
238: if (canonb[0]=='\0')
239: return(NOSTR);
240: return(savestr(canonb));
241: default:
242: erasing = 0;
243: *cp++ = (char)c;
244: *cp = '\0';
245: Echo(c);
246: }
247: }
248: }
249:
250: static int
251: savetty()
252: {
253: Out = fileno(stdout);
254: if (ioctl(Out, TCGETA, &savtty) < 0)
255: { perror("ioctl");
256: return(-1);
257: }
258: c_erase = savtty.c_cc[VERASE];
259: c_kill = savtty.c_cc[VKILL];
260: c_intr = savtty.c_cc[VINTR];
261: c_quit = savtty.c_cc[VQUIT];
262: c_word = 'W' & 037; /* erase word character */
263: ttybuf = savtty;
264: #ifdef u370
265: ttybuf.c_cflag &= ~PARENB; /* disable parity */
266: ttybuf.c_cflag |= CS8; /* character size = 8 */
267: #endif /* u370 */
268: ttybuf.c_cc[VTIME] = 0;
269: ttybuf.c_cc[VMIN] = 1;
270: ttybuf.c_iflag &= ~(BRKINT);
271: ttybuf.c_lflag &= ~(ICANON|ISIG|ECHO);
272: return 0;
273: }
274:
275: static int
276: setty()
277: {
278: if (ioctl(Out, TCSETAW, &ttybuf) < 0) {
279: perror("ioctl");
280: return(-1);
281: }
282: return(0);
283: }
284:
285: static void
286: resetty()
287: {
288: if (ioctl(Out, TCSETAW, &savtty) < 0)
289: perror("ioctl");
290: }
291:
292: static void
293: outstr(s)
294: register char *s;
295: {
296: while (*s)
297: Echo(*s++);
298: }
299:
300: static void
301: rubout(cp)
302: register char *cp;
303: {
304: register int oldcol;
305: register int c = *cp;
306:
307: erasing = 1;
308: *cp = '\0';
309: switch (c) {
310: case '\t':
311: oldcol = countcol();
312: do
313: putchar('\b');
314: while (--Col > oldcol);
315: break;
316: case '\b':
317: if (isprint(cp[-1]))
318: putchar(*(cp-1));
319: else
320: putchar(' ');
321: Col++;
322: break;
323: default:
324: if (isprint(c)) {
325: fputs("\b \b", stdout);
326: Col--;
327: }
328: }
329: }
330:
331: static int
332: countcol()
333: {
334: register int col;
335: register char *s;
336:
337: for (col=Pcol, s=canonb; *s; s++)
338: switch (*s) {
339: case '\t':
340: while (++col % 8)
341: ;
342: break;
343: case '\b':
344: col--;
345: break;
346: default:
347: if (isprint(*s))
348: col++;
349: }
350: return(col);
351: }
352:
353: static void
354: Echo(cc)
355: {
356: char c = (char)cc;
357:
358: switch (c) {
359: case '\t':
360: do
361: putchar(' ');
362: while (++Col % 8);
363: break;
364: case '\b':
365: if (Col > 0) {
366: putchar('\b');
367: Col--;
368: }
369: break;
370: case '\r':
371: case '\n':
372: Col = 0;
373: fputs("\r\n", stdout);
374: break;
375: default:
376: if (isprint(c)) {
377: Col++;
378: putchar(c);
379: }
380: }
381: }
382:
383: getbaud() /* for compatibility with V9 -- adb */
384: {
385: struct termio tbuf;
386: int baud;
387:
388: outtty = isatty(1);
389: if (ioctl(1, TCGETA, &tbuf)==0)
390: baud = tbuf.c_cflag & CBAUD;
391: else
392: baud = B9600;
393: if( baud < B1200 ) return(5);
394: else if (baud == B1200) return(10);
395: else return(20);
396: }
397:
398: /* end USG_TTY */
399: #else
400: #include <sys/ttyio.h>
401: static int c_erase; /* Current erase char */
402: static int c_kill; /* Current kill char */
403: static int hadcont; /* Saw continue signal */
404: static jmp_buf rewrite; /* Place to go when continued */
405: #ifndef TIOCSTI
406: static int ttyset; /* We must now do erase/kill */
407: #endif
408: static char *readtty(); /* adb */
409:
410: /*
411: * Read all relevant header fields.
412: */
413:
414: grabh(hp, gflags, subjtop)
415: struct header *hp;
416: {
417: struct sgttyb ttybuf;
418: void ttycont(), signull();
419: void (*savecont)();
420: register int s;
421: int errs;
422: #ifndef TIOCSTI
423: void (*savesigs[2])();
424: #endif
425:
426: #ifdef SIGCONT
427: savecont = sigset(SIGCONT, signull);
428: #endif
429: errs = 0;
430: #ifndef TIOCSTI
431: ttyset = 0;
432: #endif
433: if (gtty(fileno(stdin), &ttybuf) < 0) {
434: perror("gtty");
435: return(-1);
436: }
437: c_erase = ttybuf.sg_erase;
438: c_kill = ttybuf.sg_kill;
439: #ifndef TIOCSTI
440: ttybuf.sg_erase = 0;
441: ttybuf.sg_kill = 0;
442: for (s = SIGINT; s <= SIGQUIT; s++)
443: if ((savesigs[s-SIGINT] = sigset(s, SIG_IGN)) == (void (*)())SIG_DFL) /* adb */
444: sigset(s, SIG_DFL);
445: #endif
446: if (gflags & GSUBJECT && subjtop) {
447: #ifndef TIOCSTI
448: if (!ttyset && hp->h_subject != NOSTR)
449: ttyset++, stty(fileno(stdin), &ttybuf);
450: #endif
451: hp->h_subject = readtty("Subject: ", hp->h_subject);
452: if (hp->h_subject != NOSTR)
453: hp->h_seq++;
454: }
455: if (gflags & GTO) {
456: #ifndef TIOCSTI
457: if (!ttyset && hp->h_to != NOSTR)
458: ttyset++, stty(fileno(stdin), &ttybuf);
459: #endif
460: hp->h_to = addto(NOSTR, readtty("To: ", hp->h_to));
461: if (hp->h_to != NOSTR)
462: hp->h_seq++;
463: }
464: if (gflags & GCC) {
465: #ifndef TIOCSTI
466: if (!ttyset && hp->h_cc != NOSTR)
467: ttyset++, stty(fileno(stdin), &ttybuf);
468: #endif
469: hp->h_cc = addto(NOSTR, readtty("Cc: ", hp->h_cc));
470: if (hp->h_cc != NOSTR)
471: hp->h_seq++;
472: }
473: if (gflags & GBCC) {
474: #ifndef TIOCSTI
475: if (!ttyset && hp->h_bcc != NOSTR)
476: ttyset++, stty(fileno(stdin), &ttybuf);
477: #endif
478: hp->h_bcc = addto(NOSTR, readtty("Bcc: ", hp->h_bcc));
479: if (hp->h_bcc != NOSTR)
480: hp->h_seq++;
481: }
482: if (gflags & GSUBJECT && !subjtop) {
483: #ifndef TIOCSTI
484: if (!ttyset && hp->h_subject != NOSTR)
485: ttyset++, stty(fileno(stdin), &ttybuf);
486: #endif
487: hp->h_subject = readtty("Subject: ", hp->h_subject);
488: if (hp->h_subject != NOSTR)
489: hp->h_seq++;
490: }
491: #ifdef SIGCONT
492: sigset(SIGCONT, savecont);
493: #endif
494: #ifndef TIOCSTI
495: ttybuf.sg_erase = c_erase;
496: ttybuf.sg_kill = c_kill;
497: if (ttyset)
498: stty(fileno(stdin), &ttybuf);
499: for (s = SIGINT; s <= SIGQUIT; s++)
500: sigset(s, savesigs[s-SIGINT]);
501: #endif
502: return(errs);
503: }
504:
505: /*
506: * Read up a header from standard input.
507: * The source string has the preliminary contents to
508: * be read.
509: *
510: */
511:
512: static char *
513: readtty(pr, src)
514: char pr[], src[];
515: {
516: char canonb[LINESIZE];
517: int c, ch; /* adb */
518: void signull(); /* adb */
519: register char *cp, *cp2;
520:
521: fputs(pr, stdout);
522: fflush(stdout);
523: if (src != NOSTR && strlen(src) > LINESIZE - 2) {
524: printf("too long to edit\n");
525: return(src);
526: }
527: #ifndef TIOCSTI
528: if (src != NOSTR)
529: cp = copy(src, canonb);
530: else
531: cp = copy("", canonb);
532: fputs(canonb, stdout);
533: fflush(stdout);
534: #else
535: cp = src == NOSTR ? "" : src;
536: while (c = *cp++) {
537: if (c == c_erase || c == c_kill) {
538: ch = '\\';
539: ioctl(0, TIOCSTI, &ch);
540: }
541: ioctl(0, TIOCSTI, &c);
542: }
543: cp = canonb;
544: *cp = 0;
545: #endif
546: cp2 = cp;
547: while (cp2 < canonb + LINESIZE)
548: *cp2++ = 0;
549: cp2 = cp;
550: if (setjmp(rewrite))
551: goto redo;
552: #ifdef SIGCONT
553: sigset(SIGCONT, ttycont);
554: #endif
555: while (cp2 < canonb + LINESIZE) {
556: c = getc(stdin);
557: if (c == EOF || c == '\n')
558: break;
559: *cp2++ = c;
560: }
561: *cp2 = 0;
562: #ifdef SIGCONT
563: sigset(SIGCONT, signull);
564: #endif
565: if (c == EOF && ferror(stdin) && hadcont) {
566: redo:
567: hadcont = 0;
568: cp = strlen(canonb) > 0 ? canonb : NOSTR;
569: clearerr(stdin);
570: return(readtty(pr, cp));
571: }
572: #ifndef TIOCSTI
573: if (cp == NOSTR || *cp == '\0')
574: return(src);
575: cp2 = cp;
576: if (!ttyset)
577: return(strlen(canonb) > 0 ? savestr(canonb) : NOSTR);
578: while (*cp != '\0') {
579: c = *cp++;
580: if (c == c_erase) {
581: if (cp2 == canonb)
582: continue;
583: if (cp2[-1] == '\\') {
584: cp2[-1] = c;
585: continue;
586: }
587: cp2--;
588: continue;
589: }
590: if (c == c_kill) {
591: if (cp2 == canonb)
592: continue;
593: if (cp2[-1] == '\\') {
594: cp2[-1] = c;
595: continue;
596: }
597: cp2 = canonb;
598: continue;
599: }
600: *cp2++ = c;
601: }
602: *cp2 = '\0';
603: #endif
604: if (equal("", canonb))
605: return(NOSTR);
606: return(savestr(canonb));
607: }
608:
609: #ifdef SIGCONT
610: /*
611: * Receipt continuation.
612: */
613: void
614: ttycont(s)
615: {
616:
617: hadcont++;
618: sigrelse(SIGCONT);
619: longjmp(rewrite, 1);
620: }
621: #endif
622:
623: /* following two functions added for V9 by adb */
624: getbaud()
625: {
626: struct ttydevb tbuf;
627: int baud;
628:
629: outtty = isatty(1);
630: if (ioctl(1, TIOCGDEV, &tbuf)==0)
631: baud = tbuf.ospeed;
632: else
633: baud = B9600;
634: if( baud < B1200 ) return(5);
635: else if( baud == B1200) return(10);
636: else return(20);
637: }
638:
639: #ifdef TIOCGETP
640: gtty(i,buf)
641: int i;
642: struct sgttyb *buf;
643: {
644: return(ioctl(i,TIOCGETP,buf));
645: }
646: stty(i,buf)
647: int i;
648: struct sgttyb *buf;
649: {
650: return(ioctl(i,TIOCSETP,buf));
651: }
652: #endif /* TIOCGETP */
653:
654:
655: /*
656: * Null routine to allow us to hold SIGCONT
657: */
658: void
659: signull(s)
660: {}
661: #endif /* USG_TTY */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.