/* respond.c
*/
/* This software is copyrighted as detailed in the LICENSE file. */
#include "EXTERN.h"
#include "common.h"
#include "list.h"
#include "intrp.h"
#include "hash.h"
#include "cache.h"
#include "head.h"
#include "term.h"
#include "mime.h"
#include "ngdata.h"
#include "nntpclient.h"
#include "datasrc.h"
#include "nntp.h"
#include "ng.h"
#include "env.h"
#include "util.h"
#include "util2.h"
#include "trn.h"
#include "art.h"
#include "artio.h"
#include "search.h"
#include "artstate.h"
#include "final.h"
#include "decode.h"
#include "uudecode.h"
#include "charsubst.h"
#include "INTERN.h"
#include "respond.h"
#include "respond.ih"
static char nullart[] = "\nEmpty article.\n";
void
respond_init()
{
}
int
save_article()
{
bool_int use_pref;
register char* s;
register char* c;
char altbuf[CBUFLEN];
int i;
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);
mime_SetArticle();
clear_artbuf();
savefrom = (cmd == 'w' || cmd == 'e')? htype[PAST_HEADER].minpos : 0;
if (artopen(art,savefrom) == NULL) {
#ifdef VERBOSE
IF(verbose)
fputs("\nCan't save an empty article.\n",stdout) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs(nullart,stdout) FLUSH;
#endif
termdown(2);
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;
char* cmdstr;
int partOpt = 0, totalOpt = 0;
s = buf+1; /* skip e */
while (*s == ' ') s++; /* skip leading spaces */
if (*s == '-' && isdigit(s[1])) {
partOpt = atoi(s+1);
do s++; while (isdigit(*s));
if (*s == '/') {
totalOpt = atoi(s+1);
do s++; while (isdigit(*s));
while (*s == ' ') s++;
}
else
totalOpt = partOpt;
}
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 */
safefree(extractprog);
extractprog = savestr(s); /* put extracter in %e */
}
else
cmdstr = extractprog;
}
else
cmdstr = NULL;
s = buf;
}
else {
if (extractdest)
strcpy(s, extractdest);
if (custom_extract)
cmdstr = extractprog;
else
cmdstr = NULL;
}
custom_extract = (cmdstr != 0);
if (FILE_REF(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 (FILE_REF(s) != '/') { /* path still relative? */
c = (s==buf ? altbuf : buf);
sprintf(c, "%s/%s", cwd, s);
s = c; /* absolutize it */
}
safefree(extractdest);
s = extractdest = savestr(s); /* make it handy for %E */
if (makedir(s, MD_DIR)) { /* ensure directory exists */
int_count++;
return SAVE_DONE;
}
if (chdir(s)) {
printf(nocd,s) FLUSH;
sig_catcher(0);
}
c = trn_getwd(buf, sizeof(buf)); /* simplify path for output */
if (custom_extract) {
printf("Extracting article into %s using %s\n",c,extractprog) FLUSH;
termdown(1);
interp(cmd_buf, sizeof cmd_buf, getval("CUSTOMSAVER",CUSTOMSAVER));
invoke(cmd_buf, (char*)NULL);
}
else if (is_mime) {
printf("Extracting MIME article into %s:\n", c) FLUSH;
termdown(1);
mime_DecodeArticle(FALSE);
}
else {
char* filename;
int part, total;
int decode_type = 0;
int cnt = 0;
/* Scan subject for filename and part number information */
filename = decode_subject(art, &part, &total);
if (partOpt)
part = partOpt;
if (totalOpt)
total = totalOpt;
for (artpos = savefrom;
readart(art_line,sizeof art_line) != NULL;
artpos = tellart())
{
if (*art_line <= ' ')
continue; /* Ignore empty or initially-whitespace lines */
if (((*art_line == '#' || *art_line == ':')
&& (strnEQ(art_line+1, "! /bin/sh", 9)
|| strnEQ(art_line+1, "!/bin/sh", 8)
|| strnEQ(art_line+2, "This is ", 8)))
#if 0
|| strnEQ(art_line, "sed ", 4)
|| strnEQ(art_line, "cat ", 4)
|| strnEQ(art_line, "echo ", 5)
#endif
) {
savefrom = artpos;
decode_type = 1;
break;
}
else if (uue_prescan(art_line,&filename,&part,&total)) {
savefrom = artpos;
seekart(savefrom);
decode_type = 2;
break;
}
else if (++cnt == 300)
break;
}/* for */
switch (decode_type) {
case 1:
printf("Extracting shar into %s:\n", c) FLUSH;
termdown(1);
interp(cmd_buf,(sizeof cmd_buf),getval("SHARSAVER",SHARSAVER));
invoke(cmd_buf, (char*)NULL);
break;
case 2:
printf("Extracting uuencoded file into %s:\n", c) FLUSH;
termdown(1);
mime_section->type = IMAGE_MIME;
safefree(mime_section->filename);
mime_section->filename = filename? savestr(filename) : NULL;
mime_section->encoding = MENCODE_UUE;
mime_section->part = part;
mime_section->total = total;
if (!decode_piece((MIMECAP_ENTRY*)NULL,(char*)NULL) && *msg) {
newline();
fputs(msg,stdout);
}
newline();
break;
default:
printf("Unable to determine type of file.\n") FLUSH;
termdown(1);
break;
}
}/* if */
}
else if ((s = index(buf,'|')) != NULL) { /* is it a pipe command? */
s++; /* skip the | */
while (*s == ' ') s++;
safecpy(altbuf,filexp(s),sizeof altbuf);
safefree(savedest);
savedest = savestr(altbuf);
#ifdef SUPPORT_NNTP
if (datasrc->flags & DF_REMOTE)
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((char*)NULL,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
termdown(1);
s++;
}
for (; *s == ' '; s++); /* skip spaces */
safecpy(altbuf,filexp(s),sizeof altbuf);
s = altbuf;
if (!FILE_REF(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 (i = 0;
(there = stat(s,&filestat) >= 0) && S_ISDIR(filestat.st_mode);
i++) { /* is it a directory? */
c = (s+strlen(s));
*c++ = '/'; /* put a slash before filename */
interp(c, s==buf?(sizeof buf):(sizeof altbuf),
i ? "News" : savename );
/* generate a default name somehow or other */
}
makedir(s,MD_FILE);
if (FILE_REF(s) != '/') { /* relative path? */
c = (s==buf ? altbuf : buf);
sprintf(c, "%s/%s", cwd, s);
s = c; /* absolutize it */
}
safefree(savedest);
s = savedest = savestr(s); /* doesn't move any more */
/* make it handy for %b */
tmpfp = NULL;
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);
newline();
#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
termdown(4);
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;
termdown(1);
settle_down();
goto reask_save;
}
}
}
else if (S_ISCHR(filestat.st_mode))
mailbox = FALSE;
else {
tmpfp = fopen(s,"r+");
if (!tmpfp)
mailbox = FALSE;
else {
if (fread(buf,1,LBUFLEN,tmpfp)) {
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 */
}
}
s = getenv(mailbox ? "MBOXSAVER" : "NORMSAVER");
if (s) {
if (tmpfp)
fclose(tmpfp);
safecpy(cmd_buf, filexp(s), sizeof cmd_buf);
#ifdef SUPPORT_NNTP
if (datasrc->flags & DF_REMOTE)
nntp_finishbody(FB_SILENT);
#endif
termlib_reset();
resetty(); /* make terminal behave */
i = doshell(use_pref?(char*)NULL:SH,cmd_buf);
termlib_init();
noecho(); /* make terminal do what we want */
crmode();
}
else if (tmpfp != NULL || (tmpfp = fopen(savedest, "a")) != NULL) {
bool quote_From = FALSE;
fseek(tmpfp,0,2);
if (mailbox) {
#if MBOXCHAR == '\001'
fprintf(tmpfp,"\001\001\001\001\n");
#else
interp(cmd_buf, sizeof cmd_buf, "From %t %`LANG= date`\n");
fputs(cmd_buf, tmpfp);
quote_From = TRUE;
#endif
}
if (savefrom == 0 && art != 0)
fprintf(tmpfp,"Article: %ld of %s\n", (long)art, ngname);
seekart(savefrom);
while (readart(buf,LBUFLEN) != NULL) {
if (quote_From && strncaseEQ(buf,"from ",5))
putc('>', tmpfp);
fputs(buf, tmpfp);
}
fputs("\n\n", tmpfp);
#if MBOXCHAR == '\001'
if (mailbox)
fprintf(tmpfp,"\001\001\001\001\n");
#endif
fclose(tmpfp);
i = 0; /*$$ set non-zero on write error */
}
else
i = 1;
if (i)
fputs("Not saved",stdout);
else {
printf("%s to %s %s", there? "Appended" : "Saved",
mailbox? "mailbox" : "file", savedest);
}
if (interactive)
newline();
}
s_bomb:
chdir_newsdir();
return SAVE_DONE;
}
int
view_article()
{
parseheader(art);
mime_SetArticle();
clear_artbuf();
savefrom = htype[PAST_HEADER].minpos;
if (artopen(art,savefrom) == NULL) {
#ifdef VERBOSE
IF(verbose)
fputs("\nNo attatchments on an empty article.\n",stdout) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs(nullart,stdout) FLUSH;
#endif
termdown(2);
return SAVE_DONE;
}
printf("Processing attachments...\n") FLUSH;
termdown(1);
if (is_mime)
mime_DecodeArticle(TRUE);
else {
char* filename;
int part, total;
int cnt = 0;
/* Scan subject for filename and part number information */
filename = decode_subject(art, &part, &total);
for (artpos = savefrom;
readart(art_line,sizeof art_line) != NULL;
artpos = tellart())
{
if (*art_line <= ' ')
continue; /* Ignore empty or initially-whitespace lines */
if (uue_prescan(art_line, &filename, &part, &total)) {
MIMECAP_ENTRY* mc = mime_FindMimecapEntry("image/jpeg",0); /*$$ refine this */
savefrom = artpos;
seekart(savefrom);
mime_section->type = UNHANDLED_MIME;
safefree(mime_section->filename);
mime_section->filename = filename? savestr(filename) : NULL;
mime_section->encoding = MENCODE_UUE;
mime_section->part = part;
mime_section->total = total;
if (mc && !decode_piece(mc,(char*)NULL) && *msg) {
newline();
fputs(msg,stdout);
}
newline();
cnt = 0;
}
else if (++cnt == 300)
break;
}/* for */
if (cnt) {
printf("Unable to determine type of file.\n") FLUSH;
termdown(1);
}
}
chdir_newsdir();
return SAVE_DONE;
}
int
cancel_article()
{
char hbuf[5*LBUFLEN];
char* ngs_buf;
char* from_buf;
char* reply_buf;
int myuid = getuid();
int r = -1;
if (artopen(art,(ART_POS)0) == NULL) {
#ifdef VERBOSE
IF(verbose)
fputs("\nCan't cancel an empty article.\n",stdout) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs(nullart,stdout) FLUSH;
#endif
termdown(2);
return r;
}
reply_buf = fetchlines(art,REPLY_LINE);
from_buf = fetchlines(art,FROM_LINE);
ngs_buf = fetchlines(art,NGS_LINE);
if (strcaseNE(getval("FROM",""),from_buf)
&& (!instr(from_buf,hostname,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,hostname,from_buf) FLUSH;
printf("%s != %s\n",getval("FROM",""),from_buf) FLUSH;
termdown(3);
}
#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
termdown(2);
}
else {
tmpfp = fopen(headname,"w"); /* open header file */
if (tmpfp == NULL) {
printf(cantcreate,headname) FLUSH;
termdown(1);
goto done;
}
interp(hbuf, sizeof hbuf, getval("CANCELHEADER",CANCELHEADER));
fputs(hbuf,tmpfp);
fclose(tmpfp);
fputs("\nCanceling...\n",stdout) FLUSH;
termdown(2);
export_nntp_fds = TRUE;
r = doshell(sh,filexp(getval("CANCEL",CALL_INEWS)));
export_nntp_fds = FALSE;
}
done:
free(ngs_buf);
free(from_buf);
free(reply_buf);
return r;
}
int
supersede_article() /* Supersedes: */
{
char hbuf[5*LBUFLEN];
char* ngs_buf;
char* from_buf;
char* reply_buf;
int myuid = getuid();
int r = -1;
bool incl_body = (*buf == 'Z');
if (artopen(art,(ART_POS)0) == NULL) {
#ifdef VERBOSE
IF(verbose)
fputs("\nCan't supersede an empty article.\n",stdout) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs(nullart,stdout) FLUSH;
#endif
termdown(2);
return r;
}
reply_buf = fetchlines(art,REPLY_LINE);
from_buf = fetchlines(art,FROM_LINE);
ngs_buf = fetchlines(art,NGS_LINE);
if (strcaseNE(getval("FROM",""),from_buf)
&& (!instr(from_buf,hostname,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,hostname,from_buf) FLUSH;
printf("%s != %s\n",getval("FROM",""),from_buf) FLUSH;
termdown(3);
}
#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
termdown(2);
}
else {
tmpfp = fopen(headname,"w"); /* open header file */
if (tmpfp == NULL) {
printf(cantcreate,headname) FLUSH;
termdown(1);
goto done;
}
interp(hbuf, sizeof hbuf, getval("SUPERSEDEHEADER",SUPERSEDEHEADER));
fputs(hbuf,tmpfp);
if (incl_body && artfp != NULL) {
parseheader(art);
seekart(htype[PAST_HEADER].minpos);
while (readart(buf,LBUFLEN) != NULL)
fputs(buf,tmpfp);
}
fclose(tmpfp);
follow_it_up();
r = 0;
}
done:
free(ngs_buf);
free(from_buf);
free(reply_buf);
return r;
}
static void
follow_it_up()
{
safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)), sizeof cmd_buf);
if (invoke(cmd_buf,origdir) == 42) {
int ret;
#ifdef SUPPORT_NNTP
if ((datasrc->flags & DF_REMOTE)
&& (nntp_command("DATE") <= 0
|| (nntp_check() < 0 && atoi(ser_line) != NNTP_BAD_COMMAND_VAL)))
ret = 1;
else
#endif
{
export_nntp_fds = TRUE;
ret = invoke(filexp(CALL_INEWS),origdir);
export_nntp_fds = FALSE;
}
if (ret) {
int appended = 0;
char* deadart = filexp("%./dead.article");
FILE* fp_in;
FILE* fp_out;
if ((fp_out = fopen(deadart, "a")) != NULL) {
if ((fp_in = fopen(headname, "r")) != NULL) {
while (fgets(cmd_buf, sizeof cmd_buf, fp_in))
fputs(cmd_buf, fp_out);
fclose(fp_in);
appended = 1;
}
fclose(fp_out);
}
if (appended)
printf("Article appended to %s\n", deadart) FLUSH;
else
printf("Unable to append article to %s\n", deadart) FLUSH;
}
}
}
void
reply()
{
char hbuf[5*LBUFLEN];
bool incl_body = (*buf == 'R' && art);
char* maildoer = savestr(getval("MAILPOSTER",MAILPOSTER));
artopen(art,(ART_POS)0);
tmpfp = fopen(headname,"w"); /* open header file */
if (tmpfp == NULL) {
printf(cantcreate,headname) FLUSH;
termdown(1);
goto done;
}
interp(hbuf, sizeof hbuf, getval("MAILHEADER",MAILHEADER));
fputs(hbuf,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
termdown(3);
}
if (incl_body && artfp != NULL) {
char* s;
char* t;
interp(buf, (sizeof buf), getval("YOUSAID",YOUSAID));
fprintf(tmpfp,"%s\n",buf);
parseheader(art);
mime_SetArticle();
clear_artbuf();
seekart(htype[PAST_HEADER].minpos);
wrapped_nl = '\n';
while ((s = readartbuf(FALSE)) != NULL) {
if ((t = index(s, '\n')) != NULL)
*t = '\0';
#ifdef CHARSUBST
strcharsubst(hbuf,s,sizeof hbuf,*charsubst);
fprintf(tmpfp,"%s%s\n",indstr,hbuf);
#else
fprintf(tmpfp,"%s%s\n",indstr,s);
#endif
if (t)
*t = '\0';
}
fprintf(tmpfp,"\n");
wrapped_nl = WRAPPED_NL;
}
fclose(tmpfp);
safecpy(cmd_buf,filexp(maildoer),sizeof cmd_buf);
invoke(cmd_buf,origdir);
done:
free(maildoer);
}
void
forward()
{
char hbuf[5*LBUFLEN];
char* maildoer = savestr(getval("FORWARDPOSTER",FORWARDPOSTER));
#ifdef REGEX_WORKS_RIGHT
COMPEX mime_compex;
#else
char* s;
char* eol;
#endif
char* mime_boundary;
#ifdef REGEX_WORKS_RIGHT
init_compex(&mime_compex);
#endif
artopen(art,(ART_POS)0);
tmpfp = fopen(headname,"w"); /* open header file */
if (tmpfp == NULL) {
printf(cantcreate,headname) FLUSH;
termdown(1);
goto done;
}
interp(hbuf, sizeof hbuf, getval("FORWARDHEADER",FORWARDHEADER));
fputs(hbuf,tmpfp);
#ifdef REGEX_WORKS_RIGHT
if (!compile(&mime_compex,"Content-Type: multipart/.*; *boundary=\"\\([^\"]*\\)\"",TRUE,TRUE)
&& execute(&mime_compex,hbuf) != NULL)
mime_boundary = getbracket(&mime_compex,1);
else
mime_boundary = NULL;
#else
mime_boundary = NULL;
for (s = hbuf; s; s = eol) {
eol = index(s, '\n');
if (eol)
eol++;
if (*s == 'C' && strncaseEQ(s, "Content-Type: multipart/", 24)) {
s += 24;
for (;;) {
for ( ; *s && *s != ';'; s++) {
if (*s == '\n' && !isspace(s[1]))
break;
}
if (*s != ';')
break;
while (*++s == ' ') ;
if (*s == 'b' && strncaseEQ(s, "boundary=\"", 10)) {
mime_boundary = s+10;
if ((s = index(mime_boundary, '"')) != NULL)
*s = '\0';
mime_boundary = savestr(mime_boundary);
if (s)
*s = '"';
break;
}
}
}
}
#endif
if (!instr(maildoer,"%h",TRUE)) {
#ifdef VERBOSE
IF(verbose)
printf("\n%s\n(Above lines saved in file %s)\n",hbuf,headname)
FLUSH;
ELSE
#endif
#ifdef TERSE
printf("\n%s\n(Header in %s)\n",hbuf,headname) FLUSH;
#endif
termdown(3);
}
if (artfp != NULL) {
interp(buf, sizeof buf, getval("FORWARDMSG",FORWARDMSG));
if (mime_boundary) {
if (*buf && strncaseNE(buf, "Content-", 8))
strcpy(buf, "Content-Type: text/plain\n");
fprintf(tmpfp,"--%s\n%s\n[Replace this with your comments.]\n\n--%s\nContent-Type: message/rfc822\n\n",
mime_boundary,buf,mime_boundary);
}
else if (*buf)
fprintf(tmpfp,"%s\n",buf);
parseheader(art);
seekart((ART_POS)0);
while (readart(buf,sizeof buf) != NULL) {
if (!mime_boundary && *buf == '-') {
putchar('-');
putchar(' ');
}
fprintf(tmpfp,"%s",buf);
}
if (mime_boundary)
fprintf(tmpfp,"\n--%s--\n",mime_boundary);
else {
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);
done:
free(maildoer);
#ifdef REGEX_WORKS_RIGHT
free_compex(&mime_compex);
#else
safefree(mime_boundary);
#endif
}
void
followup()
{
char hbuf[5*LBUFLEN];
bool incl_body = (*buf == 'F' && art);
ART_NUM oldart = art;
if (!incl_body && art <= lastart) {
termdown(2);
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,(ART_POS)0);
tmpfp = fopen(headname,"w");
if (tmpfp == NULL) {
printf(cantcreate,headname) FLUSH;
termdown(1);
art = oldart;
return;
}
interp(hbuf, sizeof hbuf, getval("NEWSHEADER",NEWSHEADER));
fputs(hbuf,tmpfp);
if (incl_body && artfp != NULL) {
char* s;
char* t;
#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);
mime_SetArticle();
clear_artbuf();
seekart(htype[PAST_HEADER].minpos);
wrapped_nl = '\n';
while ((s = readartbuf(FALSE)) != NULL) {
if ((t = index(s, '\n')) != NULL)
*t = '\0';
#ifdef CHARSUBST
strcharsubst(hbuf,s,sizeof hbuf,*charsubst);
fprintf(tmpfp,"%s%s\n",indstr,hbuf);
#else
fprintf(tmpfp,"%s%s\n",indstr,s);
#endif
if (t)
*t = '\0';
}
fprintf(tmpfp,"\n");
wrapped_nl = WRAPPED_NL;
}
fclose(tmpfp);
follow_it_up();
art = oldart;
}
int
invoke(cmd,dir)
char* cmd;
char* dir;
{
char oldmode = mode;
int ret = -1;
#ifdef SUPPORT_NNTP
if (datasrc->flags & DF_REMOTE)
nntp_finishbody(FB_SILENT);
#endif
#ifdef DEBUG
if (debug)
printf("\nInvoking command: %s\n",cmd);
#endif
if (dir) {
if (chdir(dir)) {
printf(nocd,dir) FLUSH;
return ret;
}
}
set_mode(gmode,'x');
termlib_reset();
resetty(); /* make terminal well-behaved */
ret = doshell(sh,cmd); /* do the command */
noecho(); /* set no echo */
crmode(); /* and cbreak mode */
termlib_init();
set_mode(gmode,oldmode);
if (dir)
chdir_newsdir();
return ret;
}
/*
** 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----#
*/
#if 0
static bool
cut_line(str)
char* str;
{
char* cp;
char 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 (strEQ(word, "line")
|| strEQ(word, "here"))
if ((other_cnt -= 4) <= 20)
return TRUE;
break;
case 1:
if (strEQ(word, "this")) {
got_flag = 2;
other_cnt -= 4;
}
else if (strEQ(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 (strEQ(word, "cut")
|| strEQ(word, "snip")
|| strEQ(word, "tear")) {
got_flag = 1;
other_cnt -= strlen(word);
}
break;
}
*(cp = word) = '\0';
}
}
} /* for *str */
return FALSE;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1