/* $Header: ng.c,v 4.3.1.6 85/09/10 11:03:42 lwall Exp $
* Revision 4.3.1.6 85/09/10 11:03:42 lwall
* Improved %m in in_char().
* Revision 4.3.1.5 85/09/05 12:34:37 lwall
* Catchup command could make unread article count too big.
* Revision 4.3.1.4 85/07/23 18:19:46 lwall
* Added MAILCALL environment variable.
* Revision 4.3.1.3 85/05/16 16:48:09 lwall
* Revision 4.3.1.2 85/05/13 09:29:28 lwall
* Added CUSTOMLINES option.
* Revision 4.3.1.1 85/05/10 11:36:00 lwall
* Revision 4.3 85/05/01 11:43:43 lwall
* Baseline for release with 4.3bsd.
#include "artstate.h" /* somebody has to do it */
/* art_switch() return values */
ART_NUM recent_art
= 0; /* previous article # for '-' command */
ART_NUM curr_art
= 0; /* current article # */
init_compex(&hide_compex
);
init_compex(&page_compex
);
/* do newsgroup on line ng with name ngname */
/* assumes that we are chdir'ed to SPOOL, and assures that that is
* still true upon return, but chdirs to SPOOL/ngname in between
* If you can understand this routine, you understand most of the program.
* The basic structure is:
* for each desired article
* if we need another line from file
* for each column on page
* (Actually, the pager is in another routine.)
* The chief problem is deciding what is meant by "desired". Most of
* the messiness of this routine is due to the fact that people want
* to do unstructured things all the time. I have used a few judicious
* goto's where I thought it improved readability. The rest of the messiness
* arises from trying to be both space and time efficient. Have fun.
do_newsgroup(start_command
)
char *start_command
; /* command to fake up first */
register long i
; /* scratch */
int skipstate
; /* how many unavailable articles */
/* have we skipped already? */
char *whatnext
= "%sWhat next? [%s]";
srchahead
= (scanon
&& ((ART_NUM
)toread
[ng
]) >= scanon
? -1 : 0);
recent_art
= curr_art
= 0;
if (eaccess(ngdir
,5)) { /* directory read protected? */
printf("\nNewsgroup %s does not have a spool directory!\n",
printf("\nNo spool for %s!\n",ngname
) FLUSH
;
printf("\nNewsgroup %s is not currently accessible.\n",
printf("\n%s not readable.\n",ngname
) FLUSH
;
toread
[ng
] = TR_NONE
; /* make this newsgroup invisible */
/* chdir to newsgroup subdirectory */
printf(nocd
,ngdir
) FLUSH
;
subj_list
= Null(char **); /* no subject list till needed */
/* initialize control bitmap */
/* FROM HERE ON, RETURN THRU CLEANUP OR WE ARE SCREWED */
in_ng
= TRUE
; /* tell the world we are here */
forcelast
= TRUE
; /* if 0 unread, do not bomb out */
/* remember what newsgroup we were in for sake of posterity */
/* see if there are any special searches to do */
kill_unwanted(firstart
,"Looking for articles to kill...\n\n",TRUE
);
kill_unwanted(firstart
,"Killing...\n\n",TRUE
);
/* do they want a special top line? */
firstline
= getval("FIRSTLINE",Nullch
);
/* custom line suppression, custom page ending */
if (hideline
= getval("HIDELINE",Nullch
))
compile(&hide_compex
,hideline
,TRUE
,TRUE
);
if (pagestop
= getval("PAGESTOP",Nullch
))
compile(&page_compex
,pagestop
,TRUE
,TRUE
);
/* now read each unread article */
rc_changed
= doing_ng
= TRUE
; /* enter the twilight zone */
skipstate
= 0; /* we have not skipped anything (yet) */
checkcount
= 0; /* do not checkpoint for a while */
do_fseek
= FALSE
; /* start 1st article at top */
art
=firstart
; /* init the for loop below */
for (; art
<=lastart
+1; ) { /* for each article */
/* do we need to "grow" the newsgroup? */
if (art
> lastart
|| forcegrow
)
check_first(art
); /* make sure firstart is still 1st */
if (start_command
) { /* fake up an initial command? */
strcpy(buf
,start_command
);
if (art
>lastart
) { /* are we off the end still? */
ART_NUM ucount
= 0; /* count of unread articles left */
for (i
=firstart
; i
<=lastart
; i
++)
ucount
++; /* count the unread articles */
if (debug
&& ((ART_NUM
)toread
[ng
]) != ucount
)
printf("(toread=%ld sb %ld)",(long)toread
[ng
],(long)ucount
)
toread
[ng
] = (ART_UNREAD
)ucount
; /* this is perhaps pointless */
art
= lastart
+ 1; /* keep bitmap references sane */
/* remember last article # (for '-') */
curr_art
= art
; /* remember this article # */
clear(); /* clear the screen */
fputs("\n\n",stdout
) FLUSH
;
printf("End of newsgroup %s.",ngname
);
/* print pseudo-article */
printf("End of %s",ngname
);
printf(" (%ld article%s still unread)",
(long)ucount
,ucount
==1?nullstr
:"s");
goto cleanup
; /* actually exit newsgroup */
srchahead
= 0; /* no more subject search mode */
fputs("\n\n",stdout
) FLUSH
;
skipstate
= 0; /* back to none skipped */
else if (!reread
&& was_read(art
)) {
/* has this article been read? */
art
++; /* then skip it */
(!reread
&& !was_read(art
)
&& artopen(art
) == Nullfp
) { /* never read it, & cannot find it? */
if (errno
!= ENOENT
) { /* has it not been deleted? */
printf("\n(Article %ld exists but is unreadable.)\n",
printf("\n(%ld unreadable.)\n",(long)art
) FLUSH
;
fputs("Skipping unavailable article",stdout
);
fputs("Skipping",stdout
);
for (i
= just_a_sec
/3; i
; --i
)
if (! (newart
=getngmin(".",art
)))
for (i
=art
; i
<newart
; i
++)
oneless(art
); /* mark deleted as read */
art
++; /* try next article */
else { /* we have a real live article */
skipstate
= 0; /* back to none skipped */
/* remember last article # (for '-') */
curr_art
= art
; /* remember this article # */
if (!do_fseek
) { /* starting at top of article? */
artline
= 0; /* start at the beginning */
topline
= -1; /* and remember top line of screen */
/* (line # within article file) */
clear(); /* clear screen */
artopen(art
); /* make sure article file is open */
if (artfp
== Nullfp
) { /* could not find article? */
printf("Article %ld of %s is not available.\n\n",
else { /* found it, so print it */
case DA_CLEAN
: /* quit newsgroup */
case DA_TOEND
: /* do not mark as read */
case DA_RAISE
: /* reparse command at end of art */
case DA_NORM
: /* normal end of article */
mark_as_read(art
); /* mark current article as read */
/* if these gotos bother you, think of this as a little state machine */
if (erase_screen
&& can_home_clear
) /* PWP was here */
unflush_output(); /* disable any ^O in effect */
standout(); /* enter standout mode */
printf(prompt
,mailcall
,dfltcmd
);/* print prompt, whatever it is */
un_standout(); /* leave standout mode */
look_ahead(); /* see what we can do in advance */
collect_subjects(); /* loads subject cache until */
if (errno
|| *buf
== '\f') {
if (LINES
< 100 && !int_count
)
*buf
= '\f'; /* on CONT fake up refresh */
putchar('\n') FLUSH
; /* but only on a crt */
/* parse and process article level command */
case AS_INP
: /* multichar command rubbed out */
case AS_ASK
: /* reprompt "End of article..." */
case AS_CLEAN
: /* exit newsgroup */
case AS_NORM
: /* display article art */
} /* end of article selection loop */
/* shut down newsgroup */
kill_unwanted(firstart
,"\nCleaning up...\n\n",FALSE
);
/* do cleanup from KILL file, if any */
in_ng
= FALSE
; /* leave newsgroup state */
if (artfp
!= Nullfp
) { /* article still open? */
fclose(artfp
); /* close it */
artfp
= Nullfp
; /* and tell the world */
yankback(); /* do a Y command */
restore_ng(); /* reconstitute .newsrc line */
doing_ng
= FALSE
; /* tell sig_catcher to cool it */
free(ctlarea
); /* return the control area */
for (i
=OFFSET(lastart
); i
>=0; --i
)
write_rc(); /* and update .newsrc */
rc_changed
= FALSE
; /* tell sig_catcher it is ok */
printf(nocd
,spool
) FLUSH
;
/* decide what to do at the end of an article */
case 'p': /* find previous unread article */
} while (was_read(art
) || artopen(art
) == Nullfp
);
case 'P': /* goto previous article */
There are no articles prior to this one.\n\
fputs("\nNo previous articles\n",stdout
) FLUSH
;
srchahead
= -(srchahead
!= 0);
case 'n': /* find next unread article? */
else if (scanon
&& srchahead
) {
case 'N': /* goto next article */
case '1': case '2': case '3': /* goto specified article */
case '4': case '5': case '6': /* or do something with a range */
case '7': case '8': case '9': case '.':
case Ctl('n'): case Ctl('p'):
{ /* search for article by pattern */
reread
= TRUE
; /* assume this */
switch (art_search(buf
, (sizeof buf
), TRUE
)) {
printf("\n(Interrupted at article %ld)\n",(long)art
) FLUSH
;
printf("\n(Intr at %ld)\n",(long)art
) FLUSH
;
/* restore to current article */
fputs("done\n",stdout
) FLUSH
;
pad(just_a_sec
/3); /* 1/3 second */
fputs("\n\n\n\nSubject not found.\n",stdout
) FLUSH
;
pad(just_a_sec
/3); /* 1/3 second */
fputs("\n\n\n\nNot found.\n",stdout
) FLUSH
;
art
= curr_art
; /* restore to current article */
if (cmd
== Ctl('n') || cmd
== Ctl('p'))
case 'u': /* unsubscribe from this newsgroup? */
printf("\nArticle %ld will return.\n",(long)art
) FLUSH
;
printf("\nArticle %ld marked as still unread.\n",(long)art
) FLUSH
;
in_char("\nDo you really want to mark everything as read? [yn] ",
in_char("\nReally? [ynh] ", 'C');
Type y or SP to mark all articles as read.\n\
Type n to leave articles marked as they are.\n\
Type u to mark everything read and unsubscribe.\n\
y or SP to mark all read.\n\
u to mark all and unsubscribe.\n\
else if (*buf
== 'n' || *buf
== 'q') {
else if (*buf
!= 'y' && *buf
!= 'u') {
fputs(hforhelp
,stdout
) FLUSH
;
for (i
= firstart
; i
<= lastart
; i
++) {
oneless(i
); /* mark as read */
case 'q': /* go back up to newsgroup level? */
if ((cmd
= help_art()) > 0)
if (switcheroo()) /* get rest of command */
return AS_INP
; /* if rubbed out, try something else */
printf("\nThe last article is %ld.\n",(long)lastart
) FLUSH
;
printf("\n%ld\n",(long)lastart
) FLUSH
;
char *subjline
= getval("SUBJLINE",Nullch
);
fetchsubj(art
,TRUE
,FALSE
);
for (i
=firstart
; i
<=lastart
&& !int_count
; i
++) {
(subj_list
[OFFSET(i
)] != Nullch
|| fetchsubj(i
,FALSE
,FALSE
)) &&
*subj_list
[OFFSET(i
)] ) {
sprintf(tmpbuf
,"%5ld ", i
);
interp(tmpbuf
+ 6, (sizeof tmpbuf
) - 6, subjline
);
safecpy(tmpbuf
+ 6, subj_list
[OFFSET(i
)],
if (cmd
= print_lines(tmpbuf
,NOMARKING
)) {
if (!was_read(i
) && (s
= fetchsubj(i
,FALSE
,FALSE
)) && *s
) {
sprintf(tmpbuf
,"%5ld ", i
);
if (subjline
) { /* probably fetches it again! */
interp(tmpbuf
+ 6, (sizeof tmpbuf
) - 6, subjline
);
safecpy(tmpbuf
+ 6, s
, (sizeof tmpbuf
) - 6);
if (cmd
= print_lines(tmpbuf
,NOMARKING
)) {
#if defined(CACHESUBJ) && defined(DEBUGGING)
printf("\nFirst article: %ld\n",(long)firstart
) FLUSH
;
fetchsubj(art
,TRUE
,FALSE
);
if (subj_list
!= Null(char **)) {
for (i
=1; i
<=lastart
&& !int_count
; i
++) {
if (subj_list
[OFFSET(i
)])
i
, (was_read(i
)?'y':'n'), subj_list
[OFFSET(i
)]) FLUSH
;
rotate
= (*buf
==Ctl('x'));
case 'l': case Ctl('l'): /* refresh screen */
case 'b': case Ctl('b'): /* back up a page */
target
= topline
- (LINES
- 2);
} while (artline
>= 0 && artline
> target
&&
case '!': /* shell escape */
case 'f': { /* followup command */
forcegrow
= TRUE
; /* recalculate lastart */
case 's': case 'S': /* save command */
if (save_article() == SAVE_ABORT
)
case 'Y': /* yank back M articles */
art
= firstart
; /* from the beginning */
return AS_NORM
; /* pretend nothing happened */
fputs(badcr
,stdout
) FLUSH
;
printf("\n%s",hforhelp
) FLUSH
;
/* see if there is any mail */
char *mailfile
= filexp(getval("MAILFILE",MAILFILE
));
if (stat(mailfile
,&filestat
) < 0 || !filestat
.st_size
|| filestat
.st_atime
> filestat
.st_mtime
)
mailcall
= getval("MAILCALL","(Mail) ");
mailcount
%= 10; /* check every 10 articles */