/* $Id: respond.c,v 3.0 1992/02/01 03:09:32 davison Trn $
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction or this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The authors make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "intrp.h"
#include "cache.h"
#include "head.h"
#include "term.h"
#include "ngdata.h"
#include "ng.h"
#include "util.h"
#include "util2.h"
#include "trn.h"
#include "artio.h"
#include "nntp.h"
#include "final.h"
#include "decode.h"
#include "charsubst.h"
#include "INTERN.h"
#include "respond.h"

static char nullart[] = "\nNull article\n";

bool cut_line();

void
respond_init()
{
    if (actfp)
	export("NEWSACTIVE", filexp(ACTIVE));
}

int
save_article()
{
    bool_int use_pref;
    register char *s, *c;
    char altbuf[CBUFLEN];
    int iter;
    bool interactive = (buf[1] == FINISHCMD);
    char cmd = *buf;
    
    if (!finish_command(interactive))	/* get rest of command */
	return SAVE_ABORT;
    if ((use_pref = isupper(cmd)) != 0)
	cmd = tolower(cmd);
    parseheader(art);
#ifdef MIMESTORE
    savefrom = (!mime_article && (cmd == 'w' || cmd == 'e'))
#else
    savefrom = (cmd == 'w' || cmd == 'e')
#endif
		? htype[PAST_HEADER].ht_minpos : 0;
    if (artopen(art) == Nullfp) {
#ifdef VERBOSE
	IF(verbose)
	    fputs("\n\
Saving null articles is not very productive!  :-)\n\
",stdout) FLUSH;
	ELSE
#endif
#ifdef TERSE
	    fputs(nullart,stdout) FLUSH;
#endif
	return SAVE_DONE;
    }
    if (chdir(cwd)) {
	printf(nocd,cwd) FLUSH;
	sig_catcher(0);
    }
    if (cmd == 'e') {		/* is this an extract command? */
	static bool custom_extract = FALSE;
	int cnt = 0;
	bool found_cut = FALSE;
	char art_buf[LBUFLEN], *cmdstr;

	s = buf+1;		/* skip e */
	while (*s == ' ') s++;	/* skip leading spaces */
	safecpy(altbuf,filexp(s),sizeof altbuf);
	s = altbuf;
	if (*s) {
	    cmdstr = cpytill(buf,s,'|');	/* check for | */
	    s = buf + strlen(buf)-1;
	    while (*s == ' ') s--;		/* trim trailing spaces */
	    *++s = '\0';
	    if (*cmdstr) {
		s = cmdstr+1;			/* skip | */
		while (*s == ' ') s++;
		if (*s)	{			/* if new command, use it */
		    if (extractprog)
			free(extractprog);
		    extractprog = savestr(s);	/* put extracter in %e */
		}
		else
		    cmdstr = extractprog;
	    }
	    else
		cmdstr = Nullch;
	    s = buf;
	}
	else {
	    if (extractdest)
		strcpy(s, extractdest);
	    if (custom_extract)
		cmdstr = extractprog;
	    else
		cmdstr = Nullch;
	}
	if (cmdstr) {
	    if (strEQ(extractprog,"-"))
		cmdstr = Nullch;
	    else if (decode_fp != Nullfp)
		decode_end();
	}
	custom_extract = (cmdstr != 0);

	seekart((long)savefrom);
	if (*s != '/') {		/* relative path? */
	    c = (s==buf ? altbuf : buf);
	    interp(c, (sizeof buf), getval("SAVEDIR",SAVEDIR));
	    if (makedir(c,MD_DIR))	/* ensure directory exists */
		strcpy(c,cwd);
	    if (*s) {
		while (*c) c++;
		*c++ = '/';
		strcpy(c,s);		/* add filename */
	    }
	    s = (s==buf ? altbuf : buf);
	}
	if (*s != '/') {		/* path still relative? */
	    c = (s==buf ? altbuf : buf);
	    sprintf(c, "%s/%s", cwd, s);
	    s = c;			/* absolutize it */
	}
	if (decode_fp != Nullfp) {
	    printf("Continuing %s:%s\n", decode_fname,
		cmd != '\0' && strNE(extractdest,s) ?
		 " (Ignoring conflicting directory)" : nullstr ) FLUSH;
#ifdef USE_NNTP
	    nntp_finishbody(FB_SILENT);
#endif
	    if (decode_type == UUDECODE)
		uudecode(artfp);
	    else
		unship(artfp);
	}
	else {
	    if (extractdest)
		free(extractdest);
	    s = extractdest = savestr(s); /* make it handy for %E */
	    if (makedir(s, MD_DIR)) {	/* ensure directory exists */
		int_count++;
#ifdef USE_NNTP
		nntp_finishbody(FB_SILENT);
#endif
		return SAVE_DONE;
	    }
	    if (chdir(s)) {
		printf(nocd,s) FLUSH;
		sig_catcher(0);
	    }
	    s = getwd(buf);		/* simplify path for output */
	    while(readart(art_buf,LBUFLEN) != Nullch) {
		if (*art_buf <= ' ')
		    continue;	/* Ignore empty or initially-whitespace lines */
#ifdef MIMESTORE
		if (mime_article) {
		    char oldmode = mode;
		    if (!custom_extract) {
			printf("Extracting MIME article into %s:\n", s) FLUSH;
			extractprog = savestr(filexp(getval("MIMESTORE",MIMESTORE)));
		    }
		    else
			printf("Extracting MIME article into %s using %s\n",
			       s, extractprog) FLUSH;
		    cnt = 0;
#ifdef USE_NNTP
		    nntp_finishbody(FB_SILENT);
#endif
		    interp(cmd_buf, sizeof cmd_buf,
			   getval("EXMIMESAVER",EXMIMESAVER));
		    termlib_reset();
		    mode = 'x';
		    resetty();		/* restore tty state */
		    doshell(SH,cmd_buf);
		    noecho();		/* revert to cbreaking */
		    crmode();
		    termlib_init();
		    mode = oldmode;
		    break;
		}
#endif
		if (found_cut && custom_extract) {
		    printf("Extracting data into %s using %s:\n",
			s, extractprog) FLUSH;
		    goto extract_it;
		}
		if (((*art_buf == '#' || *art_buf == ':')
		  && (strnEQ(art_buf+1, "! /bin/sh", 9)
		   || strnEQ(art_buf+1, "!/bin/sh", 8)
		   || strnEQ(art_buf+2, "This is ", 8)))
		 || strnEQ(art_buf, "sed ", 4)
		 || strnEQ(art_buf, "cat ", 4)
		 || strnEQ(art_buf, "echo ", 5)) {
		    savefrom = tellart()-strlen(art_buf)-NL_SIZE+1;
		    seekart((long)savefrom);
		    if (custom_extract) {
			printf("Extracting shar into %s using %s:\n",
				s, extractprog) FLUSH;
			goto extract_it;
		    }
		    /* Check for special-case of shar'ed-uuencoded file */
		    while(readart(art_buf,LBUFLEN) != Nullch) {
			if (*art_buf == '#' || *art_buf == ':'
			 || strnEQ(art_buf, "echo ", 5)
			 || strnEQ(art_buf, "sed ", 4))
			    continue;
			if (strnEQ(art_buf, "Xbegin ", 7)) {
			    decode_type = UUDECODE;
			    goto decode_it;
			}
			break;
		    }
		    printf("Extracting shar into %s:\n", s) FLUSH;
		    if (extractprog)
			free(extractprog);
		    extractprog = savestr(filexp(getval("UNSHAR",UNSHAR)));
		  extract_it:
		    cnt = 0;
#ifdef USE_NNTP
		    nntp_finishbody(FB_SILENT);
#endif
		    interp(cmd_buf,(sizeof cmd_buf),getval("EXSAVER",EXSAVER));
		    termlib_reset();
		    resetty();		/* restore tty state */
		    doshell(SH,cmd_buf);
		    noecho();		/* revert to cbreaking */
		    crmode();
		    termlib_init();
		    break;
		}
		else
		if (!custom_extract
		 && (strEQ(art_buf,"$\n")
		  || strEQ(art_buf,"$ f\n"))) {
		    savefrom = tellart()-strlen(art_buf)-NL_SIZE+1;
		    if (found_cut
		     || (readart(art_buf,LBUFLEN) != Nullch
		      && (strnEQ(art_buf, "ship ", 5)
		       || strnEQ(art_buf, "cont ", 5)))) {
			decode_type = UNSHIP;
			goto decode_it;
		    }
		}
		else
		if (!custom_extract
		 && (strEQ(art_buf,"table\n")
		  || strnEQ(art_buf,"begin ", 6))) {
		    decode_type = UUDECODE;
		    savefrom = tellart()-strlen(art_buf)-NL_SIZE+1;
		 decode_it:
		    printf("Extracting %s file into %s:\n",
			decode_type == UNSHIP? "shipped":"uuencoded", s) FLUSH;
		    if (extractprog)
			free(extractprog);
		    extractprog = savestr("-");
		    seekart((long)savefrom);
		    cnt = 0;
#ifdef USE_NNTP
		    nntp_finishbody(FB_SILENT);
#endif
		    if (decode_type == UUDECODE) {
			uud_start();
			uudecode(artfp);
		    } else
			unship(artfp);
		    break;
		}
		else {
		    if (cut_line(art_buf)) {
			savefrom = tellart();
			found_cut = TRUE;
		    }
		    else if (found_cut || ++cnt == 300) {
			break;
		    }
		}
	    }/* while */
	    if (cnt) {
		if (custom_extract)
		    printf("Didn't find cut line for extraction to '%s'.\n",
			extractprog) FLUSH;
		else
		    printf("Unable to determine type of file.\n") FLUSH;
	    }
	}/* if */
    }
    else if ((s = index(buf,'|')) != Nullch) {
				/* is it a pipe command? */
	s++;			/* skip the | */
	while (*s == ' ') s++;
	safecpy(altbuf,filexp(s),sizeof altbuf);
	if (savedest)
	    free(savedest);
	savedest = savestr(altbuf);
#ifdef USE_NNTP
	nntp_finishbody(FB_SILENT);
#endif
	interp(cmd_buf, (sizeof cmd_buf), getval("PIPESAVER",PIPESAVER));
				/* then set up for command */
	termlib_reset();
	resetty();		/* restore tty state */
	if (use_pref)		/* use preferred shell? */
	    doshell(Nullch,cmd_buf);
				/* do command with it */
	else
	    doshell(sh,cmd_buf);	/* do command with sh */
	noecho();		/* and stop echoing */
	crmode();		/* and start cbreaking */
	termlib_init();
    }
    else {			/* normal save */
	bool there, mailbox;
	char *savename = getval("SAVENAME",SAVENAME);

	s = buf+1;		/* skip s or S */
	if (*s == '-') {	/* if they are confused, skip - also */
#ifdef VERBOSE
	    IF(verbose)
		fputs("Warning: '-' ignored.  This isn't readnews.\n",stdout)
		  FLUSH;
	    ELSE
#endif
#ifdef TERSE
		fputs("'-' ignored.\n",stdout) FLUSH;
#endif
	    s++;
	}
	for (; *s == ' '; s++);	/* skip spaces */
	safecpy(altbuf,filexp(s),sizeof altbuf);
	s = altbuf;
	if (*s != '/') {
	    interp(buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
	    if (makedir(buf,MD_DIR))	/* ensure directory exists */
		strcpy(buf,cwd);
	    if (*s) {
		for (c = buf; *c; c++) ;
		*c++ = '/';
		strcpy(c,s);		/* add filename */
	    }
	    s = buf;
	}
	for (iter = 0;
	    (there = stat(s,&filestat) >= 0) && S_ISDIR(filestat.st_mode);
	    iter++) {			/* is it a directory? */

	    c = (s+strlen(s));
	    *c++ = '/';			/* put a slash before filename */
	    interp(c, s==buf?(sizeof buf):(sizeof altbuf),
		iter ? "News" : savename );
				/* generate a default name somehow or other */
	}
	makedir(s,MD_FILE);
	if (*s != '/') {		/* relative path? */
	    c = (s==buf ? altbuf : buf);
	    sprintf(c, "%s/%s", cwd, s);
	    s = c;			/* absolutize it */
	}
	if (savedest)
	    free(savedest);
	s = savedest = savestr(s);	/* doesn't move any more */
					/* make it handy for %b */
	if (!there) {
	    if (mbox_always)
		mailbox = TRUE;
	    else if (norm_always)
		mailbox = FALSE;
	    else {
		char *dflt = (instr(savename,"%a", TRUE) ? "nyq" : "ynq");
		
		sprintf(cmd_buf,
		"\nFile %s doesn't exist--\n	use mailbox format?",s);
	      reask_save:
		in_char(cmd_buf, 'M', dflt);
		putchar('\n') FLUSH;
#ifdef VERIFY
		printcmd();
#endif
		if (*buf == 'h') {
#ifdef VERBOSE
		    IF(verbose)
			printf("\n\
Type y to create %s as a mailbox.\n\
Type n to create it as a normal file.\n\
Type q to abort the save.\n\
",s) FLUSH;
		    ELSE
#endif
#ifdef TERSE
			fputs("\n\
y to create mailbox.\n\
n to create normal file.\n\
q to abort.\n\
",stdout) FLUSH;
#endif
		    goto reask_save;
		}
		else if (*buf == 'n') {
		    mailbox = FALSE;
		}
		else if (*buf == 'y') {
		    mailbox = TRUE;
		}
		else if (*buf == 'q') {
		    goto s_bomb;
		}
		else {
		    fputs(hforhelp,stdout) FLUSH;
		    settle_down();
		    goto reask_save;
		}
	    }
	}
	else if (S_ISCHR(filestat.st_mode))
	    mailbox = FALSE;
	else {
	    int tmpfd;
	    
	    tmpfd = open(s,0);
	    if (tmpfd == -1)
		mailbox = FALSE;
	    else {
		if (read(tmpfd,buf,LBUFLEN)) {
		    c = buf;
		    if (!isspace(MBOXCHAR))   /* if non-zero, */
			while (isspace(*c))   /* check the first character */
			    c++;
		    mailbox = (*c == MBOXCHAR);
		} else {
		    mailbox = mbox_always;    /* if zero length, recheck -M */
		}
		close(tmpfd);
	    }
	}

	safecpy(cmd_buf, filexp(mailbox ?
	    getval("MBOXSAVER",MBOXSAVER) :
	    getval("NORMSAVER",NORMSAVER) ), sizeof cmd_buf);
				/* format the command */
#ifdef USE_NNTP
	nntp_finishbody(FB_SILENT);
#endif
	termlib_reset();
	resetty();		/* make terminal behave */
	if (doshell(use_pref?Nullch:SH,cmd_buf)) {
	    termlib_init();
	    fputs("Not saved",stdout);
	} else {
	    termlib_init();
	    printf("%s to %s %s",
	      there?"Appended":"Saved",
	      mailbox?"mailbox":"file",
	      s);
	}
	if (interactive)
	    putchar('\n') FLUSH;
	noecho();		/* make terminal do what we want */
	crmode();
    }
s_bomb:
#ifdef USE_NNTP
    if (chdir(spool)) {
#else
    if (chdir(spool) || chdir(ngdir)) {
#endif
	printf(nocd,ngdir) FLUSH;
	sig_catcher(0);
    }
#ifdef USE_NNTP
    nntp_finishbody(FB_SILENT);
#endif
    return SAVE_DONE;
}

int
cancel_article()
{
    char *ngs_buf;
    char *from_buf;
    char *reply_buf;
    int myuid = getuid();
    int r = -1;

    if (artopen(art) == Nullfp) {
#ifdef VERBOSE
	IF(verbose)
	    fputs("\n\
Canceling null articles is your idea of fun?  :-)\n\
",stdout) FLUSH;
	ELSE
#endif
#ifdef TERSE
	    fputs(nullart,stdout) FLUSH;
#endif
	return r;
    }
    reply_buf = fetchlines(art,REPLY_LINE);
    from_buf = fetchlines(art,FROM_LINE);
    ngs_buf = fetchlines(art,NGS_LINE);
    if (!instr(from_buf,phostname,FALSE) ||
	(!instr(from_buf,loginName,TRUE) &&
	 !instr(reply_buf,loginName,TRUE) &&
#ifdef NEWS_ADMIN
	 myuid != newsuid &&
#endif
	 myuid != ROOTID ) ) {
#ifdef DEBUG
	    if (debug)
		printf("\n%s@%s != %s\n",loginName,phostname,from_buf) FLUSH;
#endif
#ifdef VERBOSE
	    IF(verbose)
		fputs("\nYou can't cancel someone else's article\n",stdout)
		  FLUSH;
	    ELSE
#endif
#ifdef TERSE
		fputs("\nNot your article\n",stdout) FLUSH;
#endif
    }
    else {
	tmpfp = fopen(headname,"w");	/* open header file */
	if (tmpfp == Nullfp) {
	    printf(cantcreate,headname) FLUSH;
	    goto no_cancel;
	}
	interp(buf, (sizeof buf), getval("CANCELHEADER",CANCELHEADER));
	fputs(buf,tmpfp);
	fclose(tmpfp);
	fputs("\nCanceling...\n",stdout) FLUSH;
	r = doshell(sh,filexp(getval("CANCEL",CANCEL)));
    }
no_cancel:
    free(ngs_buf);
    free(from_buf);
    free(reply_buf);
    return r;
}

int
supersede_article()		/* Supersedes: */
{
    char *ngs_buf;
    char *from_buf;
    char *reply_buf;
    int myuid = getuid();
    int r = -1;
    bool incl_body = (*buf == 'Z');

    if (artopen(art) == Nullfp) {
#ifdef VERBOSE
	IF(verbose)
	    fputs("\n\
Superceding null articles is your idea of fun?  :-)\n\
",stdout) FLUSH;
	ELSE
#endif
#ifdef TERSE
	    fputs(nullart,stdout) FLUSH;
#endif
	return r;
    }
    reply_buf = fetchlines(art,REPLY_LINE);
    from_buf = fetchlines(art,FROM_LINE);
    ngs_buf = fetchlines(art,NGS_LINE);
    if (!instr(from_buf,phostname,FALSE) ||
	(!instr(from_buf,loginName,TRUE) &&
	 !instr(reply_buf,loginName,TRUE) &&
#ifdef NEWS_ADMIN
	 myuid != newsuid &&
#endif
	 myuid != ROOTID ) ) {
#ifdef DEBUG
	    if (debug)
		printf("\n%s@%s != %s\n",loginName,phostname,from_buf) FLUSH;
#endif
#ifdef VERBOSE
	    IF(verbose)
		fputs("\nYou can't supersede someone else's article\n",stdout)
		  FLUSH;
	    ELSE
#endif
#ifdef TERSE
		fputs("\nNot your article\n",stdout) FLUSH;
#endif
    }
    else {
	tmpfp = fopen(headname,"w");	/* open header file */
	if (tmpfp == Nullfp) {
	    printf(cantcreate,headname) FLUSH;
	    goto no_commute;
	}
	interp(buf, (sizeof buf), getval("SUPERSEDEHEADER",SUPERSEDEHEADER));
	fputs(buf,tmpfp);
	if (incl_body && artfp != Nullfp) {
	    parseheader(art);
	    seekart((long)htype[PAST_HEADER].ht_minpos);
	    while (readart(buf,LBUFLEN) != Nullch) {
		fputs(buf,tmpfp);
	    }
	}
	fclose(tmpfp);
    	safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),
		sizeof cmd_buf);
    	invoke(cmd_buf,origdir);
	r = 0;
    }
