|
|
1.1 root 1: /*
2: * visual - visual news interface.
3: * Kenneth Almquist
4: */
5:
6: #ifdef SCCSID
7: static char *SccsId = "@(#)visual.c 1.38 10/15/87";
8: #endif /* SCCSID */
9:
10: #include "rparams.h"
11: #ifdef USG
12: #include <sys/ioctl.h>
13: #include <termio.h>
14: #include <fcntl.h>
15: #else /* !USG */
16: #include <sgtty.h>
17: #endif /* !USG */
18:
19: #include <errno.h>
20: #ifdef BSD4_2
21: #ifndef sigmask
22: #define sigmask(m) (1<<((m)-1))
23: #endif /* !sigmask */
24: #endif /* BSD4_2 */
25:
26: #ifdef MYDB
27: #include "db.h"
28: #endif /* MYDB */
29:
30: extern int errno;
31:
32: #ifdef SIGTSTP
33: #include <setjmp.h>
34: #endif /* SIGTSTP */
35:
36: #define ARTWLEN (ROWS-2)/* number of lines used to display article */
37: #define even(cols) ((cols&1) ? cols + 1 : cols)
38: #ifdef STATTOP
39: #define PRLINE 0 /* prompter line */
40: #define SPLINE 1 /* secondary prompt line */
41: #define ARTWIN 2 /* first line of article window */
42: #define SECPRLEN 81 /* length of secondary prompter */
43: #else
44: #define PRLINE (ROWS-1)/* prompter line */
45: #define SPLINE (ROWS-2)/* secondary prompt line */
46: #define ARTWIN 0 /* first line of article window */
47: #define SECPRLEN 100 /* length of secondary prompter */
48: #endif
49:
50: #define PIPECHAR '|' /* indicate save command should pipe to program */
51: #define CAGAIN ('e'&0x1F) /* Save-to-same-place indicator */
52: #define META 0200 /* meta character bit (as in emacs) */
53: /* print (display) flags */
54: #define HDRONLY 0001 /* print header only */
55: #define NOPRT 0002 /* don't print at all */
56: #define NEWART 0004 /* force article display to be regenerated */
57: #define HELPMSG 0010 /* display currently contains help message */
58: /* prun flags */
59: #define CWAIT 0001 /* type "continue?" and wait for return */
60: #define BKGRND 0002 /* run process in the background */
61: /* values of curflag */
62: #define CURP1 1 /* cursor after prompt */
63: #define CURP2 2 /* cursor after secondary prompt */
64: #define CURHOME 3 /* cursor at home position */
65: /* flags for vsave routine */
66: #define SVHEAD 01 /* write out article header */
67: #define OVWRITE 02 /* overwrite the file if it already exists */
68: /* other files */
69:
70: #define saveart oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize
71: #define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines))
72:
73: /* terminal handler stuff */
74: extern int _junked;
75: #define okclear() (_junked = 1)
76: extern int COLS;
77: extern int ROWS;
78: extern int hasscroll;
79:
80: FILE *tmpfile();
81: char *getmailname();
82: #ifdef MYDB
83: char *findparent();
84: #endif /* MYDB */
85: int onint();
86: int onstop();
87: int xxit();
88:
89: char *Progname = "vnews"; /* for xerror */
90:
91: /* variables shared between vnews routines */
92: static char linebuf[LBUFLEN]; /* temporary workspace */
93: static FILE *tfp; /* temporary file */
94: static char tfname[] = "/tmp/vnXXXXXX"; /* name of temp file */
95: static long artbody; /* offset of body into article */
96: static int quitflg; /* if set, then quit */
97: static int erased; /* current article has been erased */
98: static int artlines; /* # lines in article body */
99: static int artread; /* entire article has been read */
100: static int hdrstart; /* beginning of header */
101: static int hdrend; /* end of header */
102: static int lastlin; /* number of lines in tempfile */
103: static int tflinno = 0; /* next line in tempfile */
104: static int maxlinno; /* number of lines in file + folded */
105: static char secpr[SECPRLEN]; /* secondary prompt */
106: static char prompt[30]; /* prompter */
107: static short prflags; /* print flags (controls updscr) */
108: static short curflag; /* where to locate cursor */
109: static int dlinno; /* top line on screen */
110: static char timestr[20]; /* current time */
111: static int ismail; /* true if user has mail */
112: static char *mailf; /* user's mail file */
113: static int alflag; /* set if unprocessed alarm signal */
114: static int atend; /* set if at end of article */
115: static char cerase; /* erase character */
116: static char ckill; /* kill character */
117: static char cintr; /* interrupt character */
118: #ifdef TIOCGLTC
119: static char cwerase; /* word erase character */
120: #endif /* TIOCGLTC */
121: short ospeed; /* terminal speed NOT STATIC */
122: static int intflag; /* set if interrupt received */
123:
124: #ifdef SIGTSTP
125: static int reading; /* to keep stupid BSD from restarting reads */
126: jmp_buf intjmp, alrmjmp;
127: #endif /* SIGTSTP */
128:
129: #ifdef MYDB
130: static int hasdb; /* true if article data base exists */
131: #endif /* MYDB */
132:
133: #ifdef DIGPAGE
134: static int endsuba; /* end of sub-article in digest */
135: #endif
136:
137: #ifdef MYDEBUG
138: FILE *debugf; /* file to write debugging info on */
139: #endif
140:
141: char *tft = "/tmp/folXXXXXX";
142:
143: /*
144: * These were made static for u370 with its buggy cc.
145: * I judged it better to have one copy with no ifdefs than
146: * to conditionally compile them as automatic variables
147: * in readr (which they originally were). Performance
148: * considerations might warrant moving some of the simple
149: * things into register variables, but I don't know what
150: * breaks the u370 cc.
151: */
152: #ifndef SERVER
153: static char goodone[BUFLEN]; /* last decent article */
154: #endif /* !SERVER */
155: static char ogroupdir[BUFLEN]; /* last groupdir */
156: static char edcmdbuf[128];
157: static int rfq = 0; /* for last article */
158: static long ongsize; /* Previous ngsize */
159: static long pngsize; /* Printing ngsize */
160: static char *bptr; /* temp pointer. */
161: static char *tfilename; /* temporary file name */
162: static char ofilename1[BUFLEN]; /* previous file name */
163: static struct hbuf hbuf1, hbuf2; /* for minusing */
164: static struct hbuf *h = &hbuf1, /* current header */
165: *hold = &hbuf2, /* previous header */
166: *hptr; /* temporary */
167: static char *ptr1, *ptr2, *ptr3; /* for reply manipulation */
168: static int aabs = FALSE; /* TRUE if we asked absolutely */
169: static char *ed, tf[100];
170: static long oobit; /* last bit, really */
171: static int dgest = 0;
172: static FILE *fp; /* current article to be printed*/
173:
174: readr()
175: {
176:
177: #ifdef MYDEBUG
178: debugf = fopen("DEBUG", "w");
179: setbuf(debugf, (char *)NULL);
180: #endif
181: if (aflag) {
182: if (*datebuf) {
183: if ((atime = cgtdate(datebuf)) == -1)
184: xerror("Cannot parse date string");
185: } else
186: atime = 0;
187: }
188:
189: if (SigTrap)
190: xxit(1);
191: (void) mktemp(tfname);
192: (void) close(creat(tfname,0666));
193: if ((tfp = fopen(tfname, "w+")) == NULL)
194: xerror("Can't create temp file");
195: (void) unlink(tfname);
196: mailf = getmailname();
197: #ifdef MYDB
198: if (opendb() >= 0) {
199: hasdb = 1;
200: fputs("Using article data base\n", stderr); /*DEBUG*/
201: getng();
202: }
203: #endif
204: ttysave();
205: (void) signal(SIGINT, onint);
206: (void) signal(SIGQUIT, xxit);
207: if (SigTrap)
208: xxit(1);
209: ttyraw();
210: timer();
211:
212: /* loop reading articles. */
213: fp = NULL;
214: obit = -1;
215: nextng();
216: quitflg = 0;
217: while (quitflg == 0) {
218: if (getnextart(FALSE))
219: break;
220: #ifndef SERVER
221: (void) strcpy(goodone, filename);
222: #endif /* !SERVER */
223: if (SigTrap)
224: return;
225: vcmd();
226: }
227:
228: if (!news) {
229: ttycooked();
230: ospeed = 0; /* to convince xxit() not to clear screen */
231: fprintf(stderr, "No news.\n");
232: }
233: }
234:
235: /*
236: * Read and execute a command.
237: */
238: vcmd() {
239: register c;
240: char *p;
241: long count;
242: int countset;
243:
244: if (prflags & HDRONLY)
245: appfile(fp, lastlin + 1);
246: else
247: appfile(fp, dlinno + ARTWLEN + 1);
248:
249: #ifdef DIGPAGE
250: endsuba = findend(dlinno);
251: if (artlines > dlinno + ARTWLEN
252: || endsuba > 0 && endsuba < artlines
253: #else
254: if (artlines > dlinno + ARTWLEN
255: #endif
256: || (prflags & HDRONLY) && artlines > hdrend) {
257: atend = 0;
258: if (prflags&HDRONLY || maxlinno == 0)
259: (void) strcpy(prompt, "more? ");
260: else
261: #ifdef DIGPAGE
262: (void) sprintf(prompt, "more(%d%%)? ",
263: ((((endsuba > 0) ?
264: endsuba : (dlinno + ARTWLEN)) -
265: hdrend) * 100) / maxlinno);
266: #else /* !DIGPAGE */
267: (void) sprintf(prompt, "more(%d%%)? ",
268: ((dlinno + ARTWLEN - hdrend) * 100) / maxlinno);
269: #endif /* !DIGPAGE */
270: } else {
271: atend = 1;
272: (void) strcpy(prompt, "next? ");
273: if (!erased)
274: clear(bit); /* article read */
275: }
276: curflag = CURP1;
277: p = prompt + strlen(prompt);
278: countset = 0;
279: count = 0;
280: /*
281: * Loop while accumulating a count, until an action character
282: * is entered. Also handle "meta" here.
283: *
284: * Count is the current count. Countset=0 means no count
285: * currently exists. Countset=1, count=0 is valid and means
286: * a count of 0 has been entered
287: */
288: for (;;) {
289: c = vgetc();
290: if (c == cerase || c == '\b' || c == '\177') {
291: if (countset == 0)
292: break; /* Use as action char */
293: if (count < 10)
294: countset = 0; /* Erase only char of count */
295: else
296: count /= 10L; /* Erase 1 char of count */
297: } else {
298: #ifdef TIOCGLTC
299: if (c == ckill || c == cwerase) {
300: #else
301: if (c == ckill) {
302: #endif
303: if (countset == 0)
304: break;
305: countset = 0;
306: } else if (c < '0' || c > '9')
307: break;
308: else {
309: countset = 1;
310: count = (count * 10) + (c - '0');
311: }
312: }
313: if (countset) {
314: (void) sprintf(p, "%ld", count);
315: } else {
316: *p = '\0';
317: count = 0;
318: }
319: }
320:
321: if (c == '\033') { /* escape */
322: (void) strcat(prompt, "M-");
323: c = vgetc();
324: if (c != cintr)
325: c |= META;
326: }
327: secpr[0] = '\0';
328: if (countset == 0)
329: count = 1;
330: docmd(c, count, countset);
331: if (c != '?' && c != 'H') /* UGGH */
332: prflags &=~ HELPMSG;
333: if (dlinno > hdrstart)
334: prflags &=~ HDRONLY;
335: }
336:
337:
338: /*
339: * Process one command, which has already been typed in.
340: */
341: docmd(c, count, countset)
342: int c;
343: long count;
344: int countset;
345: {
346: int i;
347: long nart, Hoffset;
348: char *findhist();
349:
350: switch (c) {
351:
352: /* display list of articles in current group */
353: case 'l':
354: case 'L':
355: botscreen();
356: ttycooked();
357: list_group(groupdir, countset ? (int) count : 0,
358: (c == 'l') ? FALSE : TRUE, pngsize);
359: ttyraw();
360: okclear();
361: updscr();
362: break;
363:
364: /* Show more of current article, or advance to next article */
365: case '\n':
366: case ' ':
367: #ifdef DIGPAGE
368: case 'm':
369: #endif /* DIGPAGE */
370: case '\06': /* Control-F for vi compat */
371: prflags &=~ NOPRT;
372: if (atend)
373: goto next;
374: else if (prflags & HDRONLY) {
375: prflags &=~ HDRONLY;
376: if (hasscroll)
377: dlinno = hdrstart;}
378: #ifdef DIGPAGE
379: else if (endsuba > 0)
380: dlinno = endsuba;
381: else if (c == 'm') {
382: do {
383: if (lastlin >= maxlinno)
384: goto next;
385: else
386: appfile(fp, lastlin + 1);
387: } while(STRNCMP(linebuf, "------------------------", 24)
388: != 0);
389: dlinno = endsuba = lastlin;
390: }
391: #endif
392: else if ((appfile(fp, dlinno + 2 * ARTWLEN), artread)
393: && hasscroll && artlines - dlinno <= ARTWLEN + 2)
394: dlinno = artlines - ARTWLEN;
395: else
396: dlinno += ARTWLEN * count;
397: break;
398:
399: /* No. Go on to next article. */
400: case '.': /* useful if you have a keypad */
401: next: case 'n':
402: readmode = NEXT;
403: FCLOSE(fp);
404: clear(bit);
405: saveart;
406: nextbit();
407: break;
408:
409:
410: /* Back up count pages */
411: case '\b':
412: case '\177':
413: if (dlinno == 0)
414: goto backupone;
415: /* NO BREAK */
416: case META|'v':
417: case '\002': /* Control-B */
418: dlinno -= ARTWLEN * count;
419: if (dlinno < 0)
420: dlinno = 0;
421: break;
422:
423: /* forward half a page */
424: case '\004': /* Control-D, as in vi */
425: if (!atend)
426: dlinno += ARTWLEN/2 * count;
427: break;
428:
429: /* backward half a page */
430: case '\025': /* Control-U */
431: dlinno -= ARTWLEN/2 * count;
432: if (dlinno < 0)
433: dlinno = 0;
434: break;
435:
436: /* forward count lines */
437: case '\016': /* Control-N */
438: case '\005': /* Control-E */
439: dlinno += count;
440: break;
441:
442: /* backwards count lines */
443: case '\020': /* Control-P */
444: case '\031': /* Control-Y */
445: dlinno -= count;
446: if (dlinno < 0)
447: dlinno = 0;
448: break;
449:
450: /* Turn displaying of article back on */
451: case 'd':
452: prflags &=~ NOPRT;
453: break;
454:
455: /* display header */
456: case 'h':
457: dlinno = hdrstart;
458: prflags |= HDRONLY;
459: prflags &=~ NOPRT;
460: break;
461:
462: /*
463: * Unsubscribe to the newsgroup and go on to next group
464: */
465:
466: case 'U':
467: case 'u':
468: strcat(prompt, "u");
469: c = vgetc();
470: if (c == 'g') {
471: obit = -1;
472: FCLOSE(fp);
473: zapng = TRUE;
474: saveart;
475: if (nextng()) {
476: if (actdirect == BACKWARD)
477: msg("Can't back up.");
478: else
479: quitflg = 1; /* probably unnecessary */
480: }
481: } else {
482: if (c != cintr && c != ckill)
483: beep();
484: msg("Illegal command");
485: }
486: break;
487:
488: /* Print the current version of news */
489: case 'v':
490: msg("News version: %s", news_version);
491: break;
492:
493:
494: /* Decrypt joke. Always does rot 13 */
495: case 'D':
496: appfile(fp, 32767);
497: for (i = hdrend ; i < artlines ; i++) {
498: register char ch, *p;
499: tfget(linebuf, i);
500: for (p = linebuf ; (ch = *p) != '\0' ; p++) {
501: if (ch >= 'a' && ch <= 'z')
502: *p = (ch - 'a' + 13) % 26 + 'a';
503: else if (ch >= 'A' && ch <= 'Z')
504: *p = (ch - 'A' + 13) % 26 + 'A';
505: }
506: tfput(linebuf, i);
507: }
508: prflags |= NEWART;
509: prflags &=~ (HDRONLY|NOPRT);
510: break;
511:
512: /* write out the article someplace */
513: /* w writes out without the header */
514: /* | defaults to pipeing */
515: {
516: static char savebuf[BUFLEN];
517: int wflags;
518:
519: case PIPECHAR:
520: case 's':
521: case 'w':
522: /* We loop back to here each time user types ^U to prompt */
523: do {
524: /* Prompt based on command char */
525: msg( (c==PIPECHAR)? "|": "file: ");
526: curflag = CURP2;
527: while ((wflags = vgetc()) == ' ');
528: if (wflags == cintr) {
529: secpr[0] = '\0';
530: break;
531: }
532: if (wflags != CAGAIN) {
533: if ((wflags & 0x1F) == wflags) { /* control char */
534: pushback(wflags);
535: savebuf[0] = 0;
536: } else {
537: if (c == PIPECHAR) {
538: savebuf[0] = PIPECHAR;
539: savebuf[1] = wflags;
540: savebuf[2] = 0;
541: } else {
542: savebuf[0] = wflags;
543: savebuf[1] = 0;
544: }
545: }
546: } else {
547: /* don't let them pipe to a saved filename */
548: if (c == PIPECHAR && savebuf[0] != PIPECHAR) {
549: savebuf[0] = PIPECHAR;
550: savebuf[1] = 0;
551: }
552: }
553:
554: wflags = prget( (savebuf[0] == PIPECHAR) ? "" : "file: ",
555: savebuf);
556: } while (wflags == 2);
557: if (wflags) break; /* Interrupted out */
558: wflags = 0;
559: if (c == PIPECHAR) c = 's';
560: if (c == 's')
561: wflags |= SVHEAD;
562: if (count != 1)
563: wflags |= OVWRITE;
564: bptr = savebuf;
565: while( *bptr == ' ')
566: bptr++; /* strip leading spaces */
567:
568: if (*bptr != PIPECHAR && *bptr != '/') {
569: char hetyped[BUFLEN];
570: char *boxptr;
571: (void) strcpy(hetyped, bptr);
572: if (hetyped[0] == '~' && hetyped[1] == '/') {
573: strcpy(hetyped, bptr+2);
574: strcpy(bptr, userhome);
575: } else if (boxptr = getenv("NEWSBOX")) {
576: if (index(boxptr, '%')) {
577: struct stat stbf;
578: sprintf(bptr, boxptr, groupdir);
579: if (stat(bptr,&stbf) < 0) {
580: if (mkdir(bptr, 0777) < 0) {
581: msg("Cannot create directory %s", bptr);
582: break;
583: }
584: } else if ((stbf.st_mode&S_IFMT) != S_IFDIR) {
585: msg("%s not a directory", bptr);
586: break;
587: }
588: } else
589: strcpy(bptr, boxptr);
590: } else
591: bptr[0] = '\0';
592:
593: if (bptr[0])
594: (void) strcat(bptr, "/");
595: if (hetyped[0] != '\0')
596: (void) strcat(bptr, hetyped);
597: else
598: (void) strcat(bptr, "Articles");
599: }
600:
601: /* handle ~/ for pipes */
602: if (*bptr == PIPECHAR) {
603: char fullname[BUFLEN];
604: bptr++; /* skip PIPECHAR */
605: while( *bptr == ' ')
606: bptr++; /* strip leading spaces */
607: if (bptr[0] == '~' && bptr[1] == '/') {
608: strcpy(fullname,userhome);
609: strcat(fullname,bptr+2);
610: } else
611: strcpy(fullname,bptr);
612: /* we know PIPECHAR is in *savebuf */
613: strcpy(savebuf+1,fullname);
614: bptr = savebuf;
615: }
616:
617: vsave(bptr, wflags);
618: break;
619: }
620:
621: /* back up */
622: case '-':
623: caseminus:
624: aabs = TRUE;
625: if (!*ofilename1) {
626: msg("Can't back up.");
627: break;
628: }
629: FCLOSE(fp);
630: hptr = h;
631: h = hold;
632: hold = hptr;
633: (void) strcpy(bfr, filename);
634: (void) strcpy(filename, ofilename1);
635: (void) strcpy(ofilename1, bfr);
636: obit = bit;
637: if (STRCMP(groupdir, ogroupdir)) {
638: (void) strcpy(bfr, groupdir);
639: selectng(ogroupdir, FALSE, FALSE);
640: (void) strcpy(groupdir, ogroupdir);
641: (void) strcpy(ogroupdir, bfr);
642: ngrp = 1;
643: back();
644: }
645: bit = oobit;
646: oobit = obit;
647: obit = -1;
648: getnextart(TRUE);
649: break;
650:
651: /* skip forwards */
652: case '+':
653: case '=':
654: caseplus: if (count == 0)
655: break;
656: saveart;
657: last = bit;
658: for (i = 0; i < count; i++) {
659: nextbit();
660: if ((bit > pngsize) || (rflag && bit < 1))
661: break;
662: }
663: FCLOSE(fp);
664: obit = -1;
665: break;
666:
667: /* exit - time updated to that of most recently read article */
668: case 'q':
669: quitflg = 1;
670: break;
671:
672: case 'x':
673: xxit(0);
674: break;
675:
676: /* cancel the article. */
677: case 'c':
678: strcpy(prompt, "cancel [n]? ");
679: if (vgetc() != 'y') {
680: msg("Article not cancelled");
681: break;
682: }
683: cancel_command();
684: break;
685:
686: /* escape to shell */
687: case '!': {
688: register char *p;
689: int flags;
690:
691: p = linebuf;
692: *p = 0;
693: if (prget("!", p))
694: break;
695: flags = CWAIT;
696: if (*p == '\0') {
697: (void) strcpy(linebuf, SHELL);
698: flags = 0;
699: }
700: while (*p) p++;
701: while (p > linebuf && p[-1] == ' ')
702: p--;
703: if (*--p == '&') {
704: *p = '\0';
705: flags = BKGRND;
706: } else if (*p == PIPECHAR) {
707: *p = '\0';
708: (void) sprintf(bfr, "(%s)%cmail '%s'", linebuf, PIPECHAR, username);
709: (void) strcpy(linebuf, bfr);
710: flags |= BKGRND;
711: } else {
712: prflags |= NOPRT;
713: }
714: shcmd(linebuf, flags);
715: break;
716: }
717:
718: /* mail reply */
719: case 'r':
720: reply(FALSE);
721: break;
722:
723: case 'R':
724: reply(TRUE);
725: break;
726:
727: case META|'r':
728: direct_reply();
729: break;
730:
731: /* next newsgroup */
732: case 'N':
733: FCLOSE(fp);
734: if (next_ng_command())
735: quitflg = 1;
736: break;
737:
738: /* mark the rest of the articles in this group as read */
739: case 'K':
740: saveart;
741: while (bit <= ngsize && bit >= minartno) {
742: clear(bit);
743: nextbit();
744: }
745: FCLOSE(fp);
746: break;
747:
748: /* Print the full header */
749: case 'H':
750: if (fp == NULL) {
751: msg("No current article");
752: break;
753: }
754: move(ARTWIN, 0);
755: Hoffset = ftell(fp);
756: (void) fseek(fp, 0L, 0);
757: for (i = 0; i < ARTWLEN; i++) {
758: if (fgets(linebuf, COLS, fp) == NULL)
759: break;
760: if (linebuf[0] == '\n')
761: break;
762: linebuf[COLS] = '\0';
763: addstr(linebuf);
764: }
765: (void) fseek(fp, Hoffset, 0);
766: for(; i < ARTWLEN; i++)
767: addstr(linebuf);
768: prflags |= HELPMSG|NEWART;
769: break;
770: case 'b': /* backup 1 article */
771: backupone:
772: count = bit - 1;
773: /* NO BREAK */
774:
775: case 'A': /* specific number */
776: if (count > pngsize) {
777: msg("not that many articles");
778: break;
779: }
780: readmode = SPEC;
781: aabs = TRUE;
782: bit = count;
783: obit = -1;
784: FCLOSE(fp);
785: break;
786:
787: /* display parent article */
788: case 'p':
789: #ifdef MYDB
790: if (hasdb && (ptr3 = findparent(h->ident, &nart)) != NULL) {
791: msg("parent: %s/%ld", ptr3, nart); /*DEBUG*/
792: updscr(); /*DEBUG*/
793: goto selectart;
794: }
795: #endif
796: if (h->followid[0] == '\0') {
797: msg("no references line");
798: break;
799: }
800: ptr1 = h->followid + strlen(h->followid);
801: do {
802: ptr2 = ptr1;
803: if (*ptr2 == '\0')
804: ptr1 = rindex(h->followid, ' ');
805: else {
806: *ptr2 = '\0';
807: ptr1 = rindex(h->followid, ' ');
808: *ptr2 = ' ';
809: }
810: } while (ptr1 != NULL && --count > 0);
811: if (ptr1 == NULL)
812: ptr1 = h->followid;
813: else ++ptr1;
814: (void) strncpy(linebuf, ptr1, ptr2 - ptr1);
815: linebuf[ptr2 - ptr1] = '\0';
816: msg("%s", linebuf);
817: curflag = CURP2;
818: updscr(); /* may take this out later */
819: goto searchid;
820: /* specific message ID. */
821: case '<':
822: /* could improve this */
823: linebuf[0] = '<'; linebuf[1] = 0;
824: if (prget("", linebuf)) {
825: secpr[0] = 0;
826: break;
827: }
828: searchid: secpr[0] = '\0';
829: if (index(linebuf, '@') == NULL && index(linebuf, '>') == NULL) {
830: ptr1 = linebuf;
831: if (*ptr1 == '<')
832: ptr1++;
833: ptr2 = index(ptr1, '.');
834: if (ptr2 != NULL) {
835: *ptr2++ = '\0';
836: (void) sprintf(bfr, "<%s@%s.UUCP>", ptr2, ptr1);
837: (void) strcpy(linebuf, bfr);
838: }
839: }
840: if (index(linebuf, '>') == NULL)
841: (void) strcat(linebuf, ">");
842:
843: ptr1 = findhist(linebuf);
844: if (ptr1 == NULL) {
845: msg("%s not found", linebuf);
846: break;
847: }
848: ptr2 = index(ptr1, '\t');
849: ptr3 = index(++ptr2, '\t');
850: ptr2 = index(++ptr3, ' ');
851: if (ptr2)
852: *ptr2 = '\0';
853: ptr2 = index(ptr3, '/');
854: if (!ptr2) {
855: if (STRCMP(ptr3, "cancelled") == 0)
856: msg("%s has been cancelled", linebuf);
857: else
858: msg("%s has expired", linebuf);
859: break;
860: }
861: *ptr2++ = '\0';
862: (void) sscanf(ptr2, "%ld", &nart);
863:
864: /*
865: * Go to a given article. Ptr3 specifies the newsgroup
866: * and nart specifies the article number.
867: */
868: #ifdef MYDB
869: selectart:
870: #endif /* MYDB */
871: aabs = TRUE;
872: FCLOSE(fp);
873: saveart;
874: (void) strcpy(ogroupdir, ptr3);
875: if (STRCMP(groupdir, ogroupdir)) {
876: (void) strcpy(bfr, groupdir);
877: selectng(ogroupdir, TRUE, PERHAPS);
878: (void) strcpy(groupdir, ogroupdir);
879: (void) strcpy(ogroupdir, bfr);
880: ngrp = 1;
881: back();
882: }
883: bit = nart;
884: oobit = obit;
885: obit = -1;
886: getnextart(TRUE);
887: if (bit != nart || STRCMP(groupdir, ptr3) != 0) {
888: msg("can't read %s/%ld", ptr3, nart);
889: goto caseminus;
890: }
891: rfq = 0;
892: break;
893:
894: /* follow-up article */
895: case 'f':
896: if (STRCMP(h->followto, "poster") == 0) {
897: reply(FALSE);
898: break;
899: }
900: #ifdef SERVER
901: (void) sprintf(bfr, "%s/%s", BIN, "postnews");
902: #else /* !SERVER */
903: (void) sprintf(bfr, "%s/%s %s", BIN, "postnews", goodone);
904: #endif /* !SERVER */
905: shcmd(bfr, CWAIT);
906: break;
907:
908: /* erase - pretend we haven't seen this article. */
909: case 'e':
910: erased = 1;
911: set(bit);
912: goto caseplus; /* skip this article for now */
913:
914: case '#':
915: msg("Article %ld of %ld", rfq ? oobit : bit, pngsize);
916: break;
917:
918: /* error */
919: case '?':
920: {
921: FILE *helpf;
922: (void) sprintf(linebuf, "%s/vnews.help", LIB);
923: if ((helpf = fopen(linebuf, "r")) == NULL) {
924: msg("Can't open help file");
925: break;
926: }
927: move(ARTWIN, 0);
928: while (fgets(linebuf, LBUFLEN, helpf) != NULL)
929: addstr(linebuf);
930: (void) fclose(helpf);
931: prflags |= HELPMSG|NEWART;
932: }
933: break;
934:
935: default:
936: if (c != ckill && c != cintr && c != cerase)
937: #ifdef TIOCGLTC
938: if (c != cwerase)
939: #endif
940: {
941: beep();
942: msg("Illegal command");
943: }
944: break;
945: }
946: }
947:
948: cancel_command()
949: {
950: register char *poster, *r;
951: int notauthor;
952: char *senderof();
953:
954: poster = senderof(h);
955: /* only compare up to '.' or ' ' */
956: r = index(poster,'.');
957: if (r == NULL)
958: r = index(poster,' ');
959: if (r != NULL)
960: *r = '\0';
961: tfilename = filename;
962: notauthor = STRCMP(username, poster);
963: if (uid != ROOTID && uid && notauthor) {
964: msg("Can't cancel what you didn't write.");
965: return;
966: }
967: if (!cancel(stderr, h, notauthor)) {
968: clear(bit);
969: saveart;
970: nextbit();
971: obit = -1;
972: fp = NULL;
973: }
974: FCLOSE(fp);
975: }
976: /*
977: * Generate replies
978: */
979:
980: reply(include)
981: int include;
982: {
983: char *arg[4];
984: register FILE *rfp;
985: char subj[132];
986: register char *p;
987: char *replyname();
988: struct stat statb;
989: time_t creatm;
990:
991: /* Put the user in the editor to create the body of the reply. */
992: ed = getenv("EDITOR");
993: if (ed == NULL || *ed == '\0')
994: ed = DFTEDITOR;
995: if (ed == NULL) {
996: msg("You don't have an editor");
997: return;
998: }
999:
1000: arg[0] = "/bin/sh";
1001: arg[1] = "-c";
1002:
1003: (void) strcpy(tf, tft);
1004: (void) mktemp(tf);
1005: (void) close(creat(tf,0600));
1006: if ((rfp = fopen(tf, "w")) == NULL) {
1007: msg("Can't create %s", tf) ;
1008: return;
1009: }
1010: (void) strcpy(subj, h->title);
1011: if (!PREFIX(subj, "Re:")){
1012: (void) strcpy(bfr, subj);
1013: (void) sprintf(subj, "Re: %s", bfr);
1014: }
1015:
1016: p = replyname(h);
1017: fprintf(rfp, "To: %s\n", p);
1018: fprintf(rfp, "Subject: %s\n", subj);
1019: fprintf(rfp, "In-reply-to: your article %s\n", h->ident);
1020: #ifdef INTERNET
1021: fprintf(rfp, "News-Path: %s\n", h->path);
1022: #endif /* INTERNET */
1023: (void) sprintf(rcbuf, "%s -t < %s; rm -f %s", MAILPARSER, tf, tf);
1024: putc('\n', rfp);
1025: if (include) {
1026: FILE *of;
1027: char buf[BUFSIZ];
1028:
1029: #ifndef SERVER
1030: of = xart_open(goodone, "r");
1031: while (fgets(buf, sizeof buf, of) != NULL)
1032: if (buf[0] == '\n')
1033: break;
1034: while (fgets(buf, sizeof buf, of) != NULL)
1035: fprintf(rfp, "> %s", buf);
1036: fclose(of);
1037: putc('\n', rfp);
1038: #endif /* !SERVER */
1039: }
1040:
1041: fflush(rfp);
1042: (void) fstat(fileno(rfp), &statb);
1043: creatm = statb.st_mtime;
1044: (void) fclose(rfp);
1045:
1046: (void) sprintf(edcmdbuf, "exec %s %s", ed, tf);
1047: arg[2] = edcmdbuf;
1048: arg[3] = NULL;
1049: if (prun(arg, 0) != 0) {
1050: msg("Couldn't run editor");
1051: (void) unlink(tf);
1052: return;
1053: }
1054:
1055: if (access(tf, 4) || stat(tf, &statb)) {
1056: msg("No input file - mail not sent");
1057: (void) unlink(tf);
1058: return;
1059: }
1060: if (statb.st_mtime == creatm || statb.st_size < 5) {
1061: msg("File unchanged - no message posted");
1062: (void) unlink(tf);
1063: return;
1064: }
1065:
1066: arg[2] = rcbuf;
1067: arg[3] = NULL;
1068: prun(arg, BKGRND);
1069: prflags |= NOPRT;
1070: }
1071:
1072: direct_reply()
1073: {
1074: register char *p;
1075: register char *q;
1076: char *arg[4];
1077: char address[PATHLEN];
1078: extern char *replyname();
1079: extern char *getenv();
1080:
1081: arg[0] = "/bin/sh";
1082: arg[1] = "-c";
1083: p = replyname(h);
1084: q = address;
1085: while (*p != '\0') {
1086: if (index("\"\\$", *p) != 0)
1087: *q++ = '\\';
1088: *q++ = *p++;
1089: }
1090: *q++ = '\0';
1091: if ((MAILER = getenv("MAILER")) == NULL)
1092: MAILER = "mail";
1093: sprintf(rcbuf, MAILER, hptr->title);
1094: sprintf(bfr, "%s %s", rcbuf, address);
1095: arg[2] = bfr;
1096: arg[3] = NULL;
1097: if (prun(arg, 0) != 0) {
1098: msg("Couldn't run mailer");
1099: return;
1100: }
1101: prflags |= NOPRT;
1102: }
1103:
1104: next_ng_command()
1105: {
1106: set(bit);
1107: obit = -1;
1108: linebuf[0] = 0;
1109: if (prget("group? ", linebuf))
1110: return FALSE;
1111: bptr = linebuf;
1112: if (!*bptr || *bptr == '-') {
1113: if (*bptr)
1114: actdirect = BACKWARD;
1115: saveart;
1116: if (nextng()) {
1117: if (actdirect == BACKWARD)
1118: msg("Can't back up.");
1119: else
1120: return TRUE;
1121: }
1122: return FALSE;
1123: }
1124: while (isspace(*bptr))
1125: bptr++;
1126: if (!validng(bptr)) {
1127: msg("No such group.");
1128: return FALSE;
1129: }
1130: saveart;
1131: back();
1132: selectng(bptr, TRUE, TRUE);
1133: return FALSE;
1134: }
1135:
1136: /*
1137: * Find the next article we want to consider, if we're done with
1138: * the last one, and show the header.
1139: */
1140: getnextart(minus)
1141: int minus;
1142: {
1143: int noaccess;
1144: #ifdef SERVER
1145: char workspace[256];
1146: #else /* !SERVER */
1147: register DIR *dirp;
1148: register struct direct *dir;
1149: #endif /* !SERVER */
1150: long nextnum, tnum;
1151: long atol();
1152: noaccess = 0;
1153: if (minus)
1154: goto nextart2; /* Kludge for "-" command. */
1155:
1156: if (bit == obit) /* Return if still on same article as last time */
1157: return 0;
1158:
1159: nextart:
1160: if (news) {
1161: curflag = CURHOME;
1162: _amove(0, 0);
1163: vflush();
1164: }
1165: dgest = 0;
1166:
1167: /* If done with this newsgroup, find the next one. */
1168: while (ngsize <= 0 || (!rflag && ((long) bit > ngsize)) || (rflag && bit < minartno)) {
1169: if (nextng()) {
1170: if (actdirect == BACKWARD) {
1171: msg("Can't back up.");
1172: actdirect = FORWARD;
1173: continue;
1174: }
1175: else /* if (rfq++ || pflag || cflag) */
1176: return 1;
1177: }
1178: if (rflag)
1179: bit = ngsize + 1;
1180: else
1181: bit = -1;
1182: noaccess = 2;
1183: }
1184:
1185: /* speed things up by not searching for article -1 */
1186: if (bit < 0) {
1187: bit = minartno - 1;
1188: nextbit();
1189: aabs = FALSE;
1190: goto nextart;
1191: }
1192:
1193: nextart2:
1194: if (rcreadok)
1195: rcreadok = 2; /* have seen >= 1 article */
1196: #ifdef SERVER
1197: if ((fp = getarticle(groupdir, bit, "ARTICLE")) == NULL)
1198: goto badart;
1199: strcpy(filename, article_name());
1200: (void) fclose(fp);
1201: fp = NULL;
1202: #else /* !SERVER */
1203: (void) sprintf(filename, "%s/%ld", dirname(groupdir), bit);
1204: if (rfq && goodone[0]) /* ??? */
1205: strcpy(filename, goodone);
1206: #endif /* !SERVER */
1207: if (SigTrap == SIGHUP)
1208: return 1;
1209: /* Decide if we want to show this article. */
1210: if ((fp = art_open(filename, "r")) == NULL) {
1211: /* since there can be holes in legal article numbers, */
1212: /* we wait till we hit 5 consecutive bad articles */
1213: /* before we haul off and scan the directory */
1214: if (++noaccess < 5)
1215: goto badart;
1216: noaccess = 0;
1217: #ifdef SERVER
1218: if (*groupdir == ' ' || *groupdir == '\0' ||
1219: set_group(groupdir) == NULL)
1220: goto nextart;
1221: #else /* !SERVER */
1222: dirp = opendir(dirname(groupdir));
1223: if (dirp == NULL) {
1224: if (errno != EACCES)
1225: msg("Can't open %s", dirname(groupdir));
1226: goto nextart;
1227: }
1228: #endif /* !SERVER */
1229: nextnum = rflag ? minartno - 1 : ngsize + 1;
1230: #ifdef SERVER
1231: tnum = nextnum;
1232: for(;;){
1233: (void) sprintf(bfr,"STAT %ld",tnum);
1234: put_server(bfr);
1235: (void) get_server(workspace,sizeof(workspace));
1236: if (*workspace != CHAR_OK) {
1237: if (rflag)
1238: tnum++;
1239: else
1240: tnum--;
1241: continue;
1242: }
1243: #else /* !SERVER */
1244: while ((dir = readdir(dirp)) != NULL) {
1245: if (!dir->d_ino)
1246: continue;
1247: tnum = atol(dir->d_name);
1248: if (tnum <= 0)
1249: continue;
1250: #endif /* !SERVER */
1251: if (rflag ? (tnum > nextnum && tnum < bit)
1252: : (tnum < nextnum && tnum > bit))
1253: nextnum = tnum;
1254: #ifdef SERVER
1255: break; /* not exactly right */
1256: #endif /* SERVER */
1257: }
1258: #ifndef SERVER
1259: closedir(dirp);
1260: #endif /* !SERVER */
1261: if (rflag ? (nextnum >= bit) : (nextnum <= bit))
1262: goto badart;
1263: do {
1264: clear(bit);
1265: nextbit();
1266: } while (rflag ? (nextnum < bit) : (nextnum > bit));
1267: obit = -1;
1268: aabs = FALSE;
1269: goto nextart;
1270: } else
1271: noaccess = 0;
1272:
1273: if (hread(h, fp, TRUE) == NULL || (!rfq && !aselect(h, aabs))) {
1274: badart:
1275: FCLOSE(fp);
1276: clear(bit);
1277: obit = -1;
1278: nextbit();
1279: aabs = FALSE;
1280: goto nextart;
1281: }
1282: aabs = FALSE;
1283: actdirect = FORWARD;
1284: news = TRUE;
1285: artbody = ftell(fp);
1286: fmthdr();
1287: artlines = lastlin;
1288: artread = 0;
1289: prflags |= NEWART;
1290: prflags &=~ NOPRT;
1291: if (! cflag && hdrend < ARTWLEN && !cflag)
1292: prflags |= HDRONLY;
1293: dlinno = 0;
1294: maxlinno = NLINES(h, fp);
1295: erased = 0;
1296:
1297: obit = bit;
1298: #ifdef SERVER
1299: (void) unlink(filename);
1300: #endif /* SERVER */
1301: return 0;
1302: }
1303:
1304: /*
1305: * Print out whatever the appropriate header is
1306: */
1307: fmthdr() {
1308: char *briefdate();
1309: static FILE *ngfd = NULL;
1310: static int triedopen = 0;
1311: char pbuf[BUFLEN], *printbuffer = groupdir;
1312:
1313: lastlin = 0;
1314: if (ngrp) {
1315: pngsize = ngsize;
1316: ngrp--;
1317: if (!hflag) {
1318: if (!triedopen) {
1319: (void) sprintf(pbuf,"%s/newsgroups", LIB);
1320: ngfd = fopen(pbuf, "r");
1321: triedopen++;
1322: }
1323: if (ngfd != NULL) {
1324: register char *p;
1325: char ibuf[BUFLEN];
1326: rewind(ngfd);
1327: while (fgets(ibuf, BUFLEN, ngfd) != NULL) {
1328: p = index(ibuf, '\t');
1329: if (p)
1330: *p++ = '\0';
1331: if (STRCMP(ibuf, groupdir) == 0) {
1332: register char *q;
1333: q = rindex(p, '\t');
1334: if (q) {
1335: p = q;
1336: *p++ = '\0';
1337: }
1338: if (p) {
1339: q = index(p, '\n');
1340: if (q)
1341: *q = '\0';
1342: if (*--q == '.')
1343: *q = '\0';
1344: (void) sprintf(pbuf,"%s (%s)",
1345: groupdir, p);
1346: printbuffer = pbuf;
1347: }
1348: break;
1349: }
1350: }
1351: }
1352: (void) sprintf(linebuf, "Newsgroup %s", printbuffer);
1353: tfappend(linebuf);
1354: }
1355: }
1356: hdrstart = lastlin;
1357: if (!hflag) {
1358: (void) sprintf(linebuf, "Article %s %s",
1359: h->ident, briefdate(h->subdate));
1360: tfappend(linebuf);
1361: }
1362: xtabs(h);
1363: vhprint(h, pflag ? 1 : 0);
1364: (void) sprintf(linebuf, "(%d lines)", NLINES(h, fp)); tfappend(linebuf);
1365: tfappend("");
1366: hdrend = lastlin;
1367: }
1368:
1369: /*
1370: * Grow tabs into spaces in header fields, 'cause the rest of this
1371: * lax program drops turds all over tabs (so it does with \b's, but ..)
1372: */
1373: xtabs(p)
1374: register struct hbuf *p;
1375: {
1376: xtabf(p->from, sizeof p->from);
1377: xtabf(p->path, sizeof p->path);
1378: xtabf(p->nbuf, sizeof p->nbuf);
1379: xtabf(p->title, sizeof p->title);
1380: xtabf(p->ident, sizeof p->ident);
1381: xtabf(p->replyto, sizeof p->replyto);
1382: xtabf(p->followid, sizeof p->followid);
1383: xtabf(p->subdate, sizeof p->subdate);
1384: xtabf(p->expdate, sizeof p->expdate);
1385: xtabf(p->ctlmsg, sizeof p->ctlmsg);
1386: xtabf(p->sender, sizeof p->sender);
1387: xtabf(p->followto, sizeof p->followto);
1388: xtabf(p->distribution, sizeof p->distribution);
1389: xtabf(p->organization, sizeof p->organization);
1390: xtabf(p->numlines, sizeof p->numlines);
1391: xtabf(p->keywords, sizeof p->keywords);
1392: xtabf(p->summary, sizeof p->summary);
1393: xtabf(p->approved, sizeof p->approved);
1394: xtabf(p->nf_id, sizeof p->nf_id);
1395: xtabf(p->nf_from, sizeof p->nf_from);
1396: #ifdef DOXREFS
1397: xtabf(p->xref, sizeof p->xref);
1398: #endif /* DOXREFS */
1399: }
1400:
1401: xtabf(s, size)
1402: char *s;
1403: int size;
1404: {
1405: register char *p, *str;
1406: register c, i;
1407: char buf[LBUFLEN];
1408:
1409: str = s;
1410: if (index(str, '\t') == NULL)
1411: return;
1412: i = 0;
1413: for (p = buf; c = *str++; i++) {
1414: if (c == '\t') {
1415: *p++ = ' ';
1416: if ((i & 7) != 7)
1417: str--;
1418: } else if (c == '\n') {
1419: i = -1;
1420: *p++ = c;
1421: } else
1422: *p++ = c;
1423: }
1424: *p = '\0';
1425: strncpy(s, buf, size - 1);
1426: }
1427:
1428: /*
1429: * Print the file header to the temp file.
1430: */
1431: vhprint(hp, verbose)
1432: register struct hbuf *hp;
1433: int verbose;
1434: {
1435: register char *p1, *p2;
1436: char fname[BUFLEN];
1437: char *tailpath();
1438:
1439: fname[0] = '\0'; /* init name holder */
1440:
1441: p1 = index(hp->from, '('); /* Find the sender's full name. */
1442: if (p1 == NULL && hp->path[0])
1443: p1 = index(hp->path, '(');
1444: if (p1 != NULL) {
1445: (void) strcpy(fname, p1+1);
1446: p2 = index(fname, ')');
1447: if (p2 != NULL)
1448: *p2 = '\0';
1449: }
1450:
1451: (void) sprintf(linebuf, "Subject: %s", hp->title);
1452: tfappend(linebuf);
1453: if (!hflag && hp->summary[0])
1454: (void) sprintf(linebuf, "Summary: %s", hp->summary), tfappend(linebuf);
1455: if (!hflag && hp->keywords[0])
1456: (void) sprintf(linebuf, "Keywords: %s", hp->keywords), tfappend(linebuf);
1457: if (verbose) {
1458: (void) sprintf(linebuf, "From: %s", hp->from); tfappend(linebuf);
1459: (void) sprintf(linebuf, "Path: %s", hp->path); tfappend(linebuf);
1460: if (hp->organization[0]) {
1461: (void) sprintf(linebuf, "Organization: %s", hp->organization);
1462: tfappend(linebuf);
1463: }
1464: }
1465: else {
1466: if (p1 != NULL)
1467: *--p1 = '\0'; /* bump over the '(' */
1468: #ifdef INTERNET
1469: /*
1470: * Prefer Path line if it's in internet format, or if we don't
1471: * understand internet format here, or if there is no reply-to.
1472: */
1473: (void) sprintf(linebuf, "From: %s", hp->from);
1474: #else
1475: (void) sprintf(linebuf, "Path: %s", tailpath(hp));
1476: #endif
1477: if (fname[0] || (hp->organization[0] && !hflag)) {
1478: (void) strcat(linebuf, " (");
1479: if (fname[0] == '\0') {
1480: (void) strcpy(fname, hp->from);
1481: p2 = index(fname,'@');
1482: if (p2)
1483: *p2 = '\0';
1484: }
1485: (void) strcat(linebuf, fname);
1486: if (hp->organization[0] && !hflag) {
1487: (void) strcat(linebuf, " @ ");
1488: (void) strcat(linebuf, hp->organization);
1489: }
1490: (void) strcat(linebuf, ")");
1491: }
1492: tfappend(linebuf);
1493: if (p1 != NULL)
1494: *p1 = ' ';
1495: if (hp->ctlmsg[0]) {
1496: (void) sprintf(linebuf, "Control: %s", hp->ctlmsg);
1497: tfappend(linebuf);
1498: }
1499: }
1500:
1501: if (verbose) {
1502: (void) sprintf(linebuf, "Newsgroups: %s", hp->nbuf); tfappend(linebuf);
1503: (void) sprintf(linebuf, "Date: %s", hp->subdate); tfappend(linebuf);
1504: if (hp->sender[0]) {
1505: (void) sprintf(linebuf, "Sender: %s", hp->sender);
1506: tfappend(linebuf);
1507: }
1508: if (hp->replyto[0]) {
1509: (void) sprintf(linebuf, "Reply-To: %s", hp->replyto);
1510: tfappend(linebuf);
1511: }
1512: if (hp->followto[0]) {
1513: (void) sprintf(linebuf, "Followup-To: %s", hp->followto);
1514: tfappend(linebuf);
1515: }
1516: }
1517: else if (STRCMP(hp->nbuf, groupdir) != 0) {
1518: (void) sprintf(linebuf, "Newsgroups: %s", hp->nbuf);
1519: tfappend(linebuf);
1520: timer();
1521: }
1522: }
1523:
1524: #ifdef MYDB
1525:
1526: char *
1527: findparent(id, num)
1528: char *id;
1529: long *num;
1530: {
1531: struct artrec a;
1532: char idbuf[BUFSIZE];
1533: char *ngname();
1534:
1535: strcpy(idbuf, id);
1536: lcase(idbuf);
1537:
1538: if (lookart(id, &a) == DNULL)
1539: return NULL;
1540: if (a.parent == DNULL)
1541: return NULL;
1542: readrec(a.parent, &a);
1543: *num = a.groups[0].artno;
1544: return ngname(a.groups[0].newsgroup);
1545: }
1546:
1547: #endif
1548:
1549:
1550: /*
1551: * Append file to temp file, handling control characters, folding lines, etc.
1552: * We don't grow the temp file to more than nlines so that a user won't have
1553: * to wait for 20 seconds to read in a monster file from net.sources.
1554: * What we really want is coroutines--any year now.
1555: */
1556:
1557: #define ULINE 0200
1558: static char *maxcol;
1559:
1560: appfile(iop, nlines)
1561: register FILE *iop;
1562: {
1563: register int c;
1564: register char *icol; /* &linebuf[0] <= icol <= maxcol */
1565:
1566: if (artread || artlines >= nlines || iop == NULL)
1567: return;
1568: maxcol = linebuf;
1569: icol = linebuf;
1570: while ((c = getc(iop)) != EOF) {
1571: switch (c) {
1572: case ' ':
1573: if (icol == maxcol && icol < linebuf + LBUFLEN - 1) {
1574: *icol++ = ' ';
1575: maxcol = icol;
1576: } else {
1577: if (*icol == '_')
1578: *icol++ = ULINE | ' ';
1579: else
1580: icol++;
1581: }
1582: break;
1583: case '\t':
1584: icol = (icol - linebuf &~ 07) + 8 + linebuf;
1585: growline(icol);
1586: break;
1587: case '\b':
1588: if (icol > linebuf) --icol;
1589: break;
1590: case '\n':
1591: outline();
1592: if (artlines >= nlines)
1593: return;
1594: icol = linebuf;
1595: break;
1596: case '\r':
1597: icol = linebuf;
1598: break;
1599: case '\f':
1600: outline(); outline(); outline();
1601: if (artlines >= nlines)
1602: return;
1603: icol = linebuf;
1604: break;
1605: default:
1606: if (c < ' ' || c > '~')
1607: break;
1608: else if (icol >= linebuf + LBUFLEN - 1)
1609: icol++;
1610: else if (icol == maxcol) {
1611: *icol++ = c;
1612: maxcol = icol; }
1613: else if (c == '_')
1614: *icol++ |= ULINE;
1615: else if (*icol == '_')
1616: *icol++ = (c | ULINE);
1617: else *icol++ = c;
1618: break;
1619: }
1620: }
1621: if (maxcol != linebuf) /* file not terminated with newline */
1622: outline();
1623: artread++;
1624: }
1625:
1626: growline(col)
1627: char *col;
1628: {
1629: while (maxcol < col && maxcol < linebuf + LBUFLEN - 1)
1630: *maxcol++ = ' ';
1631: }
1632:
1633: outline()
1634: {
1635: *maxcol = '\0';
1636: if (STRNCMP(linebuf, ">From ", 6) == 0) {
1637: register char *p;
1638: for (p = linebuf ; (*p = p[1]) != '\0' ; p++);
1639: }
1640: tfappend(linebuf);
1641: if (maxcol > linebuf)
1642: artlines = lastlin;
1643: maxcol = linebuf;
1644: }
1645:
1646:
1647: /*
1648: * Prompt the user and get a line.
1649: * "prompter" is the prompt. "buf" contains a string which
1650: * will be used as the initial user response (which may be edited
1651: * by the user with backspace, ^U, etc). The resulting line is
1652: * returned in "buf". The result of prget() is:
1653: * 0 if the line was terminated by NL or CR
1654: * 1 if it was terminated by the interrupt character.
1655: * 2 if it was terminated by erasing all the characters, including
1656: * one or more that were prompted initially in "buf". (If "buf"
1657: * was empty, this will never occur.)
1658: */
1659: int
1660: prget(prompter, buf)
1661: char *prompter, *buf;
1662: {
1663: register char *p, *q, *r;
1664: register char c;
1665: char lastc;
1666: char hadprompt = buf[0];
1667:
1668: curflag = CURP2;
1669: r = buf + strlen(buf);
1670: lastc = '\0';
1671: for (;;) {
1672: p = secpr;
1673: for (q = prompter ; *q ; q++)
1674: *p++ = *q;
1675: for (q = buf ; *q ; q++) {
1676: if (p < &secpr[SECPRLEN-1] && *q >= ' ' && *q <= '~')
1677: *p++ = *q;
1678: }
1679: *p = '\0';
1680: c = vgetc();
1681: if (c == '\n' || c == '\r' || c == cintr) {
1682: break;
1683: }
1684: if (c == cerase || c == '\b' || c == '\177') {
1685: if (lastc == '\\')
1686: r[-1] = c;
1687: else if (r > buf)
1688: r--;
1689: } else if (c == ckill) {
1690: if (lastc == '\\')
1691: r[-1] = c;
1692: else
1693: r = buf;
1694: #ifdef TIOCGLTC
1695: } else if (c == cwerase) {
1696: if (lastc == '\\')
1697: r[-1] = c;
1698: else {
1699: while (r > buf && (r[-1] == ' ' || r[-1] == '\t'))
1700: r--;
1701: while (r > buf && r[-1] != ' ' && r[-1] != '\t')
1702: r--;
1703: }
1704: #endif
1705: } else {
1706: *r++ = c;
1707: }
1708: lastc = c;
1709: *r = '\0';
1710: if ((r == buf) && hadprompt)
1711: return 2;
1712: }
1713: curflag = CURHOME;
1714: secpr[0] = '\0';
1715: return (c == cintr);
1716: }
1717:
1718:
1719:
1720: /*
1721: * Execute a shell command.
1722: */
1723:
1724: shcmd(cmd, flags)
1725: char *cmd;
1726: {
1727: char *arg[4];
1728:
1729: arg[0] = SHELL, arg[1] = "-c", arg[2] = cmd, arg[3] = NULL;
1730: return prun(arg, flags);
1731: }
1732:
1733:
1734: prun(args, flags)
1735: char **args;
1736: {
1737: int pid;
1738: int i;
1739: int (*savequit)();
1740: char *env[100], **envp, **oenvp;
1741: char a[BUFLEN + 2];
1742: extern char **environ;
1743: int pstatus, retval;
1744:
1745: if (!(flags & BKGRND)) {
1746: botscreen();
1747: ttycooked();
1748: #ifdef SIGTSTP
1749: (void) signal(SIGTSTP, SIG_DFL);
1750: (void) signal(SIGTTIN, SIG_DFL);
1751: (void) signal(SIGTTOU, SIG_DFL);
1752: #endif
1753: }
1754: #if defined(BSD4_2) && !defined(sun)
1755: while ((pid = vfork()) == -1)
1756: #else /* !BSD4_2 */
1757: /* 4.1 BSD (at least) can't handle this vfork with -ljobs */
1758: while ((pid = fork()) == -1)
1759: #endif /* !BSD4_2 */
1760: sleep(1); /* must not clear alarm */
1761: if (pid == 0) {
1762: for (i = 3 ; i < 20 ; i++)
1763: close(i);
1764: if (flags & BKGRND) {
1765: (void) signal(SIGINT, SIG_IGN);
1766: (void) signal(SIGQUIT, SIG_IGN);
1767: #ifdef SIGTSTP
1768: (void) signal(SIGTSTP, SIG_IGN);
1769: (void) signal(SIGTTIN, SIG_IGN);
1770: (void) signal(SIGTTOU, SIG_IGN);
1771: #endif
1772: (void) close(0);
1773: (void) close(1);
1774: (void) open("/dev/null", 2);
1775: (void) dup(0);
1776: }
1777: /* set $A */
1778: (void) sprintf(a, "A=%s", filename);
1779: oenvp = environ;
1780: env[0] = a;
1781: for (envp = env + 1 ; *oenvp != NULL && envp < env + 98 ; oenvp++)
1782: if ((*oenvp)[0] != 'A' || (*oenvp)[1] != '=')
1783: *envp++ = *oenvp;
1784: *envp = NULL;
1785:
1786: (void) umask(savmask);
1787: execve(args[0], args, env);
1788: perror(args[0]);
1789: exit(20);
1790: }
1791: if (!(flags & BKGRND)) {
1792: savequit = signal(SIGQUIT, SIG_IGN);
1793: while ((i = wait(&pstatus)) != pid && (i != -1 || errno == EINTR))
1794: ;
1795: if (i == -1)
1796: retval = 1;
1797: else
1798: retval = pstatus;
1799: if (flags & CWAIT) {
1800: fprintf(stderr, "[Hit return to continue]");
1801: while ((errno = 0, i = getchar()) != '\n'
1802: && (i != EOF || errno == EINTR));
1803: }
1804: (void) signal(SIGQUIT, savequit);
1805: ttyraw();
1806: okclear();
1807: #ifdef SIGTSTP
1808: (void) signal(SIGTSTP, onstop);
1809: (void) signal(SIGTTIN, onstop);
1810: (void) signal(SIGTTOU, onstop);
1811: #endif
1812: return retval;
1813: } else
1814: return 0;
1815: }
1816:
1817: #ifdef DIGPAGE
1818:
1819:
1820: /*
1821: * Find end of current subarticle in digest.
1822: */
1823:
1824: findend(l)
1825: {
1826: register int i, n;
1827: register char *p;
1828:
1829: for (i = l ; i < l + ARTWLEN && i < lastlin ; i++) {
1830: tfget(linebuf, i);
1831: for (p = linebuf ; *p == '-' ; p++)
1832: ;
1833: n = (int) (p - linebuf);
1834: if ( (n > 23 && n < 33) || (n > 65 && n < 79)) {
1835: tfget(linebuf, ++i);
1836: if (linebuf[0] == '\0')
1837: return i + 1;
1838: }
1839: }
1840: return 0;
1841: }
1842:
1843: #endif
1844:
1845:
1846: /*** Routines for handling temporary file ***/
1847:
1848: /*
1849: * Append to temp file.
1850: * Long lines are folded.
1851: */
1852:
1853: tfappend(tline)
1854: register char *tline;
1855: {
1856: register char *nxtlin;
1857:
1858: do {
1859: nxtlin = index(tline, '\n');
1860: if (nxtlin)
1861: *nxtlin++ = '\0';
1862:
1863: while (strlen(tline) > COLS) {
1864: tfput(tline, lastlin++);
1865: tline += COLS;
1866: maxlinno++;
1867: }
1868: tfput(tline, lastlin++);
1869: } while ((tline = nxtlin) != NULL);
1870: }
1871:
1872:
1873: tfput(tline, linno)
1874: char *tline;
1875: {
1876: register char *p;
1877: register FILE *rtfp; /* try to make it a little faster */
1878: register int i;
1879:
1880: p = tline, i = even(COLS);
1881: tfseek(linno, 1);
1882: rtfp = tfp;
1883: while (--i >= 0) {
1884: if (*p)
1885: putc(*p++, rtfp);
1886: else
1887: putc('\0', rtfp);
1888: }
1889: tflinno++;
1890: }
1891:
1892:
1893: tfget(tline, linno)
1894: char *tline;
1895: {
1896: tfseek(linno, 0);
1897: fread(tline, even(COLS), 1, tfp);
1898: tline[COLS] = '\0';
1899: tflinno++;
1900: }
1901:
1902:
1903: tfseek(linno, wrflag)
1904: {
1905: static int lastwrflag = 1;
1906:
1907: if (linno != tflinno || wrflag != lastwrflag) {
1908: (void) fseek(tfp, (long)linno * even(COLS), 0);
1909: tflinno = linno;
1910: lastwrflag = wrflag;
1911: }
1912: }
1913:
1914: /* VARARGS1 */
1915: msg(s, a1, a2, a3, a4)
1916: char *s;
1917: long a1, a2, a3, a4;
1918: {
1919: (void) sprintf(secpr, s, a1, a2, a3, a4);
1920: }
1921:
1922:
1923: /*
1924: * Update the display.
1925: * The display is entirely controlled by this routine,
1926: * which means that this routine may get pretty snarled.
1927: */
1928:
1929: static int savelinno = -1; /* dlinno on last call to updscr */
1930: static int savepr; /* prflags on last call */
1931: #ifdef TIOCGWINSZ
1932: static int UPDATING = 0, WINCH = 0;
1933:
1934: /*
1935: * called by winch() from virtterm.c -- resets state information back
1936: * to start-up state and forces a full redraw of the screen. The
1937: * current article is rewound to the beginning because it's would
1938: * be very difficult to get the screen to return to the exact point
1939: * in the file that the user left off (I know, I tried).
1940: */
1941: winch_upd()
1942: {
1943: if(UPDATING) /* concurrency. wow! */
1944: WINCH++;
1945: else if((WINCH == 0) && (savelinno >= 0)) {
1946: int saveflag = curflag;
1947:
1948: /* reread the article */
1949: FCLOSE(fp);
1950: obit = -1;
1951: getnextart(FALSE);
1952: appfile(fp, dlinno + ARTWLEN + 1);
1953:
1954: /* fix up the screen */
1955: curflag = saveflag;
1956: strcpy(prompt,"more? ");
1957: okclear();
1958: updscr();
1959: }
1960: }
1961: #endif /* TIOCGWINSZ */
1962:
1963:
1964: updscr()
1965: {
1966: int count;
1967: int i;
1968:
1969: #ifdef TIOCGWINSZ
1970: UPDATING++;
1971: #endif /* TIOCGWINSZ */
1972: if (checkin())
1973: return;
1974: if ((prflags & HELPMSG) == 0
1975: && (dlinno != savelinno || savepr != prflags)
1976: && quitflg == 0) {
1977: if (dlinno != savelinno)
1978: prflags &=~ NOPRT;
1979: count = ARTWLEN;
1980: if (prflags & NOPRT)
1981: count = 0;
1982: if ((prflags & HDRONLY) && count > hdrend)
1983: count = hdrend - dlinno;
1984: #ifdef DIGPAGE
1985: if (endsuba > 0 && count > endsuba - dlinno)
1986: count = endsuba - dlinno;
1987: #endif
1988: if ((prflags & NEWART) == 0)
1989: ushift(ARTWIN, ARTWIN+ARTWLEN-1, dlinno - savelinno);
1990: if (count > lastlin - dlinno)
1991: count = lastlin - dlinno;
1992: for (i = ARTWIN ; i < ARTWIN + ARTWLEN ; i++)
1993: clrline(i);
1994: for (i = 0 ; i < count ; i++) {
1995: tfget(linebuf, dlinno + i);
1996: mvaddstr(ARTWIN + i, 0, linebuf);
1997: }
1998: prflags &=~ NEWART;
1999: savepr = prflags;
2000: savelinno = dlinno;
2001: }
2002: clrline(SPLINE), clrline(PRLINE);
2003: #ifdef STATTOP
2004: mvaddstr(PRLINE, 0, prompt);
2005: #else
2006: if (strlen(secpr) <= COLS)
2007: mvaddstr(PRLINE, 0, prompt);
2008: #endif
2009: mvaddstr(PRLINE, 59, timestr);
2010: mvaddstr(PRLINE, 17, groupdir);
2011: addch(' '); addnum(bit); addch('/'); addnum(pngsize); addch(' ');
2012: if (ismail)
2013: mvaddstr(PRLINE, 75, ismail > 1? "MAIL" : "mail");
2014: mvaddstr(SPLINE, 0, secpr);
2015: if (curflag == CURP1)
2016: move(PRLINE, strlen(prompt));
2017: else if (curflag == CURHOME)
2018: move(0, 0);
2019: refresh();
2020: #ifdef TIOCGWINSZ
2021: UPDATING=0;
2022: if (WINCH) { /* window changed while updating screen */
2023: WINCH = 0;
2024: winch_upd();
2025: }
2026: #endif /* TIOCGWINSZ */
2027: }
2028:
2029: addnum(n)
2030: register long n;
2031: {
2032: if (n >= 10)
2033: addnum(n / 10);
2034: addch((char)(n % 10 + '0'));
2035: }
2036:
2037: /*
2038: * Called on alarm signal.
2039: * Simply sets flag, signal processed later.
2040: */
2041:
2042: onalarm()
2043: {
2044: #ifdef SIGTSTP
2045: int dojump = reading;
2046:
2047: reading = FALSE;
2048: alflag++;
2049: if (dojump)
2050: longjmp(alrmjmp, 1);
2051: #else /* !SIGTSTP */
2052: alflag++;
2053: #endif
2054: }
2055:
2056: /*
2057: * Process alarm signal (or start clock)
2058: */
2059: timer()
2060: {
2061: time_t tod;
2062: int hour;
2063: int i;
2064: struct tm *t;
2065: struct stat statb;
2066: struct tm *localtime();
2067: static char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
2068: static long oldmsize = 1000000L;
2069: static int rccount = 10;
2070: static time_t lastismail = 0;
2071:
2072: alflag = 0;
2073: (void) signal(SIGALRM, onalarm);
2074: (void) time(&tod);
2075: t = localtime(&tod);
2076: i = 60 - t->tm_sec;
2077: (void) alarm(i > 30? 30 : i); /* reset alarm */
2078: hour = t->tm_hour % 12;
2079: if (hour == 0) hour = 12;
2080: (void) sprintf(timestr, "%.3s %d %d:%02d",
2081: months + 3 * t->tm_mon, t->tm_mday, hour, t->tm_min);
2082: if (mailf == NULL || stat(mailf, &statb) < 0) {
2083: statb.st_size = 0;
2084: }
2085: if (statb.st_size > oldmsize) {
2086: ismail = 2;
2087: beep();
2088: } else {
2089: if (statb.st_size == 0)
2090: ismail = 0;
2091: /* force MAIL for at least 30 seconds */
2092: else if (ismail > 1 && (lastismail+30) < tod)
2093: ismail = 1;
2094: }
2095: oldmsize = statb.st_size;
2096: lastismail = tod;
2097: if (uflag && !xflag && --rccount < 0) {
2098: writeoutrc();
2099: if (secpr[0] == '\0')
2100: (void) strcpy(secpr, ".newsrc updated");
2101: rccount = 10;
2102: }
2103: }
2104:
2105: char *
2106: getmailname()
2107: {
2108: static char mailname[32];
2109: register char *p;
2110:
2111: if( (p = getenv("MAIL")) != NULL)
2112: return p;
2113: #ifndef MMDF
2114: if (username[0] == '\0' || strlen(username) > 15)
2115: return NULL;
2116: #ifdef USG
2117: (void) sprintf(mailname, "/usr/mail/%s", username);
2118: #else /* !USG */
2119: (void) sprintf(mailname, "/usr/spool/mail/%s", username);
2120: #endif /* !USG */
2121: #else /* MMDF */
2122: (void) sprintf(mailname, "%s/mailbox", userhome);
2123: #endif /* MMDF */
2124: return mailname;
2125: }
2126:
2127:
2128:
2129: /*** Terminal I/O ***/
2130:
2131: #define INBUFSIZ 8
2132:
2133: char inbuf[INBUFSIZ]; /* input buffer */
2134: char outbuf[BUFSIZ]; /* output buffer */
2135: int innleft = 0; /* # of chars in input buffer */
2136: int outnleft = BUFSIZ; /* room left in output buffer */
2137: char *innext; /* next input character */
2138: char *outnext = outbuf; /* next space in output buffer */
2139: #ifdef USG
2140: int oflags; /* fcntl flags (for nodelay read) */
2141: #endif
2142:
2143: /*
2144: * Input a character
2145: */
2146:
2147: vgetc()
2148: {
2149: register c;
2150: #if defined(BSD4_2) || defined(BSD4_1C)
2151: int readfds, exceptfds;
2152: #endif
2153:
2154: recurse:
2155: if (--innleft >= 0) {
2156: c = *innext++;
2157: } else {
2158: if (alflag)
2159: timer();
2160: updscr(); /* update the display */
2161: for (;;) {
2162: if (innleft > 0 || alflag)
2163: goto recurse;
2164: intflag = 0;
2165: #ifdef USG
2166: if (oflags & O_NDELAY) {
2167: oflags &=~ O_NDELAY;
2168: fcntl(0, F_SETFL, oflags);
2169: }
2170: #endif
2171: #ifdef SIGTSTP
2172: if (setjmp(alrmjmp))
2173: continue;
2174: if (setjmp(intjmp))
2175: return cintr;
2176: reading = TRUE;
2177: #endif /* SIGTSTP */
2178: #if defined(BSD4_2) || defined(BSD4_1C)
2179: /* Use a select because it can be interrupted. */
2180: readfds = 1; exceptfds = 1;
2181: select(1, &readfds, (int *)0, &exceptfds, (int *)0);
2182: if (!(readfds & 1))
2183: break;
2184: #endif
2185: innleft = read(0, inbuf, INBUFSIZ);
2186: #ifdef SIGTSTP
2187: reading = FALSE;
2188: #endif /* SIGTSTP */
2189: if (innleft > 0)
2190: break;
2191: if (innleft == 0) {
2192: quitflg++;
2193: return cintr;
2194: }
2195: if (errno != EINTR)
2196: abort(); /* "Can't happen" */
2197: if (intflag) {
2198: intflag--;
2199: return cintr;
2200: }
2201: }
2202: innext = inbuf + 1;
2203: innleft--;
2204: c = inbuf[0];
2205: }
2206: #ifndef USG
2207: #ifndef CBREAK
2208: c &= 0177;
2209: if (c == '\034') /* FS character */
2210: xxit(0);
2211: #endif
2212: #endif
2213: if (c == '\f') {
2214: okclear();
2215: prflags &=~ NOPRT;
2216: goto recurse;
2217: }
2218: if (c == '\r')
2219: c = '\n';
2220: return c;
2221: }
2222:
2223:
2224: /*
2225: * Push a character back onto the input stream.
2226: */
2227:
2228: pushback(c)
2229: {
2230: if (innext <= inbuf)
2231: abort();
2232: *--innext = c;
2233: innleft++;
2234: }
2235:
2236: /*
2237: * Check for terminal input
2238: */
2239:
2240: checkin()
2241: {
2242: #ifdef FIONREAD
2243: int count;
2244: #endif
2245: #ifdef STATTOP
2246: if (innleft > 0)
2247: #else
2248: if (innleft > 0 || alflag)
2249: #endif
2250: return 1;
2251: #if defined(USG) || defined(FIONREAD)
2252: if (ospeed >= B9600)
2253: return 0;
2254: vflush();
2255: if (ospeed <= B300)
2256: ttyowait();
2257: #ifdef USG
2258: if ((oflags & O_NDELAY) == 0) {
2259: oflags |= O_NDELAY;
2260: (void) fcntl(0, F_SETFL, oflags);
2261: }
2262: if ((innleft = read(0, inbuf, INBUFSIZ)) > 0) {
2263: innext = inbuf;
2264: return 1;
2265: }
2266: #endif
2267: #ifdef FIONREAD
2268: count = 0; /* in case FIONREAD fails */
2269: (void) ioctl(0, FIONREAD, (char *)&count);
2270: if (count)
2271: return 1;
2272: #endif
2273: #endif
2274: return 0;
2275: }
2276:
2277:
2278:
2279: /*
2280: * flush terminal input queue.
2281: */
2282:
2283: clearin()
2284: {
2285: #ifdef USG
2286: (void) ioctl(0, TCFLSH, (char *)0);
2287: #else
2288: #ifdef TIOCFLUSH
2289: (void) ioctl(0, TIOCFLUSH, (char *)0);
2290: #else
2291: struct sgttyb tty;
2292: (void) ioctl(0, TIOCGETP, &tty);
2293: (void) ioctl(0, TIOCSETP, &tty);
2294: #endif
2295: #endif
2296: innleft = 0;
2297: }
2298:
2299: vputc(c)
2300: {
2301: if (--outnleft < 0) {
2302: vflush();
2303: outnleft--;
2304: }
2305: *outnext++ = c;
2306: }
2307:
2308: /*
2309: * Flush the output buffer
2310: */
2311:
2312: vflush()
2313: {
2314: register char *p;
2315: register int i;
2316: #ifdef BSD4_2
2317: int mask;
2318: #else
2319: unsigned oalarm;
2320: #endif
2321:
2322: #ifdef BSD4_2
2323: mask = sigblock(1 << (SIGALRM-1));
2324: #else
2325: oalarm = alarm(0);
2326: #endif
2327: for (p = outbuf ; p < outnext ; p += i) {
2328: if ((i = write(1, p, outnext - p)) < 0) {
2329: if (errno != EINTR)
2330: abort(); /* "Can't happen" */
2331: i = 0;
2332: }
2333: }
2334: outnleft = BUFSIZ;
2335: outnext = outbuf;
2336: #ifdef BSD4_2
2337: sigsetmask(mask);
2338: #else
2339: (void) alarm(oalarm);
2340: #endif
2341: }
2342:
2343: /*** terminal modes ***/
2344:
2345: #ifdef USG
2346: static struct termio oldtty, newtty;
2347:
2348: /*
2349: * Save tty modes
2350: */
2351:
2352: ttysave()
2353: {
2354: if (ioctl(1, TCGETA, &oldtty) < 0)
2355: xerror("Can't get tty modes");
2356: newtty = oldtty;
2357: newtty.c_iflag &=~ (INLCR|IGNCR|ICRNL);
2358: newtty.c_oflag &=~ (OPOST);
2359: newtty.c_lflag &=~ (ICANON|ECHO|ECHOE|ECHOK|ECHONL);
2360: newtty.c_lflag |= (NOFLSH);
2361: newtty.c_cc[VMIN] = 1;
2362: newtty.c_cc[VTIME] = 0;
2363: cerase = oldtty.c_cc[VERASE];
2364: ckill = oldtty.c_cc[VKILL];
2365: cintr = oldtty.c_cc[VINTR];
2366: ospeed = oldtty.c_cflag & CBAUD;
2367: initterm();
2368: }
2369:
2370:
2371: /*
2372: * Set tty modes for visual processing
2373: */
2374:
2375: ttyraw()
2376: {
2377: while (ioctl(1, TCSETAF, &newtty) < 0 && errno == EINTR)
2378: ;
2379: rawterm();
2380: }
2381:
2382: ttyowait()
2383: { /* wait for output queue to drain */
2384: while (ioctl(1, TCSETAW, &newtty) < 0 && errno == EINTR)
2385: ;
2386: }
2387:
2388: /*
2389: * Restore tty modes
2390: */
2391:
2392: ttycooked()
2393: {
2394: cookedterm();
2395: vflush();
2396: while (ioctl(1, TCSETAF, &oldtty) < 0 && errno == EINTR)
2397: ;
2398: oflags &=~ O_NDELAY;
2399: (void) fcntl(0, F_SETFL, oflags) ;
2400: }
2401:
2402: #else
2403:
2404: static struct sgttyb oldtty, newtty;
2405: #ifdef TIOCGLTC
2406: static struct ltchars oldltchars, newltchars;
2407: #endif
2408:
2409: /*
2410: * Save tty modes
2411: */
2412:
2413: ttysave()
2414: {
2415: #ifdef CBREAK
2416: struct tchars tchars; /* special characters, including interrupt */
2417: #endif
2418: #ifdef SIGTSTP
2419: int getpgrp();
2420: #if defined(BSD4_2) || defined(BSD4_1C)
2421: int tpgrp;
2422: #else /* BSD4_1 */
2423: short tpgrp;
2424: #endif /* BSD4_1 */
2425:
2426: retry:
2427: #ifdef BSD4_2
2428: (void) sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU));
2429: #else /* !BSD4_2 */
2430: (void) signal(SIGTSTP, SIG_HOLD);
2431: (void) signal(SIGTTIN, SIG_HOLD);
2432: (void) signal(SIGTTOU, SIG_HOLD);
2433: #endif /* !BSD4_2 */
2434: if (ioctl(2, TIOCGPGRP, (char *)&tpgrp) < 0)
2435: goto nottty;
2436: if (tpgrp != getpgrp(0)) { /* not in foreground */
2437: (void) signal(SIGTTOU, SIG_DFL);
2438: #ifdef BSD4_2
2439: (void) sigsetmask(sigblock(0) & ~sigmask(SIGTTOU));
2440: #endif /* BSD4_2 */
2441: (void) kill(0, SIGTTOU);
2442: /* job stops here waiting for SIGCONT */
2443: goto retry;
2444: }
2445: (void) signal(SIGTTIN, SIG_DFL);
2446: (void) signal(SIGTTOU, SIG_DFL);
2447: (void) signal(SIGTSTP, SIG_DFL);
2448: #ifdef BSD4_2
2449: (void) sigsetmask(sigblock(0) & ~(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU)));
2450: #endif /* BSD4_2 */
2451: #endif /* SIGTSTP */
2452: if (ioctl(1, TIOCGETP, (char *)&oldtty) < 0)
2453: nottty: xerror("Can't get tty modes");
2454: newtty = oldtty;
2455: newtty.sg_flags &=~ (CRMOD|ECHO|XTABS);
2456: #ifdef CBREAK
2457: newtty.sg_flags |= CBREAK;
2458: ioctl(1, TIOCGETC, (char *)&tchars);
2459: cintr = tchars.t_intrc;
2460: #else /* !CBREAK */
2461: newtty.sg_flags |= RAW;
2462: cintr = '\0177'; /* forcibly this on V6 systems */
2463: #endif /* !CBREAK */
2464: cerase = oldtty.sg_erase;
2465: ckill = oldtty.sg_kill;
2466: ospeed = oldtty.sg_ospeed;
2467: #ifdef TIOCGLTC
2468: if (ioctl(1, TIOCGLTC, (char *)&oldltchars) >= 0) {
2469: newltchars = oldltchars;
2470: newltchars.t_dsuspc = -1;
2471: cwerase = oldltchars.t_werasc;
2472: }
2473: #endif
2474: initterm();
2475: #ifdef SIGTSTP
2476: (void) signal(SIGTTIN, onstop);
2477: (void) signal(SIGTTOU, onstop);
2478: (void) signal(SIGTSTP, onstop);
2479: #endif /* SIGTSTP */
2480: }
2481:
2482:
2483: /*
2484: * Set tty modes for visual processing
2485: */
2486:
2487: ttyraw()
2488: {
2489: while (ioctl(1, TIOCSETN, (char *)&newtty) < 0 && errno == EINTR)
2490: ;
2491: #ifdef TIOCGLTC
2492: if (newltchars.t_dsuspc == '\377')
2493: while (ioctl(1, TIOCSLTC, (char *)&newltchars) < 0 && errno == EINTR)
2494: ;
2495: #endif
2496: rawterm();
2497: }
2498:
2499: ttyowait()
2500: { /* wait for output queue to drain */
2501: #ifdef TIOCDRAIN /* This ioctl is a local mod on linus */
2502: (void) ioctl(1, TIOCDRAIN, (char *)0);
2503: #endif
2504: }
2505:
2506:
2507: /*
2508: * Restore tty modes
2509: */
2510:
2511: ttycooked()
2512: {
2513: cookedterm();
2514: vflush();
2515: while (ioctl(1, TIOCSETN, (char *)&oldtty) < 0 && errno == EINTR)
2516: ;
2517: #ifdef TIOCGLTC
2518: if (newltchars.t_dsuspc == '\377')
2519: while (ioctl(1, TIOCSLTC, (char *)&oldltchars) < 0 && errno == EINTR)
2520: ;
2521: #endif
2522: }
2523:
2524: #endif
2525:
2526:
2527:
2528: /*** signal handlers ***/
2529:
2530: onint() {
2531: #ifdef SIGTSTP
2532: int dojump = reading;
2533:
2534: reading = FALSE;
2535: #endif /* SIGTSTP */
2536: if (!news) {
2537: ttycooked();
2538: xxit(1);
2539: }
2540: (void) signal(SIGINT, onint);
2541: clearin(); /* flush input queue */
2542: #ifdef SIGTSTP
2543: if (dojump)
2544: longjmp(intjmp, 1);
2545: #endif /* SIGTSTP */
2546: intflag++;
2547: }
2548:
2549: #ifdef SIGTSTP
2550: onstop(signo)
2551: int signo;
2552: {
2553: /* restore old terminal state */
2554: botscreen();
2555: vflush();
2556: ttycooked();
2557: (void) signal(signo, SIG_DFL);
2558: #ifdef BSD4_2
2559: (void) sigblock(sigmask(SIGALRM)|sigmask(SIGINT));
2560: (void) sigsetmask(sigblock(0) & ~sigmask(signo));
2561: #else /* BSD4_1 */
2562: (void) alarm(0);
2563: #endif /* BSD4_1 */
2564: (void) kill(0, signo); /* stop here until continued */
2565:
2566: (void) signal(signo, onstop);
2567: /* restore our special terminal state */
2568: ttyraw();
2569: #ifdef TIOCGWINSZ
2570: winch(); /* get current window size and redraw screen */
2571: #else /* !TIOCGWINSZ */
2572: okclear();
2573: updscr();
2574: #endif /* !TIOCGWINSZ */
2575: #ifdef BSD4_2
2576: (void) sigsetmask(sigblock(0) & ~(sigmask(SIGALRM)|sigmask(SIGINT)));
2577: #else /* BSD4_1 */
2578: timer();
2579: #endif /* BSD4_1 */
2580: }
2581: #endif
2582:
2583: /*** stolen from rfuncs2.c and modified ***/
2584:
2585: vsave(to, flags)
2586: register char *to;
2587: {
2588: register FILE *ufp;
2589: int isprogram = 0;
2590: int isnew = 1;
2591: long saveoff;
2592: char temp[20];
2593: char *fname;
2594: char prog[BUFLEN + 24];
2595: int err;
2596:
2597: saveoff = ftell(fp);
2598: (void) fseek(fp, artbody, 0);
2599: fname = to;
2600: if (*to == PIPECHAR) {
2601: if (strlen(to) > BUFLEN) {
2602: msg("Command name too long");
2603: goto out;
2604: }
2605: flags |= OVWRITE;
2606: (void) strcpy(temp, "/tmp/vnXXXXXX");
2607: (void) mktemp(temp);
2608: fname = temp;
2609: _amove(ROWS - 1, 0);
2610: vflush();
2611: }
2612: if ((flags & OVWRITE) == 0) {
2613: ufp = fopen(fname, "r");
2614: if (ufp != NULL) {
2615: (void) fclose(ufp);
2616: isnew = 0;
2617: }
2618: }
2619: (void) umask(savmask);
2620:
2621: if (*to == PIPECHAR)
2622: isprogram++;
2623: if ((ufp = fopen(fname, (flags & OVWRITE) == 0? "a" : "w")) == NULL) {
2624: msg("Cannot open %s", fname);
2625: goto out;
2626: }
2627: /*
2628: * V7MAIL code is here to conform to V7 mail format.
2629: * If you need a different format to be able to
2630: * use your local mail command (such as four ^A's
2631: * on the end of articles) substitute it here.
2632: */
2633: if (flags & SVHEAD) {
2634: #ifdef MMDF
2635: if (!isprogram)
2636: fprintf(ufp, "\001\001\001\001\n");
2637: #endif /* MMDF */
2638: #ifdef V7MAIL
2639: h->subtime = cgtdate(h->subdate);
2640: fprintf(ufp, "From %s %s", replyname(h), ctime(&h->subtime));
2641: #endif
2642: hprint(h, ufp, 2);
2643: #ifdef V7MAIL
2644: tprint(fp, ufp, TRUE);
2645: putc('\n', ufp); /* force blank line at end (ugh) */
2646: #else
2647: tprint(fp, ufp, FALSE);
2648: #endif
2649: } else {
2650: tprint(fp, ufp, FALSE);
2651: }
2652:
2653: err = ferror(ufp);
2654:
2655: fclose(ufp);
2656: if (isprogram) {
2657: if (err)
2658: msg("error in writing temp file, maybe disk full?");
2659: else {
2660: (void) sprintf(prog, "(%s)<%s", to + 1, fname);
2661: shcmd(prog, CWAIT);
2662: prflags |= NOPRT;
2663: }
2664: } else {
2665: msg("%sfile: %s %s",
2666: err? "ERROR WHILE WRITING ": "",
2667: to,
2668: (flags&OVWRITE)? "written":
2669: isnew ? "created" : "appended");
2670: }
2671:
2672: /* If we got an error, screen may be messed. E.g. 4.2BSD
2673: * writes "disk full" messages to the user's tty.
2674: */
2675: if (err) {
2676: okclear();
2677: updscr();
2678: }
2679:
2680: out:
2681: if (isprogram) {
2682: (void) unlink(fname);
2683: }
2684: (void) umask(N_UMASK);
2685: (void) fseek(fp, saveoff, 0);
2686: }
2687:
2688: xxit(status)
2689: int status;
2690: {
2691: (void) unlink(infile);
2692: (void) unlink(outfile);
2693: #ifdef SORTACTIVE
2694: if (STRNCMP(ACTIVE,"/tmp/", 5) == 0)
2695: (void) unlink(ACTIVE);
2696: #endif /* SORTACTIVE */
2697: #ifdef SERVER
2698: (void) unlink(active_name());
2699: close_server();
2700: #endif /* SERVER */
2701: if (ospeed) { /* is == 0, we haven't been in raw mode yet */
2702: botscreen();
2703: vflush();
2704: ttycooked();
2705: }
2706: exit(status);
2707: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.