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