rsalz@bbn.com (Rich Salz) (12/04/90)
Submitted-by: Wayne Davison <davison@dri.com> Posting-number: Volume 23, Issue 69 Archive-name: trn/part10 ---- Cut Here and unpack ---- #!/bin/sh # this is part 10 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file ng.c continued # CurArch=10 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file ng.c" sed 's/^X//' << 'SHAR_EOF' >> ng.c X#endif X /*NOSTRICT*/ X toread[ng] = (ART_UNREAD)ucount; /* this is perhaps pointless */ X art = lastart + 1; /* keep bitmap references sane */ X if (art != curr_art) { X#ifdef USETHREADS X recent_p_art = curr_p_art; X find_article(art); X curr_p_art = p_art; X#endif X recent_art = curr_art; X /* remember last article # (for '-') */ X curr_art = art; /* remember this article # */ X } X if (erase_screen) X clear(); /* clear the screen */ X else X fputs("\n\n",stdout) FLUSH; X#ifdef VERBOSE X IF(verbose) X printf("End of newsgroup %s.",ngname); X /* print pseudo-article */ X ELSE X#endif X#ifdef TERSE X printf("End of %s",ngname); X#endif X if (ucount) { X#ifdef USETHREADS X if (selected_root_cnt) X printf(" (%ld + %ld articles still unread)", X (long)selected_count,(long)ucount-selected_count); X else X#endif X printf(" (%ld article%s still unread)", X (long)ucount,ucount==1?nullstr:"s"); X } X else { X if (!forcelast) X goto cleanup; /* actually exit newsgroup */ X } X prompt = whatnext; X#ifdef ARTSEARCH X srchahead = 0; /* no more subject search mode */ X#endif X fputs("\n\n",stdout) FLUSH; X skipstate = 0; /* back to none skipped */ X } X else if (!reread && was_read(art)) { X /* has this article been read? */ X#ifdef USETHREADS X follow_thread('n'); X#else X art++; /* then skip it */ X#endif X continue; X } X else if X (!reread && !was_read(art) X#ifdef SERVER X && nntpopen(art,GET_HEADER) == Nullfp) { X#else X && artopen(art) == Nullfp) { /* never read it, & cannot find it? */ X if (errno != ENOENT) { /* has it not been deleted? */ X#ifdef VERBOSE X IF(verbose) X printf("\n(Article %ld exists but is unreadable.)\n", X (long)art) FLUSH; X ELSE X#endif X#ifdef TERSE X printf("\n(%ld unreadable.)\n",(long)art) FLUSH; X#endif X skipstate = 0; X sleep(2); X } X#endif X switch(skipstate++) { X case 0: X clear(); X#ifdef VERBOSE X IF(verbose) X fputs("Skipping unavailable article",stdout); X ELSE X#endif X#ifdef TERSE X fputs("Skipping",stdout); X#endif X for (i = just_a_sec/3; i; --i) X putchar(PC); X fflush(stdout); X sleep(1); X break; X case 1: X fputs("..",stdout); X fflush(stdout); X break; X default: X putchar('.'); X fflush(stdout); X#ifndef SERVER X#define READDIR X#ifdef READDIR X { /* fast skip patch */ X ART_NUM newart; X X if (! (newart=getngmin(".",art))) X newart = lastart+1; X for (i=art; i<newart; i++) X oneless(i); X art = newart - 1; X } X#endif X#else X { X char ser_line[256]; X ART_NUM newart; X X put_server("NEXT"); X if (get_server(ser_line, sizeof (ser_line)) < 0) { X fprintf(stderr, X "rrn: unexpected close of server socket.\n"); X finalize(1); X } X if (ser_line[0] != CHAR_OK) X newart = lastart + 1; X else X newart = atoi(ser_line+4); X for (i=art; i<newart; i++) X oneless(i); X art = newart - 1; X } X#endif /* SERVER */ X break; X } X oneless(art); /* mark deleted as read */ X#ifdef USETHREADS X count_roots(FALSE); /* Keep selected_count accurate */ X find_article(art); X follow_thread('n'); X#else X art++; /* try next article */ X#endif X continue; X } X else { /* we have a real live article */ X skipstate = 0; /* back to none skipped */ X if (art != curr_art) { X#ifdef USETHREADS X recent_p_art = curr_p_art; X find_article(art); X curr_p_art = p_art; X#endif X recent_art = curr_art; X /* remember last article # (for '-') */ X curr_art = art; /* remember this article # */ X } X if (!do_fseek) { /* starting at top of article? */ X artline = 0; /* start at the beginning */ X topline = -1; /* and remember top line of screen */ X /* (line # within article file) */ X } X clear(); /* clear screen */ X if (!artopen(art)) { /* make sure article is found & open */ X#ifdef USETHREADS X char tmpbuf[256]; X /* see if we have tree data for this article anyway */ X init_tree(); X sprintf(tmpbuf,"%s #%ld is not available.",ngname,(long)art); X tree_puts(tmpbuf,0,0); X vwtary((ART_LINE)0,(ART_POS)0); X finish_tree(1); X prompt = whatnext; X#else X printf("Article %ld of %s is not available.\n\n", X (long)art,ngname) FLUSH; X prompt = whatnext; X#endif X#ifdef ARTSEARCH X srchahead = 0; X#endif X } X else { /* found it, so print it */ X switch (do_article()) { X case DA_CLEAN: /* quit newsgroup */ X goto cleanup; X case DA_TOEND: /* do not mark as read */ X goto reask_article; X case DA_RAISE: /* reparse command at end of art */ X goto article_level; X case DA_NORM: /* normal end of article */ X break; X } X } X if (art >= absfirst) /* don't mark non-existant articles */ X mark_as_read(); /* mark current article as read */ X reread = FALSE; X do_hiding = TRUE; X#ifdef ROTATION X rotate = FALSE; X#endif X } X X/* if these gotos bother you, think of this as a little state machine */ X Xreask_article: X#ifdef MAILCALL X setmail(); X#endif X setdfltcmd(); X#ifdef CLEAREOL X if (erase_screen && can_home_clear) X clear_rest(); X#endif /* CLEAREOL */ X unflush_output(); /* disable any ^O in effect */ X standout(); /* enter standout mode */ X printf(prompt,mailcall,dfltcmd);/* print prompt, whatever it is */ X un_standout(); /* leave standout mode */ X putchar(' '); X fflush(stdout); Xreinp_article: X eat_typeahead(); X#ifdef PENDING X look_ahead(); /* see what we can do in advance */ X if (!input_pending()) X collect_subjects(); /* loads subject cache until */ X /* input is pending */ X#endif X getcmd(buf); X if (errno || *buf == '\f') { X if (LINES < 100 && !int_count) X *buf = '\f'; /* on CONT fake up refresh */ X else { X putchar('\n') FLUSH; /* but only on a crt */ X goto reask_article; X } X } Xarticle_level: X X /* parse and process article level command */ X X switch (art_switch()) { X case AS_INP: /* multichar command rubbed out */ X goto reinp_article; X case AS_ASK: /* reprompt "End of article..." */ X goto reask_article; X case AS_CLEAN: /* exit newsgroup */ X goto cleanup; X case AS_NORM: /* display article art */ X break; X } X } /* end of article selection loop */ X X/* shut down newsgroup */ X Xcleanup: X uud_end(); X#ifdef KILLFILES X kill_unwanted(firstart,"\nCleaning up...\n\n",FALSE); X /* do cleanup from KILL file, if any */ X#endif X#ifdef USETHREADS X if (ThreadedGroup) X unuse_data(0); /* free article thread data */ X#endif X in_ng = FALSE; /* leave newsgroup state */ X if (artfp != Nullfp) { /* article still open? */ X fclose(artfp); /* close it */ X artfp = Nullfp; /* and tell the world */ X#ifdef SERVER X sprintf(artname, "/tmp/rrn%ld.%ld", (long) openart, our_pid); X UNLINK(artname); X#endif /* SERVER */ X openart = 0; X } X putchar('\n') FLUSH; X yankback(); /* do a Y command */ X restore_ng(); /* reconstitute .newsrc line */ X doing_ng = FALSE; /* tell sig_catcher to cool it */ X free(ctlarea); /* return the control area */ X#ifdef CACHESUBJ X if (subj_list) { X for (i=OFFSET(lastart); i>=0; --i) X if (subj_list[i]) X free(subj_list[i]); X#ifndef lint X free((char*)subj_list); X#endif /* lint */ X } X#endif X write_rc(); /* and update .newsrc */ X rc_changed = FALSE; /* tell sig_catcher it is ok */ X if (chdir(spool)) { X printf(nocd,spool) FLUSH; X sig_catcher(0); X } X#ifdef KILLFILES X if (localkfp) { X fclose(localkfp); X localkfp = Nullfp; X } X#endif X mode = oldmode; X return exit_code; X} /* Whew! */ X X/* decide what to do at the end of an article */ X Xint Xart_switch() X{ X register ART_NUM i; X X setdef(buf,dfltcmd); X#ifdef VERIFY X printcmd(); X#endif X X switch (*buf) { X#ifdef USETHREADS X case '<': /* goto previous thread */ X if (!ThreadedGroup) { X goto group_unthreaded; X } X prev_root(); X return AS_NORM; X case '>': /* goto next thread */ X if (!ThreadedGroup) { X goto group_unthreaded; X } X next_root(); X return AS_NORM; X case 'U': { /* unread some articles */ X char *u_prompt, *u_help_thread; X X if (!ThreadedGroup) { X dfltcmd = "a"; X u_help_thread = nullstr; X#ifdef VERBOSE X IF(verbose) X u_prompt = "\nSet unread: all articles? [an] "; X ELSE X#endif X#ifdef TERSE X u_prompt = "\nUnread? [an] "; X#endif X } X else if (!p_art || art > lastart) { X dfltcmd = "+"; X u_help_thread = nullstr; X#ifdef VERBOSE X IF(verbose) X u_prompt = "\nSet unread: +select or all? [+an] "; X ELSE X#endif X#ifdef TERSE X u_prompt = "\nUnread? [+an] "; X#endif X } X else { X dfltcmd = "t"; X#ifdef VERBOSE X IF(verbose) { X u_prompt = "\n\ XSet unread: thread, subthread, +select, or all? [ts+an] "; X u_help_thread = "\ XType t or SP to mark this thread's articles as unread.\n\ XType s to mark the current article and its descendants as unread.\n"; X } X ELSE X#endif X#ifdef TERSE X { X u_prompt = "\nUnread? [ts+an] "; X u_help_thread = "\ Xt or SP to mark thread unread.\n\ Xs to mark subthread unread.\n"; X } X#endif X } X reask_unread: X in_char(u_prompt,'u'); X putchar('\n') FLUSH; X setdef(buf,dfltcmd); X#ifdef VERIFY X printcmd(); X#endif X if (*buf == 'h') { X fputs(u_help_thread,stdout); X#ifdef VERBOSE X IF(verbose) X { X if (ThreadedGroup) X fputs("\ XType + to enter select thread mode using all the unread articles.\n\ X(The selected threads will be marked as unread and displayed as usual.)\n\ X",stdout) FLUSH; X fputs("\ XType a to mark all articles in this group as unread.\n\ XType n to change nothing.\n\ X",stdout) FLUSH; X } X ELSE X#endif X#ifdef TERSE X { X if (ThreadedGroup) X fputs("\ X+ to select threads from the unread.\n\ X",stdout) FLUSH; X fputs("\ Xa to mark all articles unread.\n\ Xn to change nothing.\n\ X",stdout) FLUSH; X } X#endif X goto reask_unread; X } X else if (*buf == 'n' || *buf == 'q') { X return AS_ASK; X } X else if (*buf == 't' && *dfltcmd == 't') X follow_thread('u'); X else if (*buf == 's' && *dfltcmd == 't') { X follow_thread('U'); X } X else if (*buf == 'a') { X check_first(absfirst); X for (i = absfirst; i <= lastart; i++) { X onemore(i); /* mark as unread */ X } X scan_all_roots = FALSE; X count_roots(FALSE); X if (art > lastart) { X first_art(); X } X } X else if (ThreadedGroup && *buf == '+') { X *buf = 'U'; X goto select_threads; X } X else { X fputs(hforhelp,stdout) FLUSH; X settle_down(); X goto reask_unread; X } X return AS_NORM; X } X case '[': /* goto parent article */ X case '{': /* goto thread's root article */ X if (p_art) { X if (!p_art->parent) { X if (p_art == p_articles + p_roots[p_art->root].articles) { X register char *cp = (*buf=='['?"parent":"root"); X#ifdef VERBOSE X IF(verbose) X fprintf(stdout,"\n\ XThere is no %s article prior to this one.\n",cp) FLUSH; X ELSE X#endif X#ifdef TERSE X fprintf(stdout,"\nNo prior %s.\n",cp) FLUSH; X#endif X return AS_ASK; X } X *buf = '{'; X p_art--; X } X else X p_art += p_art->parent; X X if (*buf == '{') X while (p_art->parent) X p_art += p_art->parent; X X art = p_art->num; X reread = TRUE; X return AS_NORM; X } Xnot_threaded: X if (ThreadedGroup) { X#ifdef VERBOSE X IF(verbose) X fputs("\nThis article is not threaded.\n",stdout) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nUnthreaded article.\n",stdout) FLUSH; X#endif X return AS_ASK; X } Xgroup_unthreaded: X#ifdef VERBOSE X IF(verbose) X fputs("\nThis group is not threaded.\n",stdout) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nUnthreaded group.\n",stdout) FLUSH; X#endif X return AS_ASK; X case ']': /* goto child article */ X case '}': /* goto thread's leaf article */ X if (p_art) { X if (!(p_art++)->child_cnt) { X PACKED_ARTICLE *root_limit = upper_limit(p_art-1,FALSE); X X if (p_art == root_limit) { X#ifdef VERBOSE X IF(verbose) X fputs("\n\ XThis is the last leaf in this tree.\n",stdout) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nLast leaf.\n",stdout) FLUSH; X#endif X p_art--; X return AS_ASK; X } X if (*buf == ']') X *buf = '}'; X else { X while (++p_art != root_limit && p_art->parent) X ; X p_art--; X *buf = ' '; X } X } X if( *buf == '}' ) X while (p_art->child_cnt) X p_art++; X X art = p_art->num; X reread = TRUE; X return AS_NORM; X } X goto not_threaded; X case 'T': X if (p_art) { X sprintf(buf,"T%ld\t# %s",(long)p_roots[p_art->root].root_num, X subject_ptrs[p_art->subject]); X fputs(buf,stdout); X kf_append(buf); X *buf = 'J'; X goto follow_threads; X } X goto not_threaded; X case 'K': X if (p_art) { X /* first, write kill-subject command */ X (void)art_search(buf, (sizeof buf), TRUE); X art = curr_art; X p_art = curr_p_art; X *buf = 'k'; /* then take care of any prior subjs */ X goto follow_threads; X } X goto normal_search; X case ',': /* kill this node and all descendants */ X mark_as_read(); X *buf = 'K'; X case 'k': /* kill current subject # (e.g. [1]) */ X case 'J': /* Junk all nodes in this thread */ X if (!ThreadedGroup) { X *buf = 'k'; X goto normal_search; X } Xfollow_threads: X follow_thread(*buf); X if (!reread && !toread[ng]) X return AS_CLEAN; X if (!reread && selected_root_cnt && !selected_count) X goto select_threads; X return AS_NORM; X case 't': X carriage_return(); X#ifndef CLEAREOL X erase_eol(); /* erase the prompt */ X#else X if (erase_screen && can_home_clear) X clear_rest(); X else X erase_eol(); /* erase the prompt */ X#endif /* CLEAREOL */ X fflush(stdout); X page_line = 1; X p_art = curr_p_art; X entire_tree(); X return AS_ASK; X case ':': /* execute command on selected articles */ X if (!ThreadedGroup) { X goto group_unthreaded; X } X page_line = 1; X if (!use_selected()) X return AS_INP; X putchar('\n'); X art = curr_art; X p_art = curr_p_art; X return AS_ASK; X#endif /* USETHREADS */ X case 'p': /* find previous unread article */ X#ifdef USETHREADS X if (ThreadedGroup) { X goto backtrack_threads; X } X#endif X do { X if (art <= firstart) X break; X art--; X#ifdef SERVER X } while (was_read(art) || nntpopen(art,GET_HEADER) == Nullfp); X#else X } while (was_read(art) || artopen(art) == Nullfp); X#endif X#ifdef ARTSEARCH X srchahead = 0; X#endif X return AS_NORM; X case 'P': /* goto previous article */ X#ifdef USETHREADS X if (ThreadedGroup) { Xbacktrack_threads: X backtrack_thread( *buf ); X art++; /* prepare for art-- below */ X } X#endif X if (art > absfirst) X art--; X else { X#ifdef VERBOSE X IF(verbose) X fprintf(stdout,"\n\ XThere are no%s articles prior to this one.\n\ X",*buf=='P'?nullstr:" unread") FLUSH; X ELSE X#endif X#ifdef TERSE X fprintf(stdout,"\n\ XNo previous%s articles\n\ X",*buf=='P'?nullstr:" unread") FLUSH; X#endif X art = curr_art; X#ifdef USETHREADS X p_art = curr_p_art; X#endif X return AS_ASK; X } X reread = TRUE; X#ifdef ARTSEARCH X srchahead = 0; X#endif X return AS_NORM; X case '-': X if (recent_art >= 0) { X#ifdef USETHREADS X p_art = recent_p_art; X#endif X art = recent_art; X reread = TRUE; X#ifdef ARTSEARCH X srchahead = -(srchahead != 0); X#endif X return AS_NORM; X } X else { X exit_code = NG_MINUS; X return AS_CLEAN; X } X case 'n': /* find next unread article? */ X#ifdef USETHREADS X if (ThreadedGroup) { X goto follow_threads; X } X#endif X if (art > lastart) { X if (!toread[ng]) X return AS_CLEAN; X art = firstart; X } X#ifdef ARTSEARCH X else if (scanon && srchahead) { X *buf = Ctl('n'); X goto normal_search; X } X#endif X else X art++; X X#ifdef ARTSEARCH X srchahead = 0; X#endif X return AS_NORM; X case 'N': /* goto next article */ X#ifdef USETHREADS X if (ThreadedGroup) { X goto follow_threads; X } X#endif X if (art > lastart) X art = absfirst; X else X art++; X if (art <= lastart) X reread = TRUE; X#ifdef ARTSEARCH X srchahead = 0; X#endif X return AS_NORM; X case '$': X art = lastart+1; X forcelast = TRUE; X#ifdef USETHREADS X p_art = Nullart; X#endif X#ifdef ARTSEARCH X srchahead = 0; X#endif X return AS_NORM; X case '1': case '2': case '3': /* goto specified article */ X case '4': case '5': case '6': /* or do something with a range */ X case '7': case '8': case '9': case '.': X forcelast = TRUE; X switch (numnum()) { X case NN_INP: X return AS_INP; X case NN_ASK: X return AS_ASK; X case NN_REREAD: X reread = TRUE; X#ifdef ARTSEARCH X if (srchahead) X srchahead = -1; X#endif X break; X case NN_NORM: X if (was_read(art)) { X#ifdef USETHREADS X first_art(); X#else X art = firstart; X#endif X pad(just_a_sec/3); X } X else { X putchar('\n'); X return AS_ASK; X } X break; X } X return AS_NORM; X case Ctl('k'): X edit_kfile(); X return AS_ASK; X#ifndef USETHREADS X case 'K': X case 'k': X#endif X case Ctl('n'): /* search for next article with same subject */ X#ifdef USETHREADS X if (ThreadedGroup) { X goto follow_threads; X } X#endif X case Ctl('p'): /* search for previous article with same subject */ X#ifdef USETHREADS X if (ThreadedGroup) { X goto backtrack_threads; X } X#endif X case '/': case '?': Xnormal_search: X#ifdef ARTSEARCH X { /* search for article by pattern */ X char cmd = *buf; X X reread = TRUE; /* assume this */ X page_line = 1; X switch (art_search(buf, (sizeof buf), TRUE)) { X case SRCH_ERROR: X art = curr_art; X return AS_ASK; X case SRCH_ABORT: X art = curr_art; X return AS_INP; X case SRCH_INTR: X#ifdef VERBOSE X IF(verbose) X printf("\n(Interrupted at article %ld)\n",(long)art) FLUSH; X ELSE X#endif X#ifdef TERSE X printf("\n(Intr at %ld)\n",(long)art) FLUSH; X#endif X art = curr_art; X /* restore to current article */ X return AS_ASK; X case SRCH_DONE: X fputs("done\n",stdout) FLUSH; X pad(just_a_sec/3); /* 1/3 second */ X if (!srchahead) { X art = curr_art; X return AS_ASK; X } X#ifdef USETHREADS X first_art(); X#else X art = firstart; X#endif X reread = FALSE; X return AS_NORM; X case SRCH_SUBJDONE: X#ifdef UNDEF X fputs("\n\n\n\nSubject not found.\n",stdout) FLUSH; X pad(just_a_sec/3); /* 1/3 second */ X#endif X#ifdef USETHREADS X first_art(); X#else X art = firstart; X#endif X reread = FALSE; X return AS_NORM; X case SRCH_NOTFOUND: X fputs("\n\n\n\nNot found.\n",stdout) FLUSH; X art = curr_art; /* restore to current article */ X return AS_ASK; X case SRCH_FOUND: X if (cmd == Ctl('n') || cmd == Ctl('p')) X oldsubject = TRUE; X break; X } X return AS_NORM; X } X#else X buf[1] = '\0'; X notincl(buf); X return AS_ASK; X#endif X case 'u': /* unsubscribe from this newsgroup? */ X rcchar[ng] = NEGCHAR; X return AS_CLEAN; X case 'M': X#ifdef DELAYMARK X if (art <= lastart) { X delay_unmark(art); X printf("\nArticle %ld will return.\n",(long)art) FLUSH; X } X#else X notincl("M"); X#endif X return AS_ASK; X case 'm': X if (art <= lastart) { X unmark_as_read(); X printf("\nArticle %ld marked as still unread.\n",(long)art) FLUSH; X } X return AS_ASK; X case 'c': /* catch up */ X reask_catchup: X#ifdef VERBOSE X IF(verbose) X in_char("\nDo you really want to mark everything as read? [yn] ", X 'C'); X ELSE X#endif X#ifdef TERSE X in_char("\nReally? [ynh] ", 'C'); X#endif X putchar('\n') FLUSH; X setdef(buf,"y"); X#ifdef VERIFY X printcmd(); X#endif X if (*buf == 'h') { X#ifdef VERBOSE X IF(verbose) X fputs("\ XType y or SP to mark all articles as read.\n\ XType n to leave articles marked as they are.\n\ XType u to mark everything read and unsubscribe.\n\ X",stdout) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\ Xy or SP to mark all read.\n\ Xn to forget it.\n\ Xu to mark all and unsubscribe.\n\ X",stdout) FLUSH; X#endif X goto reask_catchup; X } X else if (*buf == 'n' || *buf == 'q') { X return AS_ASK; X } X else if (*buf != 'y' && *buf != 'u') { X fputs(hforhelp,stdout) FLUSH; X settle_down(); X goto reask_catchup; X } X for (i = firstart; i <= lastart; i++) { X oneless(i); /* mark as read */ X } X#ifdef USETHREADS X selected_root_cnt = selected_count = 0; X#endif X#ifdef DELAYMARK X if (dmfp) X yankback(); X#endif X if (*buf == 'u') { X rcchar[ng] = NEGCHAR; X return AS_CLEAN; X } X#ifdef USETHREADS X p_art = Nullart; X selected_count = 0; X#endif X art = lastart+1; X forcelast = FALSE; X return AS_NORM; X case 'Q': X exit_code = NG_ASK; X /* FALL THROUGH */ X case 'q': /* go back up to newsgroup level? */ X return AS_CLEAN; X case 'j': X putchar('\n') FLUSH; X if (art <= lastart) X mark_as_read(); X return AS_ASK; X case 'h': { /* help? */ X int cmd; X X if ((cmd = help_art()) > 0) X pushchar(cmd); X return AS_ASK; X } X case '&': X if (switcheroo()) /* get rest of command */ X return AS_INP; /* if rubbed out, try something else */ X return AS_ASK; X case '#': X#ifdef VERBOSE X IF(verbose) X printf("\nThe last article is %ld.\n",(long)lastart) FLUSH; X ELSE X#endif X#ifdef TERSE X printf("\n%ld\n",(long)lastart) FLUSH; X#endif X return AS_ASK; X#ifdef USETHREADS X case '+': /* enter thread selection mode */ X if (ThreadedGroup) { Xselect_threads: X *buf = select_thread(*buf); X if (*buf == 'q') { X putchar( '\n' ) FLUSH; X return AS_ASK; X } X if (*buf == 'Q') { X exit_code = NG_ASK; X return AS_CLEAN; X } X if (*buf == 'N' || !toread[ng]) X return AS_CLEAN; X return AS_NORM; X } X /* FALLTHROUGH */ X#endif X case '=': { /* list subjects */ X char tmpbuf[256]; X ART_NUM oldart = art; X int cmd; X char *subjline = getval("SUBJLINE",Nullch); X#ifndef CACHESUBJ X char *s; X#endif X X page_init(); X#ifdef CACHESUBJ X if (!subj_list) X fetchsubj(art,TRUE,FALSE); X#endif X for (i=firstart; i<=lastart && !int_count; i++) { X#ifdef CACHESUBJ X if (!was_read(i) && X (subj_list[OFFSET(i)] != Nullch || fetchsubj(i,FALSE,FALSE)) && X *subj_list[OFFSET(i)] ) { X sprintf(tmpbuf,"%5ld ", i); X if (subjline) { X art = i; X interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline); X } X else X safecpy(tmpbuf + 6, subj_list[OFFSET(i)], X (sizeof tmpbuf) - 6); X if (cmd = print_lines(tmpbuf,NOMARKING)) { X if (cmd > 0) X pushchar(cmd); X break; X } X } X#else X if (!was_read(i) && (s = fetchsubj(i,FALSE,FALSE)) && *s) { X sprintf(tmpbuf,"%5ld ", i); X if (subjline) { /* probably fetches it again! */ X art = i; X interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline); X } X else X safecpy(tmpbuf + 6, s, (sizeof tmpbuf) - 6); X if (cmd = print_lines(tmpbuf,NOMARKING)) { X if (cmd > 0) X pushchar(cmd); X break; X } X } X#endif X } X int_count = 0; X art = oldart; X return AS_ASK; X } X case '^': X#ifdef USETHREADS X first_art(); X#else X art = firstart; X#endif X#ifdef ARTSEARCH X srchahead = 0; X#endif X return AS_NORM; X#if defined(CACHESUBJ) && defined(DEBUGGING) X case 'D': X printf("\nFirst article: %ld\n",(long)firstart) FLUSH; X if (!subj_list) X fetchsubj(art,TRUE,FALSE); X if (subj_list != Null(char **)) { X for (i=1; i<=lastart && !int_count; i++) { X if (subj_list[OFFSET(i)]) X printf("%5ld %c %s\n", X i, (was_read(i)?'y':'n'), subj_list[OFFSET(i)]) FLUSH; X } X } X int_count = 0; X return AS_ASK; X#endif X case 'v': X if (art <= lastart) { X reread = TRUE; X do_hiding = FALSE; X } X return AS_NORM; X#ifdef ROTATION X case Ctl('x'): X#endif X case Ctl('r'): X#ifdef ROTATION X rotate = (*buf==Ctl('x')); X#endif X if (art <= lastart) X reread = TRUE; X return AS_NORM; X#ifdef ROTATION X case 'X': X rotate = !rotate; X /* FALL THROUGH */ X#else X case Ctl('x'): X case 'x': X case 'X': X notincl("x"); X return AS_ASK; X#endif X case 'l': case Ctl('l'): /* refresh screen */ X if (art <= lastart) { X reread = TRUE; X clear(); X do_fseek = TRUE; X artline = topline; X if (artline < 0) X artline = 0; X } X return AS_NORM; X case 'b': case Ctl('b'): /* back up a page */ X if (art <= lastart) { X ART_LINE target; X X reread = TRUE; X clear(); X do_fseek = TRUE; X target = topline - (LINES - 2); X artline = topline; X while (artline >= 0 && artline > target && vrdary(artline-1) >= 0) X artline--; X topline = artline; X if (artline < 0) X artline = 0; X } X return AS_NORM; X case '!': /* shell escape */ X if (escapade()) X return AS_INP; X return AS_ASK; X case 'C': { X cancel_article(); X return AS_ASK; X } X case 'R': X case 'r': { /* reply? */ X reply(); X return AS_ASK; X } X case 'F': X case 'f': { /* followup command */ X followup(); X forcegrow = TRUE; /* recalculate lastart */ X return AS_ASK; X } X case '|': X case 'w': case 'W': X case 's': case 'S': /* save command */ X case 'e': /* extract command */ X if (save_article() == SAVE_ABORT) X return AS_INP; X int_count = 0; X return AS_ASK; X case 'E': X if (uu_out != Nullfp) { X uud_end(); X } X return AS_ASK; X#ifdef DELAYMARK X case 'Y': /* yank back M articles */ X yankback(); X#ifdef USETHREADS X first_art(); X#else X art = firstart; /* from the beginning */ X#endif X return AS_NORM; /* pretend nothing happened */ X#endif X#ifdef STRICTCR X case '\n': X fputs(badcr,stdout) FLUSH; X return AS_ASK; X#endif X default: X printf("\n%s",hforhelp) FLUSH; X settle_down(); X return AS_ASK; X } X} X X#ifdef MAILCALL X/* see if there is any mail */ X Xvoid Xsetmail() X{ X if (! (mailcount++)) { X char *mailfile = filexp(getval("MAILFILE",MAILFILE)); X X if (stat(mailfile,&filestat) < 0 || !filestat.st_size X || filestat.st_atime > filestat.st_mtime) X mailcall = nullstr; X else X mailcall = getval("MAILCALL","(Mail) "); X } X mailcount %= 10; /* check every 10 articles */ X} X#endif X Xvoid Xsetdfltcmd() X{ X#ifdef USETHREADS X if (toread[ng] == unthreaded) { X#else X if (!toread[ng]) { X#endif X if (art > lastart) X dfltcmd = "qnp"; X else X dfltcmd = "npq"; X } X else { X#ifdef USETHREADS X if (selected_root_cnt && !selected_count) X dfltcmd = "+npq"; X else X# ifdef ARTSEARCH X if (!ThreadedGroup && srchahead) X dfltcmd = "^Nnpq"; X else X# endif X#else X# ifdef ARTSEARCH X if (srchahead) X dfltcmd = "^Nnpq"; X else X# endif X#endif X dfltcmd = "npq"; X } X} SHAR_EOF echo "File ng.c is complete" chmod 0660 ng.c || echo "restore of ng.c fails" echo "x - extracting ng.h (Text)" sed 's/^X//' << 'SHAR_EOF' > ng.h && X/* $Header: ng.h,v 4.3 85/05/01 11:44:29 lwall Exp $ X * X * $Log: ng.h,v $ X * Revision 4.3 85/05/01 11:44:29 lwall X * Baseline for release with 4.3bsd. X * X */ X XEXT ART_NUM art INIT(0); /* current or prospective article # */ X XEXT int checkcount INIT(0); /* how many articles have we read */ X /* in the current newsgroup since */ X /* the last checkpoint? */ XEXT int docheckwhen INIT(20); /* how often to do checkpoint */ X X#ifdef MAILCALL XEXT int mailcount INIT(0); /* check for mail when 0 mod 10 */ X#endif XEXT char *mailcall INIT(nullstr); X XEXT bool forcelast INIT(FALSE); /* ought we show "End of newsgroup"? */ XEXT bool forcegrow INIT(FALSE); /* do we want to recalculate size */ X /* of newsgroup, e.g. after posting? */ X X#define NG_ERROR -1 X#define NG_NORM 0 X#define NG_ASK 1 X#define NG_MINUS 2 X Xvoid ng_init(); Xint do_newsgroup(); Xint art_switch(); X#ifdef MAILCALL X void setmail(); X#endif Xvoid setdfltcmd(); SHAR_EOF chmod 0660 ng.h || echo "restore of ng.h fails" echo "x - extracting ngdata.c (Text)" sed 's/^X//' << 'SHAR_EOF' > ngdata.c && X/* $Header: ngdata.c,v 4.3.3.1 90/07/21 20:28:27 davison Trn $ X * X * $Log: ngdata.c,v $ X * Revision 4.3.3.1 90/07/21 20:28:27 davison X * Initial Trn Release X * X * Revision 4.3.2.10 90/04/14 22:05:15 sob X * Removed redundant declaration of active_name X * X * Revision 4.3.2.9 90/03/22 23:04:55 sob X * Fixes provided by Wayne Davison <drivax!davison> X * X * Revision 4.3.2.8 90/03/17 20:50:51 sob X * Fixes provided by stewart@netxcom.iad-nxe.global-mis.dhl.com to handle X * flaky transfers of the active file from the server. X * X * Revision 4.3.2.7 90/03/17 17:11:08 sob X * Added support for CNEWS active file flags. X * X * Revision 4.3.2.6 89/12/08 22:42:04 sob X * Corrected typo in an #ifdef statement pointed out by X * jik@pit-manager.mit.edu X * X * Revision 4.3.2.5 89/11/28 01:51:14 sob X * Removed redundant #include directive. X * X * Revision 4.3.2.4 89/11/27 01:31:07 sob X * Altered NNTP code per ideas suggested by Bela Lubkin X * <filbo@gorn.santa-cruz.ca.us> X * X * Revision 4.3.2.3 89/11/08 02:41:40 sob X * Removed unneeded subroutine. X * X * Revision 4.3.2.2 89/11/08 02:24:31 sob X * Integrated modifications from other RRN patches colleceted from USENET X * X * Revision 4.3.2.1 89/11/06 00:42:43 sob X * Added RRN support from NNTP 1.5 X * X * Revision 4.3 85/05/01 11:44:38 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "ndir.h" X#include "rcstuff.h" X#include "rn.h" X#include "intrp.h" X#include "final.h" X#include "rcln.h" X#include "util.h" X#ifdef SERVER X#include "server.h" X#endif X#include "INTERN.h" X#include "ngdata.h" X Xvoid Xngdata_init() X{ X#ifdef SERVER X char ser_line[256]; X int entries; X#endif X char *cp; X X/* The following is only for systems that do not zero globals properly */ X#ifdef ZEROGLOB X# ifdef CACHEFIRST X for (i=0; i<MAXRCLINE; i++) X abs1st[i] = 0; X# endif X#endif /* ZEROGLOB */ X X /* open the active file */ X X#ifdef SERVER X X#ifdef USETHREADS X if (use_threads) { X cp = filexp(ACTIVE2); X actfp = fopen(cp,"r"); X if (actfp == Nullfp) { X printf(cantopen,cp) FLUSH; X finalize(1); X } X return; X } X#endif X X put_server("LIST"); /* tell server we want the active file */ X get_server(ser_line, sizeof(ser_line)); X if (*ser_line != CHAR_OK) { /* and then see if that's ok */ X fprintf(stdout, "Can't get active file from server: \n%s\n", ser_line); X finalize(1); X } X X cp = filexp("/tmp/rrnact.%$"); /* make a temporary name */ X strcpy(active_name, cp); X actfp = fopen(active_name, "w+"); /* and get ready */ X if (actfp == Nullfp) { X printf(cantopen,active_name) FLUSH; X finalize(1); X } X X entries = 0; X while (1) { X if (get_server(ser_line, sizeof(ser_line)) < 0) { X printf("Can't get active file from server:\ntransfer failed after %d entries\n", entries); X finalize(1); X } X if (ser_line[0] == '.') /* while there's another line */ X break; /* get it and write it to */ X entries++; X fputs(ser_line, actfp); X putc('\n', actfp); X } X X fseek(actfp,0L,0); /* just get to the beginning */ X X#else /* not SERVER */ X X#ifdef USETHREADS X if (use_threads) X cp = filexp(ACTIVE2); X else X#endif X cp = filexp(ACTIVE); X actfp = fopen(cp,"r"); X if (actfp == Nullfp) { X printf(cantopen,cp) FLUSH; X finalize(1); X } X#endif X} X X/* find the maximum article number of a newsgroup */ X XART_NUM Xgetngsize(num) Xregister NG_NUM num; X{ X register int len; X register char *nam; X char tmpbuf[80]; X ART_POS oldsoft; X X nam = rcline[num]; X len = rcnums[num] - 1; X softtries++; X#ifdef DEBUGGING X if (debug & DEB_SOFT_POINTERS) X printf("Softptr = %ld\n",(long)softptr[num]) FLUSH; X#endif X oldsoft = softptr[num]; X if ((softptr[num] = findact(tmpbuf, nam, len, (long)oldsoft)) >= 0) { X if (softptr[num] != oldsoft) { X softmisses++; X writesoft = TRUE; X } X } X else { X softptr[num] = 0; X if (rcchar[num] == ':') /* unsubscribe quietly */ X rcchar[num] = NEGCHAR; X return TR_BOGUS; /* well, not so quietly, actually */ X } X X#ifdef DEBUGGING X if (debug & DEB_SOFT_POINTERS) { X printf("Should be %ld\n",(long)softptr[num]) FLUSH; X } X#endif X#ifdef MININACT X { X register char *s, ch; X ART_NUM tmp; X X for (s=tmpbuf+len+1; isdigit(*s); s++) ; X if (tmp = atol(s)) X#ifdef CACHEFIRST X abs1st[num] = tmp; X#else X abs1st = tmp; X#endif X if (!in_ng) { X for (s++; isdigit(*s); s++) ; X while (isspace(*s)) s++; X ch = *s; X#ifdef USETHREADS X if (isupper(ch)) { X ch = tolower(ch); X ThreadedGroup = FALSE; X } else X ThreadedGroup = use_threads; X#endif X switch (ch) { X case 'n': moderated = getval("NOPOSTRING"," (no posting)"); break; X case 'm': moderated = getval("MODSTRING", " (moderated)"); break; X /* This shouldn't even occur. What are we doing in a non-existent X group? Disallow it. */ X case 'x': return TR_BOGUS; X /* what should be done about refiled groups? rn shouldn't even X be in them (ie, if sci.aquaria is refiled to rec.aquaria, then X get the news there) */ X case '=': return TR_BOGUS; X default: moderated = nullstr; X } X } X } X#endif X return atol(tmpbuf+len+1); X} X XACT_POS Xfindact(outbuf,nam,len,suggestion) Xchar *outbuf; Xchar *nam; Xint len; Xlong suggestion; X{ X ACT_POS retval; X X fseek(actfp,100000L,1); /* hopefully this forces a reread */ X if (suggestion == 0L || fseek(actfp,suggestion,0) < 0 || X fgets(outbuf,80,actfp) == Nullch || X outbuf[len] != ' ' || X strnNE(outbuf,nam,len)) { X#ifdef DEBUGGING X if (debug & DEB_SOFT_POINTERS) X printf("Missed, looking for %s in %sLen = %d\n",nam,outbuf,len) X FLUSH; X#endif X fseek(actfp,0L,0); X#ifndef lint X retval = (ACT_POS)ftell(actfp); X#else X retval = Null(ACT_POS); X#endif /* lint */ X while (fgets(outbuf,80,actfp) != Nullch) { X if (outbuf[len] == ' ' && strnEQ(outbuf,nam,len)) X return retval; X#ifndef lint X retval = (ACT_POS) ftell(actfp); X#endif /* lint */ X } X return (ACT_POS) -1; /* well, not so quietly, actually */ X } X else X#ifndef lint X return (ACT_POS) suggestion; X#else X return retval; X#endif /* lint */ X /*NOTREACHED*/ X} X X/* determine the absolutely first existing article number */ X#ifdef SERVER XART_NUM Xgetabsfirst(ngnum,ngsize) Xregister NG_NUM ngnum; XART_NUM ngsize; X{ X register ART_NUM a1st; X#ifndef MININACT X char ser_line[256]; X ART_NUM x,y; X#endif X X#ifdef CACHEFIRST X if (a1st = abs1st[ngnum]) X return a1st; X#endif X#ifdef MININACT X getngsize(ngnum); X# ifdef CACHEFIRST X return abs1st[ngnum]; X# else X return abs1st; X# endif X#else X sprintf(cp,"GROUP %s",rcline[ngnum]); X put_server(cp); X if (get_server(ser_line, sizeof(ser_line)) < 0) { X fprintf(stderr, "rrn: Unexpected close of server socket.\n"); X finalize(1); X } X if (*ser_line != CHAR_OK) { /* and then see if that's ok */ X a1st = ngsize+1; /* nothing there */ X } X (void) sscanf(ser_line,"%d%d%d",&x,&y,&a1st); X# ifdef CACHEFIRST X abs1st[ngnum] = a1st; X# endif X return a1st; X#endif X} X/* we already know the lowest article number with NNTP */ XART_NUM Xgetngmin(dirname,floor) Xchar *dirname; XART_NUM floor; X{ X return(floor); X} X#else XART_NUM Xgetabsfirst(ngnum,ngsize) Xregister NG_NUM ngnum; XART_NUM ngsize; X{ X register ART_NUM a1st; X#ifndef MININACT X char dirname[MAXFILENAME]; X#endif X X#ifdef CACHEFIRST X if (a1st = abs1st[ngnum]) X return a1st; X#endif X#ifdef MININACT X getngsize(ngnum); X# ifdef CACHEFIRST X return abs1st[ngnum]; X# else X return abs1st; X# endif X#else /* not MININACT */ X sprintf(dirname,"%s/%s",spool,getngdir(rcline[ngnum])); X a1st = getngmin(dirname,0L); X if (!a1st) /* nothing there at all? */ X a1st = ngsize+1; /* aim them at end of newsgroup */ X# ifdef CACHEFIRST X abs1st[ngnum] = a1st; X# endif X return a1st; X#endif /* MININACT */ X} X X/* scan a directory for minimum article number greater than floor */ X XART_NUM Xgetngmin(dirname,floor) Xchar *dirname; XART_NUM floor; X{ X register DIR *dirp; X register struct DIRTYPE *dp; X register ART_NUM min = 1000000; X register ART_NUM maybe; X register char *p; X char tmpbuf[128]; X X dirp = opendir(dirname); X if (!dirp) X return 0; X while ((dp = readdir(dirp)) != Null(struct DIRTYPE *)) { X if ((maybe = atol(dp->d_name)) < min && maybe > floor) { X for (p = dp->d_name; *p; p++) X if (!isdigit(*p)) X goto nope; X if (*dirname == '.' && !dirname[1]) X stat(dp->d_name, &filestat); X else { X sprintf(tmpbuf,"%s/%s",dirname,dp->d_name); X stat(tmpbuf, &filestat); X } X if (! (filestat.st_mode & S_IFDIR)) X min = maybe; X } X nope: X ; X } X closedir(dirp); X return min==1000000 ? 0 : min; X} X#endif SHAR_EOF chmod 0660 ngdata.c || echo "restore of ngdata.c fails" echo "x - extracting ngdata.h (Text)" sed 's/^X//' << 'SHAR_EOF' > ngdata.h && X/* $Header: ngdata.h,v 4.3.3.1 90/06/20 22:38:50 davison Trn $ X * X * $Log: ngdata.h,v $ X * Revision 4.3.3.1 90/06/20 22:38:50 davison X * Initial Trn Release X * X * Revision 4.3.2.1 89/11/06 00:41:21 sob X * Added RRN support from NNTP 1.5 X * X * Revision 4.3 85/05/01 11:44:48 lwall X * added to local RCS X * X * Revision 4.3 85/05/01 11:44:48 lwall X * Baseline for release with 4.3bsd. X * X */ X XEXT FILE *actfp INIT(Nullfp); /* the active file */ XEXT bool writesoft INIT(FALSE); /* rewrite the soft pointer file? */ XEXT int softtries INIT(0), softmisses INIT(0); X X#ifdef SERVER X EXT char active_name[256]; X#endif X X#ifdef CACHEFIRST X EXT ART_NUM abs1st[MAXRCLINE]; /* 1st real article in newsgroup */ X#else X# ifdef MININACT X EXT ART_NUM abs1st INIT(0); X# endif X#endif X XEXT char *moderated; X#ifdef USETHREADS XEXT bool ThreadedGroup; X#endif X Xvoid ngdata_init(); XART_NUM getngsize(); XACT_POS findact(); XART_NUM getabsfirst(); XART_NUM getngmin(); SHAR_EOF chmod 0660 ngdata.h || echo "restore of ngdata.h fails" echo "x - extracting ngsrch.c (Text)" sed 's/^X//' << 'SHAR_EOF' > ngsrch.c && X/* $Header: ngsrch.c,v 4.3 85/05/01 11:44:51 lwall Exp $ X * X * $Log: ngsrch.c,v $ X * Revision 4.3 85/05/01 11:44:51 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "rcstuff.h" X#include "final.h" X#include "search.h" X#include "rn.h" X#include "util.h" X#include "term.h" X#include "rcln.h" X#include "INTERN.h" X#include "ngsrch.h" X X#ifdef NGSORONLY X COMPEX ngcompex; X#endif X Xvoid Xngsrch_init() X{ X#ifdef ZEROGLOB X init_compex(&ngcompex); X#endif /* ZEROGLOB */ X ; X} X X#ifdef NGSEARCH Xint Xng_search(patbuf,get_cmd) Xchar *patbuf; /* if patbuf != buf, get_cmd must */ Xint get_cmd; /* be set to FALSE!!! */ X{ X char *pattern; /* unparsed pattern */ X register char cmdchr = *patbuf; /* what kind of search? */ X register char *s; X bool backward = cmdchr == '?'; /* direction of search */ X X int_count = 0; X if (get_cmd && buf == patbuf) X if (!finish_command(FALSE)) /* get rest of command */ X return NGS_ABORT; X for (pattern = patbuf+1; *pattern == ' '; pattern++) ; X if (*pattern) { X ng_doread = FALSE; X } X s = rindex(pattern,cmdchr); X if (s != Nullch && *(s-1) != '\\') { X *s++ = '\0'; X if (index(s,'r') != Nullch) X ng_doread = TRUE; X } X if ((s = ng_comp(&ngcompex,pattern,TRUE,TRUE)) != Nullch) { X /* compile regular expression */ X printf("\n%s\n",s) FLUSH; X return NGS_ABORT; X } X fputs("\nSearching...",stdout) FLUSH; /* give them something to read */ X fflush(stdout); X for (;;) { X if (int_count) { X int_count = 0; X return NGS_INTR; X } X if (backward) { X if (ng > 0) X --ng; X else X ng = nextrcline; X } X else { X if (ng >= nextrcline) X ng = 0; X else X ++ng; X } X if (ng == current_ng) X return NGS_NOTFOUND; X if (ng == nextrcline || toread[ng] < TR_NONE || !ng_wanted()) X continue; X if (toread[ng] == TR_NONE) X set_toread(ng); X X if (toread[ng] > TR_NONE) X return NGS_FOUND; X else if (toread[ng] == TR_NONE) X if (ng_doread) X return NGS_FOUND; X else X printf("\n[0 unread in %s--skipping]",rcline[ng]) FLUSH; X } X} X Xbool Xng_wanted() X{ X return execute(&ngcompex,rcline[ng]) != Nullch; X} X#endif X X#ifdef NGSORONLY Xchar * Xng_comp(compex,pattern,RE,fold) XCOMPEX *compex; Xchar *pattern; Xbool RE; Xbool fold; X{ X char ng_pattern[128]; X register char *s = pattern, *d = ng_pattern; X X if (!*s) X return Nullch; /* reuse old pattern */ X for (; *s; s++) { X if (*s == '.') { X *d++ = '\\'; X *d++ = *s; X } X else if (*s == '?') { X *d++ = '.'; X } X else if (*s == '*') { X *d++ = '.'; X *d++ = *s; X } X else if (strnEQ(s,"all",3)) { X *d++ = '.'; X *d++ = '*'; X s += 2; X } X else X *d++ = *s; X } X *d = '\0'; X return compile(compex,ng_pattern,RE,fold); X} X#endif X SHAR_EOF chmod 0660 ngsrch.c || echo "restore of ngsrch.c fails" echo "x - extracting ngsrch.h (Text)" sed 's/^X//' << 'SHAR_EOF' > ngsrch.h && X/* $Header: ngsrch.h,v 4.3 85/05/01 11:44:56 lwall Exp $ X * X * $Log: ngsrch.h,v $ X * Revision 4.3 85/05/01 11:44:56 lwall X * Baseline for release with 4.3bsd. X * X */ X X#ifdef NGSEARCH X#define NGS_ABORT 0 X#define NGS_FOUND 1 X#define NGS_INTR 2 X#define NGS_NOTFOUND 3 X XEXT bool ng_doread INIT(FALSE); /* search read newsgroups? */ X#endif X Xvoid ngsrch_init(); X#ifdef NGSEARCH X int ng_search(); X bool ng_wanted(); X#endif X#ifdef NGSORONLY X char *ng_comp(); X#endif SHAR_EOF chmod 0660 ngsrch.h || echo "restore of ngsrch.h fails" echo "x - extracting ngstuff.c (Text)" sed 's/^X//' << 'SHAR_EOF' > ngstuff.c && X/* $Header: ngstuff.c,v 4.3.3.1 90/07/21 20:29:12 davison Trn $ X * X * $Log: ngstuff.c,v $ X * Revision 4.3.3.1 90/07/21 20:29:12 davison X * Initial Trn Release X * X * Revision 4.3.2.2 90/04/14 19:40:02 sob X * Fixed small syntax problem that generates errors with particular C X * preprocessors. X * X * Revision 4.3.1.2 85/05/10 14:31:52 lwall X * Prevented "Junked" or "Marked unread" when no state change. X * X * Revision 4.3.1.1 85/05/10 11:36:45 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 11:45:03 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "term.h" X#include "util.h" X#include "ng.h" X#include "bits.h" X#include "intrp.h" X#include "cheat.h" X#include "head.h" X#include "final.h" X#include "sw.h" X#ifdef USETHREADS X#include "rthreads.h" X#include "rn.h" X#include "rcstuff.h" X#endif X#include "uudecode.h" X#include "INTERN.h" X#include "ngstuff.h" X Xvoid Xngstuff_init() X{ X ; X} X X/* do a shell escape */ X Xint Xescapade() X{ X register char *s; X bool interactive = (buf[1] == FINISHCMD); X bool docd; X char whereiam[256]; X X if (!finish_command(interactive)) /* get remainder of command */ X return -1; X s = buf+1; X docd = *s != '!'; X if (!docd) { X s++; X } X else { X getwd(whereiam); X if (chdir(cwd)) { X printf(nocd,cwd) FLUSH; X sig_catcher(0); X } X } X while (*s == ' ') s++; X /* skip leading spaces */ X interp(cmd_buf, (sizeof cmd_buf), s);/* interpret any % escapes */ X resetty(); /* make sure tty is friendly */ X doshell(Nullch,cmd_buf); /* invoke the shell */ X noecho(); /* and make terminal */ X crmode(); /* unfriendly again */ X if (docd) { X if (chdir(whereiam)) { X printf(nocd,whereiam) FLUSH; X sig_catcher(0); X } X } X#ifdef MAILCALL X mailcount = 0; /* force recheck */ X#endif X return 0; X} X X/* process & command */ X Xint Xswitcheroo() X{ X if (!finish_command(TRUE)) /* get rest of command */ X return -1; /* if rubbed out, try something else */ X if (!buf[1]) X pr_switches(); X#ifdef PUSHBACK X else if (buf[1] == '&') { X if (!buf[2]) { X page_init(); X show_macros(); X } X else { X char tmpbuf[LBUFLEN]; X register char *s; X X for (s=buf+2; isspace(*s); s++); X mac_line(s,tmpbuf,(sizeof tmpbuf)); X } X } X#endif X else { X bool docd = (instr(buf,"-d") != Nullch); X char whereami[256]; X X if (docd) X getwd(whereami); X sw_list(buf+1); X if (docd) { X cwd_check(); X if (chdir(whereami)) { /* -d does chdirs */ X printf(nocd,whereami) FLUSH; X sig_catcher(0); X } X } X } X return 0; X} X X/* process range commands */ X Xint Xnumnum() X{ X ART_NUM min, max; X char *cmdlst = Nullch; X register char *s, *c; X ART_NUM oldart = art; X char tmpbuf[LBUFLEN]; X bool justone = TRUE; /* assume only one article */ X X perform_cnt = 0; X if (!finish_command(TRUE)) /* get rest of command */ X return NN_INP; X if (lastart < 1) { X fputs("\nNo articles\n",stdout) FLUSH; X return NN_ASK; X } X#ifdef ARTSRCH X if (srchahead) X srchahead = -1; X#endif X for (s=buf; *s && (isdigit(*s) || index(" ,-.$",*s)); s++) X if (!isdigit(*s)) X justone = FALSE; X if (*s) { X cmdlst = savestr(s); X justone = FALSE; X } X else if (!justone) X cmdlst = savestr("m"); X *s++ = ','; X *s = '\0'; X safecpy(tmpbuf,buf,LBUFLEN); X for (s = tmpbuf; c = index(s,','); s = ++c) { X *c = '\0'; X if (*s == '.') X min = oldart; X else X min = atol(s); X#ifdef USETHREADS X if (min<absfirst && justone) { X int r; X X /* Check if this is a root number */ X for (r = 0; r < total.root; r++) { X if (p_roots[r].root_num == min) { X p_art = p_articles + p_roots[r].articles; X art = p_art->num; X if (p_art->subject == -1) { X follow_thread('N'); X } X return NN_REREAD; X } X } X } X#endif X if (min<absfirst) { /* make sure it is reasonable */ X min = absfirst; X printf("(First article is %ld)\n",(long)absfirst) FLUSH; X pad(just_a_sec/3); X } X if ((s=index(s,'-')) != Nullch) { X s++; X if (*s == '$') X max = lastart; X else if (*s == '.') X max = oldart; X else X max = atol(s); X } X else X max = min; X if (max>lastart) { X max = lastart; X if (min > max) X min = max; X printf("(Last article is %ld)\n",(long)lastart) FLUSH; X pad(just_a_sec/3); X } X if (max < min) { X fputs("\nBad range\n",stdout) FLUSH; X if (cmdlst) X free(cmdlst); X return NN_ASK; X } X if (justone) { X art = min; X return NN_REREAD; X } X check_first(min); X for (art=min; art<=max; art++) { X if (perform(cmdlst,TRUE)) { X#ifdef VERBOSE X IF(verbose) X printf("\n(Interrupted at article %ld)\n",(long)art) X FLUSH; X ELSE X#endif X#ifdef TERSE X printf("\n(Intr at %ld)\n",(long)art) FLUSH; X#endif X if (cmdlst) X free(cmdlst); X return NN_ASK; X } X } X } X art = oldart; X if (cmdlst) X free(cmdlst); X return NN_NORM; X} X X#ifdef USETHREADS Xint Xuse_selected() X{ X PACKED_ARTICLE *root_limit; X register char *s, ch; X register int r; X char *cmdstr; X int ret = 1, orig_root_cnt = selected_root_cnt; X X if (!finish_command(TRUE)) /* get rest of command */ X return 0; X if (!(ch = buf[1])) X return -1; X cmdstr = savestr(buf+1); X X perform_cnt = 0; X page_line = 1; X X /* Multiple commands and commands that operate on individual articles X ** use the article loop. X */ X if (strlen(cmdstr) > 1 || index("ejmMsSwW|=", ch)) { X bool want_unread = (unread_selector || ch == 'm'); X X for (r = 0; r < total.root; r++) { X if (scan_all_roots X || (!orig_root_cnt&&root_article_cnts[r]&&!(selected_roots[r]&4)) X || (selected_roots[r] & (unread_selector+1))) { X p_art = p_articles + p_roots[r].articles; X root_limit = upper_limit( p_art, 0 ); X for (; p_art < root_limit; p_art++) { X art = p_art->num; X if (p_art->subject != -1 X && (!was_read(art) ^ want_unread)) { X if (perform(cmdstr, TRUE)) { X fputs("\nInterrupted\n", stdout) FLUSH; X goto break_out; X } X } X if (p_art == Nullart) X break; X }/* for all articles */ X }/* if selected */ X }/* for all threads */ X } /* other commands get the root loop */ X else if (ch == '+' || ch == '-' || ch == 'J' || ch == 'T' || ch == 't') { X for (r = 0; r < total.root; r++) { X if (scan_all_roots X || (!orig_root_cnt&&root_article_cnts[r]&&!(selected_roots[r]&4)) X || (selected_roots[r] & (unread_selector+1))) { X if (mode != 't' && ch != 't') { X printf("T%-5ld ", (long)p_roots[r].root_num); X } X p_art = p_articles + p_roots[r].articles; X art = p_art->num; X if (perform(cmdstr, FALSE)) { X fputs("\nInterrupted\n", stdout) FLUSH; X goto break_out; X } X#ifdef VERBOSE X IF(verbose) X if (mode != 't' && ch != 't' && ch != 'T') X putchar('\n') FLUSH; X#endif X } X } X } X else if (ch == 'E') { /* one command needs no looping at all */ X if (uu_out != Nullfp) { X uud_end(); X } else { X ret = 2; X } X } X else { X printf("???%s\n",cmdstr); X ret = -1; X } X break_out: X free(cmdstr); X return ret; X} X#endif X Xint Xperform(cmdlst,toplevel) Xregister char *cmdlst; Xint toplevel; X{ X register int ch; X X if (toplevel) { X printf("%-6ld ",art); X fflush(stdout); X } X perform_cnt++; X for (; ch = *cmdlst; cmdlst++) { X if (isspace(ch) || ch == ':') X continue; X if (ch == 'j') { X if (!was_read(art)) { X mark_as_read(); X#ifdef VERBOSE X IF(verbose) X fputs("\tJunked",stdout); X#endif X } X } X#ifdef USETHREADS X else if (ch == '+') { X find_article(art); X if (p_art && !(selected_roots[p_art->root] & (unread_selector+1))) { X selected_roots[p_art->root] |= (unread_selector+1); X selected_root_cnt++; X if (mode == 't') { X selected_count += root_article_cnts[p_art->root]; X } else { X selected_count += count_one_root(p_art->root); X#ifdef VERBOSE X IF(verbose) X fputs("\tSelected",stdout); X#endif X } X } X } X else if (ch == '-') { X find_article(art); X if (p_art && selected_root_cnt X && (selected_roots[p_art->root] & (unread_selector+1))) { X selected_roots[p_art->root] &= ~(unread_selector+1); X selected_root_cnt--; X if (mode == 't') { X selected_count -= root_article_cnts[p_art->root]; X } else { X selected_count -= count_one_root(p_art->root); X#ifdef VERBOSE X IF(verbose) X fputs("\tDeselected",stdout); X#endif X } X } X } X else if (ch == 't') { X find_article(art); X entire_tree(); X } X else if (ch == 'J' || ch == 'T') { X char tmpbuf[128]; X ART_NUM oldart = art; X X find_article(art); X if (p_art) { X if (ch == 'T') { X sprintf(tmpbuf,"T%ld\t# %s", X (long)p_roots[p_art->root].root_num, X subject_ptrs[p_art->subject]); X fputs(tmpbuf,stdout); X kf_append(tmpbuf); X } X follow_thread('J'); X art = oldart; X } X } X#endif X else if (ch == 'm') { X if (was_read(art)) { X unmark_as_read(); X#ifdef VERBOSE X IF(verbose) X fputs("\tMarked unread",stdout); X#endif X } X } X else if (ch == 'M') { X#ifdef DELAYMARK X delay_unmark(art); X#ifdef VERBOSE X IF(verbose) X fputs("\tWill return",stdout); X#endif X#else X notincl("M"); X return -1; X#endif X } X else if (ch == '=') { X printf("\t%s",fetchsubj(art,FALSE,FALSE)); X#ifdef VERBOSE X IF(verbose) X ; X ELSE X#endif X putchar('\n') FLUSH; /* ghad! */ X } X else if (ch == 'C') { X#ifdef ASYNC_PARSE X printf("\t%sancelled",(cancel_article() ? "Not c" : "C")); X#else X notincl("C"); X return -1; X#endif X } X else if (ch == '%') { X#ifdef ASYNC_PARSE X char tmpbuf[512]; X X if (one_command) X interp(tmpbuf, (sizeof tmpbuf), cmdlst); X else X cmdlst = dointerp(tmpbuf, (sizeof tmpbuf), cmdlst, ":") - 1; X perform_cnt--; X if (perform(tmpbuf,FALSE)) X return -1; X#else X notincl("%"); X return -1; X#endif X } X else if (index("!&sSwWe|",ch)) { X if (one_command) X strcpy(buf,cmdlst); X else X cmdlst = cpytill(buf,cmdlst,':') - 1; X /* we now have the command in buf */ X if (ch == '!') { X escapade(); X#ifdef VERBOSE X IF(verbose) X fputs("\tShell escaped",stdout); X#endif X } X else if (ch == '&') { X switcheroo(); X#ifdef VERBOSE X IF(verbose) X if (buf[1] && buf[1] != '&') X fputs("\tSwitched",stdout); X#endif X } X else { X putchar('\t'); X save_article(); X#ifdef VERBOSE X IF(verbose) X ; X ELSE X#endif X putchar('\n') FLUSH; X } X } X else { X printf("\t???%s\n",cmdlst); X return -1; X } X#ifdef VERBOSE X fflush(stdout); X#endif X if (one_command) X break; X } X if (toplevel) { X#ifdef VERBOSE X IF(verbose) X putchar('\n') FLUSH; X#endif X } X if( int_count ) { X int_count = 0; X return -1; X } X return 0; X} SHAR_EOF chmod 0660 ngstuff.c || echo "restore of ngstuff.c fails" echo "x - extracting ngstuff.h (Text)" sed 's/^X//' << 'SHAR_EOF' > ngstuff.h && X/* $Header: ngstuff.h,v 4.3.3.1 90/06/20 22:39:07 davison Trn $ X * X * $Log: ngstuff.h,v $ X * Revision 4.3.3.1 90/06/20 22:39:07 davison X * Initial Trn Release X * X * Revision 4.3 85/05/01 11:45:12 lwall X * Baseline for release with 4.3bsd. X * X */ X X#define NN_NORM 0 X#define NN_INP 1 X#define NN_REREAD 2 X#define NN_ASK 3 X XEXT bool one_command INIT(FALSE); /* no ':' processing in perform() */ X Xvoid ngstuff_init(); Xint escapade(); Xint switcheroo(); Xint numnum(); Xint perform(); SHAR_EOF chmod 0660 ngstuff.h || echo "restore of ngstuff.h fails" echo "x - extracting norm.saver.SH (Text)" sed 's/^X//' << 'SHAR_EOF' > norm.saver.SH && Xcase $CONFIG in X '') . ./config.sh ;; Xesac Xecho "Extracting norm.saver (with variable substitutions)" X$spitshell >norm.saver <<!GROK!THIS! X$startsh X# $Header: norm.saver.SH,v 4.3.2.1 89/11/28 00:08:01 sob Locked $ X# X# $Log: norm.saver.SH,v $ X# Revision 4.3.2.1 89/11/28 00:08:01 sob X# Branch for RN/RRN combo. X# X# Revision 4.3.1.2 85/05/20 15:56:24 lwall X# Turned $5 into \$5. X# X# Revision 4.3.1.1 85/05/10 11:36:52 lwall X# Branch for patches. X# X# Revision 4.3 85/05/01 11:45:16 lwall X# Baseline for release with 4.3bsd. X# X# X# Arguments: X# 1 Full name of article (%A) X# 2 Public news spool directory (%P) X# 3 Directory of current newsgroup (%c) X# 4 Article number (%a) X# 5 Where in article to start (%B) X# 6 Newsgroup name (%C) X# 7 Save destination (%b) X# Xexport PATH || (echo "OOPS, this isn't sh. Desperation time. I will feed myself to sh."; sh \$0; kill \$\$) X X( case "\$5" in X 0) $echo "Article \$4 of \$6:" ;; X esac X $tail +\$5c \$1 X $echo "" X $echo "" ) >> \$7 X!GROK!THIS! X$eunicefix norm.saver Xchmod 755 norm.saver SHAR_EOF chmod 0770 norm.saver.SH || echo "restore of norm.saver.SH fails" echo "x - extracting only.c (Text)" sed 's/^X//' << 'SHAR_EOF' > only.c && X/* $Header: only.c,v 4.3.3.1 90/06/20 22:39:13 davison Trn $ X * X * $Log: only.c,v $ X * Revision 4.3.3.1 90/06/20 22:39:13 davison X * Initial Trn Release X * X * Revision 4.3 85/05/01 11:45:21 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "search.h" X#include "util.h" X#include "final.h" X#include "ngsrch.h" X#include "INTERN.h" X#include "only.h" X Xvoid Xonly_init() X{ X ; X} X Xvoid Xsetngtodo(pat) Xchar *pat; X{ X char *s; X X#ifdef ONLY X if (!*pat) X return; X if (maxngtodo < NGMAX) { X ngtodo[maxngtodo] = savestr(pat); X#ifdef SPEEDOVERMEM X#ifndef lint X compextodo[maxngtodo] = (COMPEX*)safemalloc(sizeof(COMPEX)); X#endif /* lint */ X init_compex(compextodo[maxngtodo]); X compile(compextodo[maxngtodo],pat,TRUE,TRUE); X if ((s = ng_comp(compextodo[maxngtodo],pat,TRUE,TRUE)) != Nullch) { X /* compile regular expression */ X printf("\n%s\n",s) FLUSH; X finalize(1); X } X#endif X maxngtodo++; X } X#else X notincl("o"); X#endif X} X X/* if command line list is non-null, is this newsgroup wanted? */ X Xbool Xinlist(ngnam) Xchar *ngnam; X{ X#ifdef ONLY X register int i; X#ifdef SPEEDOVERMEM X X if (maxngtodo == 0) X return TRUE; X for (i=0; i<maxngtodo; i++) { X if (execute(compextodo[i],ngnam)) X return TRUE; X } X return FALSE; X#else X COMPEX ilcompex; X char *s; X X if (maxngtodo == 0) X return TRUE; X init_compex(&ilcompex); X for (i=0; i<maxngtodo; i++) { X if ((s = ng_comp(&ilcompex,ngtodo[i],TRUE,TRUE)) != Nullch) { X /* compile regular expression */ X printf("\n%s\n",s) FLUSH; X finalize(1); X } X X if (execute(&ilcompex,ngnam) != Nullch) { X free_compex(&ilcompex); X return TRUE; X } X } X free_compex(&ilcompex); X return FALSE; X#endif X#else X return TRUE; X#endif X} X X#ifdef ONLY Xvoid Xend_only() X{ X if (maxngtodo) { /* did they specify newsgroup(s) */ X int whicharg; X X#ifdef VERBOSE X IF(verbose) X printf("\nRestriction %s%s removed.\n",ngtodo[0], X maxngtodo > 1 ? ", etc." : nullstr) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nExiting \"only\".\n",stdout) FLUSH; X#endif X for (whicharg = 0; whicharg < maxngtodo; whicharg++) { X free(ngtodo[whicharg]); X#ifdef SPEEDOVERMEM X free_compex(compextodo[whicharg]); X#ifndef lint X free((char*)compextodo[whicharg]); X#endif /* lint */ X#endif X } X maxngtodo = 0; X } X} X#endif SHAR_EOF chmod 0660 only.c || echo "restore of only.c fails" echo "x - extracting only.h (Text)" sed 's/^X//' << 'SHAR_EOF' > only.h && X/* $Header: only.h,v 4.3 85/05/01 11:45:27 lwall Exp $ X * X * $Log: only.h,v $ X * Revision 4.3 85/05/01 11:45:27 lwall X * Baseline for release with 4.3bsd. X * X */ X X#ifndef NBRA X#include "search.h" X#endif X X#ifdef ONLY X EXT char *ngtodo[NGMAX]; /* restrictions in effect */ X# ifdef SPEEDOVERMEM X EXT COMPEX *compextodo[NGMAX]; /* restrictions in compiled form */ X# endif X#endif X XEXT int maxngtodo INIT(0); /* 0 => no restrictions */ X /* >0 => # of entries in ngtodo */ X Xvoid only_init(); Xbool inlist(); /* return TRUE if ngname is in command line list */ X /* or if there was no list */ Xvoid setngtodo(); X#ifdef ONLY X void end_only(); X#endif SHAR_EOF chmod 0660 only.h || echo "restore of only.h fails" echo "x - extracting rcln.c (Text)" sed 's/^X//' << 'SHAR_EOF' > rcln.c && X/* $Header: rcln.c,v 4.3.3.1 90/06/20 22:39:19 davison Trn $ X * X * $Log: rcln.c,v $ X * Revision 4.3.3.1 90/06/20 22:39:19 davison X * Initial Trn Release X * X * Revision 4.3.2.1 90/04/23 00:22:22 sob X * Changed atoi to atol and fixed RCS information. X * X * Revision 4.3.1.2 85/07/23 17:39:08 lwall X * Oops, was freeing a static buf on -c in checkexpired. X * X * Revision 4.3.1.1 85/05/10 11:37:08 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 11:45:36 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "util.h" X#include "rcstuff.h" X#include "ngdata.h" X#include "INTERN.h" X#include "rcln.h" X Xvoid Xrcln_init() X{ X ; X} X X#ifdef CATCHUP Xvoid Xcatch_up(ngx) XNG_NUM ngx; X{ X char tmpbuf[128]; X char *tmpp; SHAR_EOF echo "End of part 10" echo "File rcln.c is continued in part 11" echo "11" > s2_seq_.tmp exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.