no_commute:
    free(ngs_buf);
    free(from_buf);
    free(reply_buf);
    return r;
}

void
reply()
{
    bool incl_body = (*buf == 'R');
#ifdef CHARSUBST
    char hbuf[4*LBUFLEN];
#endif
    char *maildoer = savestr(getval("MAILPOSTER",MAILPOSTER));

    artopen(art);
    tmpfp = fopen(headname,"w");	/* open header file */
    if (tmpfp == Nullfp) {
	printf(cantcreate,headname) FLUSH;
	goto no_reply;
    }
    interp(buf, (sizeof buf), getval("MAILHEADER",MAILHEADER));
    fputs(buf,tmpfp);
    if (!instr(maildoer,"%h",TRUE))
#ifdef VERBOSE
	IF(verbose)
	    printf("\n%s\n(Above lines saved in file %s)\n",buf,headname)
	      FLUSH;
	ELSE
#endif
#ifdef TERSE
	    printf("\n%s\n(Header in %s)\n",buf,headname) FLUSH;
#endif
    if (incl_body && artfp != Nullfp) {
	interp(buf, (sizeof buf), getval("YOUSAID",YOUSAID));
	fprintf(tmpfp,"%s\n",buf);
	parseheader(art);
	seekart((long)htype[PAST_HEADER].ht_minpos);
	while (readart(buf,LBUFLEN) != Nullch) {
#ifdef CHARSUBST
	    strcharsubst(buf,hbuf);
	    fprintf(tmpfp,"%s%s",indstr,hbuf);
#else
	    fprintf(tmpfp,"%s%s",indstr,buf);
#endif
	}
	fprintf(tmpfp,"\n");
    }
    fclose(tmpfp);
    safecpy(cmd_buf,filexp(maildoer),sizeof cmd_buf);
    invoke(cmd_buf,origdir);
    UNLINK(headname);		/* kill the header file */
no_reply:
    free(maildoer);
}
  
