/* ngstuff.c
*/
/* This software is copyrighted as detailed in the LICENSE file. */
#include "EXTERN.h"
#include "common.h"
#include "list.h"
#include "term.h"
#include "util.h"
#include "util2.h"
#include "hash.h"
#include "cache.h"
#include "bits.h"
#include "ngdata.h"
#include "nntpclient.h"
#include "datasrc.h"
#include "nntp.h"
#include "ng.h"
#include "intrp.h"
#include "head.h"
#include "final.h"
#include "sw.h"
#include "rthread.h"
#include "rt-select.h"
#include "rt-wumpus.h"
#include "rt-util.h"
#include "trn.h"
#include "rcln.h"
#include "rcstuff.h"
#include "respond.h"
#include "kfile.h"
#include "decode.h"
#include "addng.h"
#include "opt.h"
#include "only.h"
#include "INTERN.h"
#include "ngstuff.h"
void
ngstuff_init()
{
;
}
/* do a shell escape */
int
escapade()
{
register char* s;
bool interactive = (buf[1] == FINISHCMD);
bool docd;
char whereiam[1024];
if (!finish_command(interactive)) /* get remainder of command */
return -1;
s = buf+1;
docd = *s != '!';
if (!docd) {
s++;
}
else {
trn_getwd(whereiam, sizeof(whereiam));
if (chdir(cwd)) {
printf(nocd,cwd) FLUSH;
sig_catcher(0);
}
}
while (*s == ' ') s++;
/* skip leading spaces */
interp(cmd_buf, (sizeof cmd_buf), s);/* interpret any % escapes */
resetty(); /* make sure tty is friendly */
doshell((char*)NULL,cmd_buf); /* invoke the shell */
noecho(); /* and make terminal */
crmode(); /* unfriendly again */
if (docd) {
if (chdir(whereiam)) {
printf(nocd,whereiam) FLUSH;
sig_catcher(0);
}
}
#ifdef MAILCALL
mailcount = 0; /* force recheck */
#endif
return 0;
}
/* process & command */
int
switcheroo()
{
if (!finish_command(TRUE)) /* get rest of command */
return -1; /* if rubbed out, try something else */
if (!buf[1]) {
char* prior_savedir = savedir;
if (option_sel_ilock) {
buf[1] = '\0';
return 0;
}
option_sel_ilock = TRUE;
if (gmode != 's' || sel_mode != SM_OPTIONS)/*$$*/
option_selector();
option_sel_ilock = FALSE;
if (savedir != prior_savedir)
cwd_check();
buf[1] = '\0';
}
else if (buf[1] == '&') {
if (!buf[2]) {
page_start();
show_macros();
}
else {
char tmpbuf[LBUFLEN];
register char* s;
for (s=buf+2; isspace(*s); s++);
mac_line(s,tmpbuf,(sizeof tmpbuf));
}
}
else {
bool docd = (instr(buf,"-d", TRUE) != NULL);
char whereami[1024];
char tmpbuf[LBUFLEN+16];
if (docd)
trn_getwd(whereami, sizeof(whereami));
if (buf[1] == '-' || buf[1] == '+') {
strcpy(tmpbuf,buf+1);
sw_list(tmpbuf);
}
else {
sprintf(tmpbuf,"[options]\n%s\n",buf+1);
prep_ini_data(tmpbuf,"'&' input");
parse_ini_section(tmpbuf+10,options_ini);
set_options(INI_VALUES(options_ini));
}
if (docd) {
cwd_check();
if (chdir(whereami)) { /* -d does chdirs */
printf(nocd,whereami) FLUSH;
sig_catcher(0);
}
}
}
return 0;
}
/* process range commands */
int
numnum()
{
ART_NUM min, max;
char* cmdlst = NULL;
register char* s;
register char* c;
ART_NUM oldart = art;
char tmpbuf[LBUFLEN];
bool output_level = (!use_threads && gmode != 's');
bool justone = TRUE; /* assume only one article */
if (!finish_command(TRUE)) /* get rest of command */
return NN_INP;
if (lastart < 1) {
errormsg("No articles");
return NN_ASK;
}
#ifdef ARTSEARCH
if (srchahead)
srchahead = -1;
#endif
perform_status_init(ngptr->toread);
for (s=buf; *s && (isdigit(*s) || index(" ,-.$",*s)); s++)
if (!isdigit(*s))
justone = FALSE;
if (*s) {
cmdlst = savestr(s);
justone = FALSE;
}
else if (!justone)
cmdlst = savestr("m");
*s++ = ',';
*s = '\0';
safecpy(tmpbuf,buf,LBUFLEN);
if (!output_level && !justone) {
printf("Processing...");
fflush(stdout);
}
for (s = tmpbuf; (c = index(s,',')) != NULL; s = ++c) {
*c = '\0';
if (*s == '.')
min = oldart;
else
min = atol(s);
if (min < absfirst) {
min = absfirst;
sprintf(msg,"(First article is %ld)",(long)absfirst);
warnmsg(msg);
}
if ((s=index(s,'-')) != NULL) {
s++;
if (*s == '$')
max = lastart;
else if (*s == '.')
max = oldart;
else
max = atol(s);
}
else
max = min;
if (max>lastart) {
max = lastart;
if (min > max)
min = max;
sprintf(msg,"(Last article is %ld)",(long)lastart) FLUSH;
warnmsg(msg);
}
if (max < min) {
errormsg("Bad range");
if (cmdlst)
free(cmdlst);
return NN_ASK;
}
if (justone) {
art = min;
return NN_REREAD;
}
for (art = article_first(min); art <= max; art = article_next(art)) {
artp = article_ptr(art);
if (perform(cmdlst,output_level && page_line == 1) < 0) {
#ifdef VERBOSE
IF(verbose)
sprintf(msg,"(Interrupted at article %ld)",(long)art);
ELSE
#endif
#ifdef TERSE
sprintf(msg,"(Intr at %ld)",(long)art);
#endif
errormsg(msg);
if (cmdlst)
free(cmdlst);
return NN_ASK;
}
if (!output_level)
perform_status(ngptr->toread, 50);
}
}
art = oldart;
if (cmdlst)
free(cmdlst);
return NN_NORM;
}
int
thread_perform()
{
register SUBJECT* sp;
register ARTICLE* ap;
bool want_unread;
char* cmdstr;
int len;
int bits;
bool output_level = (!use_threads && gmode != 's');
bool one_thread = FALSE;
if (!finish_command(TRUE)) /* get rest of command */
return 0;
if (!buf[1])
return -1;
len = 1;
if (buf[1] == ':') {
bits = 0;
len++;
}
else
bits = SF_VISIT;
if (buf[len] == '.') {
if (!artp)
return -1;
one_thread = TRUE;
len++;
}
cmdstr = savestr(buf+len);
want_unread = !sel_rereading && *cmdstr != 'm';
perform_status_init(ngptr->toread);
len = strlen(cmdstr);
if (!output_level && !one_thread) {
printf("Processing...");
fflush(stdout);
}
/* A few commands can just loop through the subjects. */
if ((len == 1 && (*cmdstr == 't' || *cmdstr == 'J'))
|| (len == 2
&& (((*cmdstr == '+' || *cmdstr == '-') && cmdstr[0] == cmdstr[1])
|| *cmdstr == 'T' || *cmdstr == 'A'))) {
performed_article_loop = FALSE;
if (one_thread)
sp = (sel_mode==SM_THREAD? artp->subj->thread->subj : artp->subj);
else
sp = next_subj((SUBJECT*)NULL,bits);
for ( ; sp; sp = next_subj(sp,bits)) {
if ((!(sp->flags & sel_mask) ^ !bits) || !sp->misc)
continue;
artp = first_art(sp);
if (artp) {
art = article_num(artp);
if (perform(cmdstr, 0) < 0) {
errormsg("Interrupted");
goto break_out;
}
}
if (one_thread)
break;
}
#if 0
} else if (strEQ(cmdstr, "E")) {
/* The 'E'nd-decode command doesn't do any looping at all. */
if (decode_fp)
decode_end();
#endif
} else if (*cmdstr == 'p') {
ART_NUM oldart = art;
art = lastart+1;
followup();
forcegrow = TRUE;
art = oldart;
page_line++; /*$$*/
} else {
/* The rest loop through the articles. */
/* Use the explicit article-order if it exists */
if (artptr_list) {
ARTICLE** app;
ARTICLE** limit = artptr_list + artptr_list_size;
sp = (sel_mode==SM_THREAD? artp->subj->thread->subj : artp->subj);
for (app = artptr_list; app < limit; app++) {
ap = *app;
if (one_thread && ap->subj->thread != sp->thread)
continue;
if ((!(ap->flags & AF_UNREAD) ^ want_unread)
&& !(ap->flags & sel_mask) ^ !!bits) {
art = article_num(ap);
artp = ap;
if (perform(cmdstr, output_level && page_line == 1) < 0) {
errormsg("Interrupted");
goto break_out;
}
}
if (!output_level)
perform_status(ngptr->toread, 50);
}
} else {
if (one_thread)
sp = (sel_mode==SM_THREAD? artp->subj->thread->subj : artp->subj);
else
sp = next_subj((SUBJECT*)NULL,bits);
for ( ; sp; sp = next_subj(sp,bits)) {
for (ap = first_art(sp); ap; ap = next_art(ap))
if ((!(ap->flags & AF_UNREAD) ^ want_unread)
&& !(ap->flags & sel_mask) ^ !!bits) {
art = article_num(ap);
artp = ap;
if (perform(cmdstr,output_level && page_line==1) < 0) {
errormsg("Interrupted");
goto break_out;
}
}
if (one_thread)
break;
if (!output_level)
perform_status(ngptr->toread, 50);
}
}
}
break_out:
free(cmdstr);
return 1;
}
int
perform(cmdlst,output_level)
register char* cmdlst;
int output_level;
{
register int ch;
int savemode = 0;
char tbuf[LBUFLEN+1];
/* A quick fix to avoid reuse of buf and cmdlst by shell commands. */
safecpy(tbuf, cmdlst, sizeof tbuf);
cmdlst = tbuf;
if (output_level == 1) {
printf("%-6ld ",art);
fflush(stdout);
}
perform_cnt++;
for (; (ch = *cmdlst) != 0; cmdlst++) {
if (isspace(ch) || ch == ':')
continue;
if (ch == 'j') {
if (savemode) {
mark_as_read(artp);
change_auto_flags(artp, AUTO_KILL_1);
}
else if (!was_read(art)) {
mark_as_read(artp);
#ifdef VERBOSE
IF(output_level && verbose)
fputs("\tJunked",stdout);
#endif
}
if (sel_rereading)
deselect_article(artp, output_level? ALSO_ECHO : 0);
} else if (ch == '+') {
if (savemode || cmdlst[1] == '+') {
if (sel_mode == SM_THREAD)
select_arts_thread(artp, savemode? AUTO_SEL_THD : 0);
else
select_arts_subject(artp, savemode? AUTO_SEL_SBJ : 0);
if (cmdlst[1] == '+')
cmdlst++;
} else
select_article(artp, output_level? ALSO_ECHO : 0);
} else if (ch == 'S') {
select_arts_subject(artp, AUTO_SEL_SBJ);
} else if (ch == '.') {
select_subthread(artp, savemode? AUTO_SEL_FOL : 0);
} else if (ch == '-') {
if (cmdlst[1] == '-') {
if (sel_mode == SM_THREAD)
deselect_arts_thread(artp);
else
deselect_arts_subject(artp);
cmdlst++;
} else
deselect_article(artp, output_level? ALSO_ECHO : 0);
} else if (ch == ',') {
kill_subthread(artp, AFFECT_ALL | (savemode? AUTO_KILL_FOL : 0));
} else if (ch == 'J') {
if (sel_mode == SM_THREAD)
kill_arts_thread(artp,AFFECT_ALL|(savemode? AUTO_KILL_THD:0));
else
kill_arts_subject(artp,AFFECT_ALL|(savemode? AUTO_KILL_SBJ:0));
} else if (ch == 'K' || ch == 'k') {
kill_arts_subject(artp, AFFECT_ALL|(savemode? AUTO_KILL_SBJ : 0));
} else if (ch == 'x') {
if (!was_read(art)) {
oneless(artp);
#ifdef VERBOSE
IF(output_level && verbose)
fputs("\tKilled",stdout);
#endif
}
if (sel_rereading)
deselect_article(artp, 0);
} else if (ch == 't') {
entire_tree(artp);
} else if (ch == 'T') {
savemode = 1;
} else if (ch == 'A') {
savemode = 2;
} else if (ch == 'm') {
if (savemode)
change_auto_flags(artp, AUTO_SEL_1);
else if ((artp->flags & (AF_UNREAD|AF_EXISTS)) == AF_EXISTS) {
unmark_as_read(artp);
#ifdef VERBOSE
IF(output_level && verbose)
fputs("\tMarked unread",stdout);
#endif
}
}
else if (ch == 'M') {
delay_unmark(artp);
oneless(artp);
#ifdef VERBOSE
IF(output_level && verbose)
fputs("\tWill return",stdout);
#endif
}
else if (ch == '=') {
carriage_return();
output_subject((char*)artp,0);
output_level = 0;
}
else if (ch == 'C') {
#ifdef ASYNC_PARSE
int ret = cancel_article();
# ifdef VERBOSE
IF(output_level && verbose)
printf("\t%sanceled",ret? "Not c" : "C");
# endif
#else
notincl("C");
return -1;
#endif
}
else if (ch == '%') {
#ifdef ASYNC_PARSE
char tmpbuf[512];
if (one_command)
interp(tmpbuf, (sizeof tmpbuf), cmdlst);
else
cmdlst = dointerp(tmpbuf,sizeof tmpbuf,cmdlst,":",(char*)NULL) - 1;
perform_cnt--;
if (perform(tmpbuf,output_level?2:0) < 0)
return -1;
#else
notincl("%");
return -1;
#endif
}
else if (index("!&sSwWae|",ch)) {
if (one_command)
strcpy(buf,cmdlst);
else
cmdlst = cpytill(buf,cmdlst,':') - 1;
/* we now have the command in buf */
if (ch == '!') {
escapade();
#ifdef VERBOSE
IF(output_level && verbose)
fputs("\tShell escaped",stdout);
#endif
}
else if (ch == '&') {
switcheroo();
#ifdef VERBOSE
IF(output_level && verbose)
if (buf[1] && buf[1] != '&')
fputs("\tSwitched",stdout);
#endif
}
else {
if (output_level != 1) {
erase_line(FALSE);
printf("%-6ld ",art);
}
if (ch == 'a')
view_article();
else
save_article();
newline();
output_level = 0;
}
}
else {
sprintf(msg,"Unknown command: %s",cmdlst);
errormsg(msg);
return -1;
}
#ifdef VERBOSE
IF(output_level && verbose)
fflush(stdout);
#endif
if (one_command)
break;
}
#ifdef VERBOSE
IF(output_level && verbose)
newline();
#endif
if (int_count) {
int_count = 0;
return -1;
}
return 1;
}
int
ngsel_perform()
{
char* cmdstr;
int len;
int bits;
bool one_group = FALSE;
if (!finish_command(TRUE)) /* get rest of command */
return 0;
if (!buf[1])
return -1;
len = 1;
if (buf[1] == ':') {
bits = 0;
len++;
}
else
bits = NF_INCLUDED;
if (buf[len] == '.') {
if (!ngptr)
return -1;
one_group = TRUE;
len++;
}
cmdstr = savestr(buf+len);
perform_status_init(newsgroup_toread);
len = strlen(cmdstr);
if (one_group) {
ng_perform(cmdstr, 0);
goto break_out;
}
for (ngptr = first_ng; ngptr; ngptr = ngptr->next) {
if (sel_rereading? ngptr->toread != TR_NONE
: ngptr->toread < ng_min_toread)
continue;
set_ng(ngptr);
if ((ngptr->flags & bits) == bits
&& (!(ngptr->flags & sel_mask) ^ !!bits)) {
if (ng_perform(cmdstr, 0) < 0)
break;
}
perform_status(newsgroup_toread, 50);
}
break_out:
free(cmdstr);
return 1;
}
int
ng_perform(cmdlst, output_level)
register char* cmdlst;
int output_level;
{
register int ch;
if (output_level == 1) {
printf("%s ",ngname);
fflush(stdout);
}
perform_cnt++;
for (; (ch = *cmdlst) != 0; cmdlst++) {
if (isspace(ch) || ch == ':')
continue;
switch (ch) {
case '+':
if (!(ngptr->flags & sel_mask)) {
ngptr->flags = ((ngptr->flags | sel_mask) & ~NF_DEL);
selected_count++;
}
break;
case 'c':
catch_up(ngptr, 0, 0);
/* FALL THROUGH */
case '-':
deselect:
if (ngptr->flags & sel_mask) {
ngptr->flags &= ~sel_mask;
if (sel_rereading)
ngptr->flags |= NF_DEL;
selected_count--;
}
break;
case 'u':
#ifdef VERBOSE
IF(output_level && verbose) {
printf(unsubto,ngptr->rcline) FLUSH;
termdown(1);
}
#endif
ngptr->subscribechar = NEGCHAR;
ngptr->toread = TR_UNSUB;
ngptr->rc->flags |= RF_RCCHANGED;
ngptr->flags &= ~sel_mask;
newsgroup_toread--;
goto deselect;
default:
sprintf(msg,"Unknown command: %s",cmdlst);
errormsg(msg);
return -1;
}
#ifdef VERBOSE
IF(output_level && verbose)
fflush(stdout);
#endif
if (one_command)
break;
}
#ifdef VERBOSE
IF(output_level && verbose)
newline();
#endif
if (int_count) {
int_count = 0;
return -1;
}
return 1;
}
int
addgrp_sel_perform()
{
register ADDGROUP* gp;
char* cmdstr;
int len;
int bits;
bool one_group = FALSE;
if (!finish_command(TRUE)) /* get rest of command */
return 0;
if (!buf[1])
return -1;
len = 1;
if (buf[1] == ':') {
bits = 0;
len++;
}
else
bits = sel_mask;
if (buf[len] == '.') {
if (first_addgroup) /*$$*/
return -1;
one_group = TRUE;
len++;
}
cmdstr = savestr(buf+len);
perform_status_init(newsgroup_toread);
len = strlen(cmdstr);
if (one_group) {
/*addgrp_perform(gp, cmdstr, 0);$$*/
goto break_out;
}
for (gp = first_addgroup; gp; gp = gp->next) {
if (!(gp->flags & sel_mask) ^ !!bits) {
if (addgrp_perform(gp, cmdstr, 0) < 0)
break;
}
perform_status(newsgroup_toread, 50);
}
break_out:
free(cmdstr);
return 1;
}
int
addgrp_perform(gp, cmdlst, output_level)
register ADDGROUP* gp;
register char* cmdlst;
int output_level;
{
register int ch;
if (output_level == 1) {
printf("%s ",gp->name);
fflush(stdout);
}
perform_cnt++;
for (; (ch = *cmdlst) != 0; cmdlst++) {
if (isspace(ch) || ch == ':')
continue;
if (ch == '+') {
gp->flags |= AGF_SEL;
selected_count++;
} else if (ch == '-') {
gp->flags &= ~AGF_SEL;
selected_count--;
}
else {
sprintf(msg,"Unknown command: %s",cmdlst);
errormsg(msg);
return -1;
}
#ifdef VERBOSE
IF(output_level && verbose)
fflush(stdout);
#endif
if (one_command)
break;
}
#ifdef VERBOSE
IF(output_level && verbose)
newline();
#endif
if (int_count) {
int_count = 0;
return -1;
}
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1