/* art.c
*/
/* This software is copyrighted as detailed in the LICENSE file. */
#include "EXTERN.h"
#include "common.h"
#include "list.h"
#include "trn.h"
#include "hash.h"
#include "ngdata.h"
#include "nntpclient.h"
#include "datasrc.h"
#include "addng.h"
#include "nntp.h"
#include "ngstuff.h"
#include "cache.h"
#include "bits.h"
#include "head.h"
#include "help.h"
#include "search.h"
#include "artio.h"
#include "ng.h"
#include "final.h"
#include "artstate.h"
#include "rcstuff.h"
#include "mime.h"
#include "term.h"
#include "env.h"
#include "util.h"
#include "util2.h"
#include "sw.h"
#include "kfile.h"
#include "decode.h"
#include "backpage.h"
#include "intrp.h"
#include "rthread.h"
#include "rt-select.h"
#include "rt-util.h"
#include "rt-wumpus.h"
#include "charsubst.h"
#ifdef SCAN_ART
#include "scanart.h"
#endif
#ifdef SCORE
#include "score.h" /* for sc_lookahead() */
#endif
#ifdef USE_TK
#include "tkstuff.h"
#include "tktree.h"
#endif
#include "color.h"
#include "INTERN.h"
#include "art.h"
#include "artstate.h" /* somebody has to do it */
#define LINE_PTR(pos) (artbuf + (pos) - htype[PAST_HEADER].minpos)
#define LINE_OFFSET(ptr) ((ptr) - artbuf + htype[PAST_HEADER].minpos)
/* page_switch() return values */
#define PS_NORM 0
#define PS_ASK 1
#define PS_RAISE 2
#define PS_TOEND 3
bool special = FALSE; /* is next page special length? */
int slines = 0; /* how long to make page when special */
ART_POS restart = 0; /* if nonzero, the place where last */
/* line left off on line split */
ART_POS alinebeg; /* where in file current line began */
int more_prompt_col; /* non-zero when the more prompt is indented */
ART_LINE isrchline = 0; /* last line to display */
#ifdef INNERSEARCH
COMPEX gcompex; /* in article search pattern */
#endif
bool firstpage; /* is this the 1st page of article? */
bool continuation; /* this line/header is being continued */
void
art_init()
{
#ifdef INNERSEARCH
init_compex(&gcompex);
#endif
}
int
do_article()
{
register char* s;
bool hide_this_line = FALSE; /* hidden header line? */
bool restart_color;
ART_LINE linenum; /* line # on page, 1 origin */
#ifdef ULSMARTS
bool under_lining = FALSE; /* are we underlining a word? */
#endif
register char* bufptr = art_line; /* pointer to input buffer */
register int outpos; /* column position of output */
static char prompt_buf[64]; /* place to hold prompt */
bool notesfiles = FALSE; /* might there be notesfiles junk? */
char oldmode = mode;
register int outputok = TRUE;
#ifdef SUPPORT_NNTP
if (datasrc->flags & DF_REMOTE)
artsize = raw_artsize = nntp_artsize();
else
#endif
{
if (fstat(fileno(artfp),&filestat)) /* get article file stats */
return DA_CLEAN;
if (!S_ISREG(filestat.st_mode))
return DA_NORM;
artsize = raw_artsize = filestat.st_size;
}
#ifdef SCORE
#ifdef USE_TK
if (ttcl_running)
ttcl_set_int("score_curvar",sc_score_art((int)art,TRUE));
#endif
#endif
sprintf(prompt_buf, mousebar_cnt>3? "%%sEnd of art %ld (of %ld) %%s[%%s]"
: "%%sEnd of article %ld (of %ld) %%s-- what next? [%%s]",
(long)art,(long)lastart); /* format prompt string */
prompt = prompt_buf;
int_count = 0; /* interrupt count is 0 */
if ((firstpage = (topline < 0)) != 0) {
parseheader(art);
mime_SetArticle();
clear_artbuf();
seekart(artbuf_seek = htype[PAST_HEADER].minpos);
}
term_scrolled = 0;
#ifdef USE_TK
if (ThreadedGroup && ttk_running)
ttk_draw_tree(curr_artp, 0, 0);
#endif
for (;;) { /* for each page */
if (ThreadedGroup && max_tree_lines)
init_tree(); /* init tree display */
assert(art == openart);
if (do_fseek) {
parseheader(art); /* make sure header is ours */
if (!*artbuf) {
mime_SetArticle();
artbuf_seek = htype[PAST_HEADER].minpos;
}
artpos = vrdary(artline);
if (artpos < 0)
artpos = -artpos; /* labs(), anyone? */
if (firstpage)
artpos = (ART_POS)0;
if (artpos < htype[PAST_HEADER].minpos) {
in_header = SOME_LINE;
seekart(htype[PAST_HEADER].minpos);
seekartbuf(htype[PAST_HEADER].minpos);
}
else {
seekart(artbuf_seek);
seekartbuf(artpos);
}
do_fseek = FALSE;
restart = 0;
}
linenum = 1;
if (!do_hiding)
is_mime = FALSE;
if (firstpage) {
if (firstline) {
interp(art_line,sizeof art_line,firstline);
linenum += tree_puts(art_line,linenum+topline,0);
} else {
ART_NUM i;
int selected, unseen;
selected = (curr_artp->flags & AF_SEL);
unseen = article_unread(art)? 1 : 0;
sprintf(art_line,"%s%s #%ld",ngname,moderated,(long)art);
if (selected_only) {
i = selected_count - (unseen && selected);
sprintf(art_line+strlen(art_line)," (%ld + %ld more)",
(long)i,(long)ngptr->toread - selected_count
- (!selected && unseen));
}
else if ((i = (ART_NUM)(ngptr->toread - unseen)) != 0
|| (!ThreadedGroup && dmcount)) {
sprintf(art_line+strlen(art_line),
" (%ld more)",(long)i);
}
if (!ThreadedGroup && dmcount)
sprintf(art_line+strlen(art_line)-1,
" + %ld Marked to return)",(long)dmcount);
linenum += tree_puts(art_line,linenum+topline,0);
}
start_header(art);
forcelast = FALSE; /* we will have our day in court */
restart = 0;
artline = 0; /* start counting lines */
artpos = 0;
vwtary(artline,artpos); /* remember pos in file */
}
for (restart_color = 1; /* linenum already set */
innersearch? (in_header || innermore())
: special? (linenum < slines)
: (firstpage && !in_header)? (linenum < initlines)
: (linenum < LINES);
linenum++) { /* for each line on page */
if (int_count) { /* exit via interrupt? */
newline(); /* get to left margin */
int_count = 0; /* reset interrupt count */
set_mode(gmode,oldmode);
special = FALSE;
return DA_NORM; /* skip out of loops */
}
if (restart) { /* did not finish last line? */
bufptr = LINE_PTR(restart);/* then start again here */
restart = 0; /* and reset the flag */
continuation = 1;
if (restart_color && do_hiding && !in_header)
maybe_set_color(bufptr, 1);
}
else if (in_header && *(bufptr = headbuf + artpos))
continuation = *bufptr == ' ' || *bufptr == '\t';
else {
if ((bufptr = readartbuf(auto_view_inline)) == NULL) {
special = FALSE;
if (innersearch)
(void)innermore();
break;
}
if (do_hiding && !in_header)
continuation = maybe_set_color(bufptr, restart_color);
else
continuation = 0;
}
alinebeg = artpos; /* remember where we began */
restart_color = 0;
if (in_header) {
hide_this_line = parseline(bufptr,do_hiding,hide_this_line);
if (!in_header) {
linenum += finish_tree(linenum+topline);
end_header();
seekart(artbuf_seek);
}
} else if (notesfiles && do_hiding && !continuation
&& *bufptr == '#' && isupper(bufptr[1])
&& bufptr[2] == ':' ) {
if ((bufptr = readartbuf(auto_view_inline)) == NULL)
break;
for (s = bufptr; *s && *s != '\n' && *s != '!'; s++) ;
if (*s != '!')
readartbuf(auto_view_inline);
mime_SetArticle();
clear_artbuf(); /* exclude notesfiles droppings */
artbuf_seek = htype[PAST_HEADER].minpos = tellart();
hide_this_line = TRUE; /* and do not print either */
notesfiles = FALSE;
}
#ifdef CUSTOMLINES
if (hideline && !continuation && execute(&hide_compex,bufptr))
hide_this_line = TRUE;
#endif
if (in_header && do_hiding && (htype[in_header].flags & HT_MAGIC)) {
switch (in_header) {
case NGS_LINE:
if ((s = index(bufptr,'\n')) != NULL)
*s = '\0';
hide_this_line = (index(bufptr,',') == NULL)
&& strEQ(bufptr+12, ngname);
if (s != NULL)
*s = '\n';
break;
case EXPIR_LINE:
if (!(htype[EXPIR_LINE].flags & HT_HIDE)) {
s = bufptr + htype[EXPIR_LINE].length + 1;
hide_this_line = *s != ' ' || s[1] == '\n';
}
break;
case FROM_LINE:
if ((s = index(bufptr,'\n')) != NULL
&& s-bufptr < sizeof art_line)
safecpy(art_line,bufptr,s-bufptr+1);
else
safecpy(art_line,bufptr,sizeof art_line);
if ((s = extract_name(art_line+6)) != NULL) {
strcpy(art_line+6,s);
bufptr = art_line;
}
break;
#ifdef HAS_STRFTIME
case DATE_LINE:
if (curr_artp->date != -1) {
strncpy(art_line,bufptr,6);
strftime(art_line+6, (sizeof art_line)-6,
getval("LOCALTIMEFMT", LOCALTIMEFMT),
localtime(&curr_artp->date));
bufptr = art_line;
}
break;
#endif
}
}
if (in_header == SUBJ_LINE && do_hiding
&& (htype[SUBJ_LINE].flags & HT_MAGIC)) { /* handle the subject */
s = get_cached_line(artp, SUBJ_LINE, FALSE);
if (s && continuation) {
/* continuation lines were already output */
linenum--;
}
else {
int length = strlen(bufptr+1);
notesfiles = instr(&bufptr[length-10]," - (nf", TRUE)!=NULL;
artline++;
if (!s)
bufptr += (continuation? 0 : 9);
else
bufptr = s;
/* tree_puts(, ,1) underlines subject */
linenum += tree_puts(bufptr,linenum+topline,1)-1;
}
}
else if (hide_this_line && do_hiding) { /* do not print line? */
linenum--; /* compensate for linenum++ */
if (!in_header)
hide_this_line = FALSE;
}
else if (in_header) {
artline++;
linenum += tree_puts(bufptr,linenum+topline,0)-1;
}
else { /* just a normal line */
if (outputok && erase_each_line)
erase_line(0);
if (highlight == artline) { /* this line to be highlit? */
if (marking == STANDOUT) {
#ifdef NOFIREWORKS
if (erase_screen)
no_sofire();
#endif
standout();
}
else {
#ifdef NOFIREWORKS
if (erase_screen)
no_ulfire();
#endif
underline();
carriage_return();
}
if (*bufptr == '\n')
putchar(' ');
}
outputok = !hide_everything; /* registerize it, hopefully */
#ifdef CUSTOMLINES
if (pagestop && !continuation && execute(&page_compex,bufptr))
linenum = 32700;
#endif
for (outpos = 0; outpos < COLS; ) { /* while line has room */
if (AT_NORM_CHAR(bufptr)) { /* normal char? */
#ifdef ULSMARTS
if (*bufptr == '_') {
if (bufptr[1] == '\b') {
if (outputok && !under_lining
&& highlight != artline) {
under_lining++;
if (UG) {
if (bufptr != buf && bufptr[-1]==' ') {
outpos--;
backspace();
}
}
underline();
}
bufptr += 2;
}
}
else {
if (under_lining) {
under_lining = 0;
un_underline();
if (UG) {
outpos++;
if (*bufptr == ' ')
goto skip_put;
}
}
}
#endif
/* handle rot-13 if wanted */
if (rotate && !in_header && isalpha(*bufptr)) {
if (outputok) {
if ((*bufptr & 31) <= 13)
putchar(*bufptr+13);
else
putchar(*bufptr-13);
}
outpos++;
}
else {
#ifdef CHARSUBST
register int i;
i = putsubstchar(*bufptr, COLS - outpos, outputok);
if (i < 0) {
outpos += -i - 1;
break;
}
outpos += i;
#else
if (outputok)
putchar(*bufptr);
outpos++;
#endif /* CHARSUBST */
}
if (*UC && ((highlight==artline && marking == STANDOUT)
#ifdef ULSMARTS
|| under_lining
#endif
)) {
backspace();
underchar();
}
skip_put:
bufptr++;
}
else if (AT_NL(*bufptr) || !*bufptr) { /* newline? */
#ifdef ULSMARTS
if (under_lining) {
under_lining = 0;
un_underline();
}
#endif
#ifdef DEBUG
if (debug & DEB_INNERSRCH && outpos < COLS - 6) {
standout();
printf("%4d",artline);
un_standout();
}
#endif
if (outputok)
newline();
restart = 0;
outpos = 1000; /* signal normal \n */
}
else if (*bufptr == '\t') { /* tab? */
int incpos = 8 - outpos % 8;
if (outputok) {
if (GT)
putchar(*bufptr);
else
while (incpos--) putchar(' ');
}
bufptr++;
outpos += 8 - outpos % 8;
}
else if (*bufptr == '\f') { /* form feed? */
if (outpos+2 > COLS)
break;
if (outputok)
fputs("^L",stdout);
if (bufptr == LINE_PTR(alinebeg) && highlight != artline)
linenum = 32700;
/* how is that for a magic number? */
bufptr++;
outpos += 2;
}
else { /* other control char */
if (dont_filter_control) {
if (outputok)
putchar(*bufptr);
outpos++;
}
else if (*bufptr != '\r' || bufptr[1] != '\n') {
if (outpos+2 > COLS)
break;
if (outputok) {
putchar('^');
if (highlight == artline && *UC
&& marking == STANDOUT) {
backspace();
underchar();
putchar((*bufptr & 0x7F) ^ 0x40);
backspace();
underchar();
}
else
putchar((*bufptr & 0x7F) ^ 0x40);
}
outpos += 2;
}
bufptr++;
}
} /* end of column loop */
if (outpos < 1000) { /* did line overflow? */
restart = LINE_OFFSET(bufptr);/* restart here next time */
if (outputok) {
if (!AM || XN || outpos < COLS)
newline();
else
term_line++;
}
if (AT_NL(*bufptr)) /* skip the newline */
restart = 0;
}
/* handle normal end of output line formalities */
if (highlight == artline) {
/* were we highlighting line? */
if (marking == STANDOUT)
un_standout();
else
un_underline();
carriage_return();
highlight = -1; /* no more we are */
/* in case terminal highlighted rest of line earlier */
/* when we did an eol with highlight turned on: */
if (erase_each_line)
erase_eol();
}
artline++; /* count the line just printed */
if (artline - LINES + 1 > topline)
/* did we just scroll top line off? */
topline = artline - LINES + 1;
/* then recompute top line # */
}
/* determine actual position in file */
if (restart) /* stranded somewhere in the buffer? */
artpos += restart - alinebeg;
else if (in_header)
artpos = index(headbuf+artpos,'\n') - headbuf + 1;
else
artpos = artbuf_pos + htype[PAST_HEADER].minpos;
vwtary(artline,artpos); /* remember pos in file */
} /* end of line loop */
#ifdef INNERSEARCH
innersearch = 0;
if (hide_everything) {
*buf = hide_everything;
hide_everything = 0;
goto fake_command;
}
#endif
if (linenum >= 32700) /* did last line have formfeed? */
vwtary(artline-1,-vrdary(artline-1));
/* remember by negating pos in file */
special = FALSE; /* end of page, so reset page length */
firstpage = FALSE; /* and say it is not 1st time thru */
highlight = -1;
/* extra loop bombout */
#ifdef SUPPORT_NNTP
if (artsize < 0 && (raw_artsize = nntp_artsize()) >= 0)
artsize = raw_artsize-artbuf_seek+artbuf_len+htype[PAST_HEADER].minpos;
recheck_pager:
if (do_hiding && artbuf_pos == artbuf_len) {
/* If we're filtering we need to figure out if any
* remaining text is going to vanish or not. */
long seekpos = artbuf_pos + htype[PAST_HEADER].minpos;
readartbuf(FALSE);
seekartbuf(seekpos);
}
#endif
if (artpos == artsize) {/* did we just now reach EOF? */
color_default();
set_mode(gmode,oldmode);
return DA_NORM; /* avoid --MORE--(100%) */
}
/* not done with this article, so pretend we are a pager */
reask_pager:
if (term_line >= LINES) {
term_scrolled += term_line - LINES + 1;
term_line = LINES-1;
}
more_prompt_col = term_col;
unflush_output(); /* disable any ^O in effect */
maybe_eol();
color_default();
#ifdef SUPPORT_NNTP
if (artsize < 0)
strcpy(cmd_buf,"?");
else
#endif
sprintf(cmd_buf,"%ld",(long)(artpos*100/artsize));
#ifdef CHARSUBST
sprintf(buf,"%s--MORE--(%s%%)",current_charsubst(),cmd_buf);
#else
sprintf(buf,"--MORE--(%s%%)",cmd_buf);
#endif
outpos = term_col + strlen(buf);
draw_mousebar(COLS - (term_line == LINES-1? outpos+5 : 0), 1);
color_string(COLOR_MORE,buf);
fflush(stdout);
term_col = outpos;
eat_typeahead();
#ifdef DEBUG
if (debug & DEB_CHECKPOINTING) {
printf("(%d %d %d)",checkcount,linenum,artline);
fflush(stdout);
}
#endif
if (checkcount >= docheckwhen && linenum == LINES
&& (artline > 40 || checkcount >= docheckwhen+10)) {
/* while he is reading a whole page */
/* in an article he is interested in */
checkcount = 0;
checkpoint_newsrcs(); /* update all newsrcs */
#ifdef KILLFILES
update_thread_kfile();
#endif
}
cache_until_key();
#ifdef SUPPORT_NNTP
if (artsize < 0 && (raw_artsize = nntp_artsize()) >= 0) {
artsize = raw_artsize-artbuf_seek+artbuf_len+htype[PAST_HEADER].minpos;
goto_xy(more_prompt_col,term_line);
goto recheck_pager;
}
#endif
set_mode(gmode,'p');
getcmd(buf);
if (errno) {
if (LINES < 100 && !int_count)
*buf = '\f';/* on CONT fake up refresh */
else {
*buf = 'q'; /* on INTR or paper just quit */
}
}
erase_line(erase_screen && erase_each_line);
fake_command: /* used by innersearch */
color_default();
output_chase_phrase = TRUE;
/* parse and process pager command */
if (mousebar_cnt)
clear_rest();
switch (page_switch()) {
case PS_ASK: /* reprompt "--MORE--..." */
goto reask_pager;
case PS_RAISE: /* reparse on article level */
set_mode(gmode,oldmode);
return DA_RAISE;
case PS_TOEND: /* fast pager loop exit */
set_mode(gmode,oldmode);
return DA_TOEND;
case PS_NORM: /* display more article */
break;
}
} /* end of page loop */
}
int
maybe_set_color(cp, backsearch)
char* cp;
bool_int backsearch;
{
register char ch = (cp == artbuf || cp == art_line? 0 : cp[-1]);
if (ch == '\001')
color_object(COLOR_MIMEDESC, 0);
else if (ch == '\002')
color_object(COLOR_MIMESEP, 0);
else if (ch == WRAPPED_NL) {
if (backsearch) {
while (cp > artbuf && cp[-1] != '\n') cp--;
maybe_set_color(cp, 0);
}
return 1;
}
else {
while (*cp == ' ' || *cp == '\t') cp++;
if (index(">}]#!:|", *cp))
color_object(COLOR_CITEDTEXT, 0);
else
color_object(COLOR_BODYTEXT, 0);
}
return 0;
}
/* process pager commands */
int
page_switch()
{
register char* s;
switch (*buf) {
case '!': /* shell escape */
escapade();
return PS_ASK;
#ifdef INNERSEARCH
case Ctl('i'): {
ART_LINE i = artline;
ART_POS pos;
gline = 3;
s = LINE_PTR(alinebeg);
while (AT_NL(*s) && i >= topline) {
pos = vrdary(--i);
if (pos < 0)
pos = -pos;
if (pos < htype[PAST_HEADER].minpos)
break;
seekartbuf(pos);
if ((s = readartbuf(FALSE)) == NULL) {
s = LINE_PTR(alinebeg);
break;
}
}
sprintf(cmd_buf,"^[^%c\n]",*s);
compile(&gcompex,cmd_buf,TRUE,TRUE);
goto caseG;
}
case Ctl('g'):
gline = 3;
compile(&gcompex,"^Subject:",TRUE,TRUE);
goto caseG;
case 'g': /* in-article search */
if (!finish_command(FALSE))/* get rest of command */
return PS_ASK;
s = buf+1;
if (isspace(*s)) s++;
if ((s = compile(&gcompex,s,TRUE,TRUE)) != NULL) {
/* compile regular expression */
printf("\n%s\n",s) FLUSH;
termdown(2);
return PS_ASK;
}
erase_line(0); /* erase the prompt */
/* FALL THROUGH */
caseG:
case 'G': {
ART_POS start_where;
bool success;
char* nlptr;
char ch;
if (gline < 0 || gline > LINES-2)
gline = LINES-2;
#ifdef DEBUG
if (debug & DEB_INNERSRCH) {
printf("Start here? %d >=? %d\n",topline + gline + 1,artline)
FLUSH;
termdown(1);
}
#endif
if (*buf == Ctl('i') || topline+gline+1 >= artline)
start_where = artpos;
/* in case we had a line wrap */
else {
start_where = vrdary(topline+gline+1);
if (start_where < 0)
start_where = -start_where;
}
if (start_where < htype[PAST_HEADER].minpos)
start_where = htype[PAST_HEADER].minpos;
seekartbuf(start_where);
innerlight = 0;
innersearch = 0; /* assume not found */
while ((s = readartbuf(FALSE)) != NULL) {
if ((nlptr = index(s,'\n')) != NULL) {
ch = *++nlptr;
*nlptr = '\0';
}
#ifdef DEBUG
if (debug & DEB_INNERSRCH)
printf("Test %s\n",s) FLUSH;
#endif
success = execute(&gcompex,s) != NULL;
if (nlptr)
*nlptr = ch;
if (success) {
innersearch = artbuf_pos + htype[PAST_HEADER].minpos;
break;
}
}
if (!innersearch) {
seekartbuf(artpos);
fputs("(Not found)",stdout) FLUSH;
term_col = 11;
return PS_ASK;
}
#ifdef DEBUG
if (debug & DEB_INNERSRCH) {
printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos)
FLUSH;
termdown(1);
}
#endif
if (innersearch <= artpos) { /* already on page? */
if (innersearch < artpos) {
artline = topline+1;
while (vrdary(artline) < innersearch)
artline++;
}
highlight = artline - 1;
#ifdef DEBUG
if (debug & DEB_INNERSRCH) {
printf("@ %d\n",highlight) FLUSH;
termdown(1);
}
#endif
topline = highlight - gline;
if (topline < -1)
topline = -1;
*buf = '\f'; /* fake up a refresh */
innersearch = 0;
return page_switch();
}
else { /* who knows how many lines it is? */
do_fseek = TRUE;
hide_everything = '\f';
}
return PS_NORM;
}
#else
case 'g': case 'G': case Ctl('g'):
notincl("g");
return PS_ASK;
#endif
case '\n': /* one line down */
case '\r':
special = TRUE;
slines = 2;
return PS_NORM;
case 'X':
rotate = !rotate;
/* FALL THROUGH */
case 'l':
case '\f': /* refresh screen */
refresh_screen:
#ifdef DEBUG
if (debug & DEB_INNERSRCH) {
printf("Topline = %d",topline) FLUSH;
fgets(buf, sizeof buf, stdin);
}
#endif
clear();
do_fseek = TRUE;
artline = topline;
if (artline < 0)
artline = 0;
firstpage = (topline < 0);
return PS_NORM;
#ifdef INNERSEARCH
case Ctl('e'):
#ifdef SUPPORT_NNTP
if (artsize < 0) {
nntp_finishbody(FB_OUTPUT);
raw_artsize = nntp_artsize();
artsize = raw_artsize-artbuf_seek+artbuf_len+htype[PAST_HEADER].minpos;
}
#endif
if (do_hiding) {
seekartbuf(artsize);
seekartbuf(artpos);
}
topline = artline;
innerlight = artline - 1;
innersearch = artsize;
gline = 0;
hide_everything = 'b';
return PS_NORM;
#endif
case 'B': /* one line up */
if (topline < 0)
break;
if (*IL && *HO) {
ART_POS pos;
home_cursor();
insert_line();
carriage_return();
pos = vrdary(topline-1);
if (pos < 0)
pos = -pos;
if (pos >= htype[PAST_HEADER].minpos) {
seekartbuf(pos);
if ((s = readartbuf(FALSE)) != NULL) {
artpos = vrdary(topline);
if (artpos < 0)
artpos = -artpos;
maybe_set_color(s, 1);
for (pos = artpos - pos; pos-- && !AT_NL(*s); s++)
putchar(*s);
color_default();
putchar('\n') FLUSH;
topline--;
artpos = vrdary(--artline);
if (artpos < 0)
artpos = -artpos;
seekartbuf(artpos);
alinebeg = vrdary(artline-1);
if (alinebeg < 0)
alinebeg = -alinebeg;
goto_xy(0,artline-topline);
erase_line(0);
return PS_ASK;
}
}
}
/* FALL THROUGH */
case 'b':
case Ctl('b'): { /* back up a page */
ART_LINE target;
if (erase_each_line)
home_cursor();
else
clear();
do_fseek = TRUE; /* reposition article file */
if (*buf == 'B')
target = topline - 1;
else {
target = topline - (LINES - 2);
if (marking && (marking_areas & BACKPAGE_MARKING))
highlight = topline;
}
artline = topline;
if (artline >= 0) do {
artline--;
} while(artline >= 0 && artline > target && vrdary(artline-1) >= 0);
topline = artline; /* remember top line of screen */
/* (line # within article file) */
if (artline < 0)
artline = 0;
firstpage = (topline < 0);
return PS_NORM;
}
case 'H': /* help */
help_page();
return PS_ASK;
case 't': /* output thread data */
page_line = 1;
entire_tree(curr_artp);
return PS_ASK;
case '_':
if (!finish_dblchar())
return PS_ASK;
switch (buf[1] & 0177) {
#ifdef CHARSUBST
case 'C':
if (!*(++charsubst))
charsubst = charsets;
goto refresh_screen;
#endif
default:
break;
}
goto leave_pager;
case '\0': /* treat break as 'n' */
*buf = 'n';
/* FALL THROUGH */
case 'a': case 'A':
case 'e':
case 'k': case 'K': case 'J':
case 'n': case 'N': case Ctl('n'):
case 'F':
case 'R':
case 's': case 'S':
case 'T':
case 'u':
case 'w': case 'W':
case '|':
mark_as_read(artp); /* mark article as read */
/* FALL THROUGH */
case 'U': case ',':
case '<': case '>':
case '[': case ']':
case '{': case '}':
case '(': case ')':
case ':':
case '+':
case Ctl('v'): /* verify crypto signature */
#ifdef SCAN_ART
case ';': /* enter article scan mode */
#endif
#ifdef SCORE
case '"': /* append to local scorefile */
case '\'': /* score command */
#endif
case '#':
case '$':
case '&':
case '-':
case '.':
case '/':
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case '=':
case '?':
case 'c': case 'C':
#ifdef DEBUG
case 'D':
#endif
case 'f': case Ctl('f'):
case 'h':
case 'j':
case Ctl('k'):
case 'm': case 'M':
case 'p': case 'P': case Ctl('p'):
case '`': case 'Q':
case 'r': case Ctl('r'):
case 'v':
case 'x': case Ctl('x'):
case 'Y':
case 'z': case 'Z':
case '^': case Ctl('^'):
case '\b': case '\177':
leave_pager:
reread = FALSE;
if (index("nNpP\016\020",*buf) == NULL
&& index("wWsSe:!&|/?123456789.",*buf) != NULL) {
setdfltcmd();
color_object(COLOR_CMD, 1);
interpsearch(cmd_buf, sizeof cmd_buf, mailcall, buf);
printf(prompt,cmd_buf,
#ifdef CHARSUBST
current_charsubst(),
#else
nullstr,
#endif
dfltcmd); /* print prompt, whatever it is */
color_pop(); /* of COLOR_CMD */
putchar(' ');
fflush(stdout);
}
return PS_RAISE; /* and pretend we were at end */
case 'd': /* half page */
case Ctl('d'):
special = TRUE;
slines = LINES / 2 + 1;
/* no divide-by-zero, thank you */
if (LINES > 2 && (LINES & 1) && artline % (LINES-2) >= LINES/2 - 1)
slines++;
goto go_forward;
case 'y':
case ' ': /* continue current article */
if (erase_screen) { /* -e? */
if (erase_each_line)
home_cursor();
else
clear(); /* clear screen */
fflush(stdout);
}
else {
special = TRUE;
slines = LINES;
}
go_forward:
if (*LINE_PTR(alinebeg) != '\f'
#ifdef CUSTOMLINES
&& (!pagestop || continuation || !execute(&page_compex,LINE_PTR(alinebeg)))
#endif
) {
if (!special
|| (marking && (*buf!='d' || (marking_areas&HALFPAGE_MARKING)))) {
restart = alinebeg;
artline--; /* restart this line */
artpos = alinebeg;
if (special)
up_line();
else
topline = artline;
if (marking)
highlight = artline;
}
else
slines--;
}
return PS_NORM;
case 'i':
if ((auto_view_inline = !auto_view_inline) != 0)
first_view = 0;
printf("\nAuto-View inlined mime is %s\n", auto_view_inline? "on" : "off");
termdown(2);
break;
case 'q': /* quit this article? */
return PS_TOEND;
default:
fputs(hforhelp,stdout) FLUSH;
termdown(1);
settle_down();
return PS_ASK;
}
return PS_ASK;
}
bool
innermore()
{
if (artpos < innersearch) { /* not even on page yet? */
#ifdef DEBUG
if (debug & DEB_INNERSRCH)
printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch)
FLUSH;
#endif
return TRUE;
}
if (artpos == innersearch) { /* just got onto page? */
isrchline = artline; /* remember first line after */
if (innerlight)
highlight = innerlight;
else
highlight = artline - 1;
#ifdef DEBUG
if (debug & DEB_INNERSRCH) {
printf("There it is %ld = %ld, %d @ %d\n",(long)artpos,
(long)innersearch,hide_everything,highlight) FLUSH;
termdown(1);
}
#endif
if (hide_everything) { /* forced refresh? */
topline = artline - gline - 1;
if (topline < -1)
topline = -1;
return FALSE; /* let refresh do it all */
}
}
#ifdef DEBUG
if (debug & DEB_INNERSRCH) {
printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline)
FLUSH;
termdown(1);
}
#endif
if (artline < isrchline + gline)
return TRUE;
return FALSE;
}
/* On click:
* btn = 0 (left), 1 (middle), or 2 (right) + 4 if double-clicked;
* x = 0 to COLS-1; y = 0 to LINES-1;
* btn_clk = 0, 1, or 2 (no 4); x_clk = x; y_clk = y.
* On release:
* btn = 3; x = released x; y = released y;
* btn_clk = click's 0, 1, or 2; x_clk = clicked x; y_clk = clicked y.
*/
void
pager_mouse(btn, x,y, btn_clk, x_clk,y_clk)
int btn;
int x, y;
int btn_clk;
int x_clk, y_clk;
{
ARTICLE* ap;
if (check_mousebar(btn, x,y, btn_clk, x_clk,y_clk))
return;
if (btn != 3)
return;
ap = get_tree_artp(x_clk,y_clk+topline+1+term_scrolled);
if (ap && ap != get_tree_artp(x,y+topline+1+term_scrolled))
return;
switch (btn_clk) {
case 0:
if (ap) {
if (ap == artp)
return;
artp = ap;
art = article_num(ap);
reread = TRUE;
pushchar(Ctl('r'));
}
else if (y > LINES/2)
pushchar(' ');
else if (topline != -1)
pushchar('b');
break;
case 1:
if (ap) {
select_subthread(ap, 0);
special = TRUE;
slines = 1;
pushchar(Ctl('r'));
}
else if (y > LINES/2)
pushchar('\n');
else if (topline != -1)
pushchar('B');
break;
case 2:
if (ap) {
kill_subthread(ap, 0);
special = TRUE;
slines = 1;
pushchar(Ctl('r'));
}
else if (y > LINES/2)
pushchar('n');
else
pushchar(Ctl('r'));
break;
}
}
syntax highlighted by Code2HTML, v. 0.9.1