void
forward()
{
#ifdef CHARSUBST
    char hbuf[4*LBUFLEN];
#endif
    char *maildoer = savestr(getval("FORWARDPOSTER",FORWARDPOSTER));

    artopen(art);
    tmpfp = fopen(headname,"w");	/* open header file */
    if (tmpfp == Nullfp) {
	printf(cantcreate,headname) FLUSH;
	goto no_forward;
    }
    interp(buf, (sizeof buf), getval("FORWARDHEADER",FORWARDHEADER));
    fputs(buf,tmpfp);
    if (!instr(maildoer,"%h",TRUE))
#ifdef VERBOSE
	IF(verbose)
	    printf("\n%s\n(Above lines saved in file %s)\n",buf,headname)
	      FLUSH;
	ELSE
#endif
#ifdef TERSE
	    printf("\n%s\n(Header in %s)\n",buf,headname) FLUSH;
#endif
    if (artfp != Nullfp) {
	interp(buf, (sizeof buf), getval("FORWARDMSG",FORWARDMSG));
	if (*buf)
	    fprintf(tmpfp,"%s\n",buf);
	parseheader(art);
	seekart(0L);
	while (readart(buf,LBUFLEN) != Nullch) {
#ifdef CHARSUBST
	    strcharsubst(buf,hbuf);
	    fprintf(tmpfp,"%s",hbuf);
#else
	    fprintf(tmpfp,"%s",buf);
#endif
	}
	interp(buf, (sizeof buf), getval("FORWARDMSGEND",FORWARDMSGEND));
	if (*buf)
	    fprintf(tmpfp,"%s\n",buf);
    }
    fclose(tmpfp);
    safecpy(cmd_buf,filexp(maildoer),sizeof cmd_buf);
    invoke(cmd_buf,origdir);
    UNLINK(headname);		/* kill the header file */
no_forward:
    free(maildoer);
}

void
followup()
{
    bool incl_body = (*buf == 'F');
    char hbuf[4*LBUFLEN];	/* four times the old size */
    ART_NUM oldart = art;

    if (!incl_body && art <= lastart) {
	in_answer("\n\nAre you starting an unrelated topic? [ynq] ", 'F');
	setdef(buf,"y");
	if (*buf == 'q')  /*TODO: need to add 'h' also */
	    return;
	if (*buf != 'n')
	    art = lastart + 1;
    }
    artopen(art);
    tmpfp = fopen(headname,"w");
    if (tmpfp == Nullfp) {
	printf(cantcreate,headname) FLUSH;
	art = oldart;
	return;
    }
    interp(hbuf, (sizeof hbuf), getval("NEWSHEADER",NEWSHEADER));
    fprintf(tmpfp,"%s",hbuf);
    if (incl_body && artfp != Nullfp) {
#ifdef VERBOSE
	if (verbose)
	    fputs("\n\
(Be sure to double-check the attribution against the signature, and\n\
trim the quoted article down as much as possible.)\n\
",stdout) FLUSH;
#endif
	interp(buf, (sizeof buf), getval("ATTRIBUTION",ATTRIBUTION));
	fprintf(tmpfp,"%s\n",buf);
	parseheader(art);
	seekart((long)htype[PAST_HEADER].ht_minpos);
	while (readart(buf,LBUFLEN) != Nullch) {
#ifdef CHARSUBST
	    strcharsubst(buf,hbuf);
	    fprintf(tmpfp,"%s%s",indstr,hbuf);
#else
	    fprintf(tmpfp,"%s%s",indstr,buf);
#endif
	}
	fprintf(tmpfp,"\n");
    }
    fclose(tmpfp);
    safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),sizeof cmd_buf);
    invoke(cmd_buf,origdir);
    UNLINK(headname);
    art = oldart;
}

void
invoke(cmd,dir)
char *cmd,*dir;
{
    char oldmode = mode;
    if (chdir(dir)) {
	printf(nocd,dir) FLUSH;
	return;
    }
    termlib_reset();
    mode = 'x';
#ifdef VERBOSE
    IF(verbose)
	printf("\n(leaving cbreak mode; cwd=%s)",dir);
    ELSE
#endif
#ifdef TERSE
	printf("\n(-cbreak; cwd=%s)",dir);
#endif
#ifdef DEBUG
    if (debug)
	printf("\nInvoking command: %s",cmd);
#endif
    printf("\n\n") FLUSH;
    resetty();			/* make terminal well-behaved */
    doshell(sh,cmd);		/* do the command */
    noecho();			/* set no echo */
    crmode();			/* and cbreak mode */
#ifdef VERBOSE
    IF(verbose)
	fputs("\n(re-entering cbreak mode)\n",stdout) FLUSH;
    ELSE
#endif
#ifdef TERSE
	fputs("\n(+cbreak)\n",stdout) FLUSH;
#endif
    termlib_init();
    mode = oldmode;
#ifdef USE_NNTP
    if (chdir(spool)) {
#else
    if (chdir(spool) || chdir(ngdir)) {
#endif
	printf(nocd,ngdir) FLUSH;
	sig_catcher(0);
    }
}

/*
** cut_line() determines if a line is meant as a "cut here" marker.
** Some examples that we understand:
**
**  BEGIN--cut here--cut here
**
**  ------------------ tear at this line ------------------
**
**  #----cut here-----cut here-----cut here-----cut here----#
*/
bool
cut_line(str)
char *str;
{
    char *cp, got_flag;
    char word[80];
    int  dash_cnt, equal_cnt, other_cnt;

    /* Disallow any single-/double-quoted, parenthetical or c-commented
    ** string lines.  Make sure it has the cut-phrase and at least six
    ** '-'s or '='s.  If only four '-'s are present, check for a duplicate
    ** of the cut phrase.  If over 20 unknown characters are encountered,
    ** assume it isn't a cut line.  If we succeed, return TRUE.
    */
    for (cp = str, dash_cnt = equal_cnt = other_cnt = 0; *cp; cp++) {
	switch (*cp) {
	case '-':
	    dash_cnt++;
	    break;
	case '=':
	    equal_cnt++;
	    break;
	case '/':
	    if(*(cp+1) != '*') {
		break;
	    }
	case '"':
	case '\'':
	case '(':
	case ')':
	case '[':
	case ']':
	case '{':
	case '}':
	    return FALSE;
	default:
	    other_cnt++;
	    break;
	}
    }
    if (dash_cnt < 4 && equal_cnt < 6)
	return FALSE;

    got_flag = 0;

    for (*(cp = word) = '\0'; *str; str++) {
	if (islower(*str))
	    *cp++ = *str;
	else if (isupper(*str))
	    *cp++ = tolower(*str);
	else {
	    if (*word) {
		*cp = '\0';
		switch (got_flag) {
		case 2:
		    if (!strcmp(word, "line")
		     || !strcmp(word, "here"))
			if ((other_cnt -= 4) <= 20)
			    return TRUE;
		    break;
		case 1:
		    if (!strcmp(word, "this")) {
			got_flag = 2;
			other_cnt -= 4;
		    }
		    else if (!strcmp(word, "here")) {
			other_cnt -= 4;
			if ((dash_cnt >= 6 || equal_cnt >= 6)
			 && other_cnt <= 20)
			    return TRUE;
			dash_cnt = 6;
			got_flag = 0;
		    }
		    break;
		case 0:
		    if (!strcmp(word, "cut")
		     || !strcmp(word, "snip")
		     || !strcmp(word, "tear")) {
			got_flag = 1;
			other_cnt -= strlen(word);
		    }
		    break;
		}
		*(cp = word) = '\0';
	    }
	}
    } /* for *str */

    return FALSE;
}
