home *** CD-ROM | disk | FTP | other *** search
- /* $Header: respond.c,v 4.3.3.2 91/01/16 03:28:40 davison Trn $
- *
- * $Log: respond.c,v $
- * Revision 4.3.3.2 91/01/16 03:28:40 davison
- * Integrated rn patches 48-54. Changed fseek to allow for NL_SIZE.
- *
- * Revision 4.3.3.1 90/07/21 20:30:18 davison
- * Initial Trn Release
- *
- * Revision 4.3.2.4 90/11/22 16:09:04 sob
- * Added changes to accomodate pickly C preprocessors
- *
- * Revision 4.3.2.3 90/03/22 23:05:19 sob
- * Fixes provided by Wayne Davison <drivax!davison>
- *
- * Revision 4.3.2.2 89/11/26 18:25:10 sob
- * Enlarged the size of the header buffer to accomodate long references lines.
- * Fix provided by Joe Buck.
- *
- * Revision 4.3.2.1 89/11/06 01:00:26 sob
- * Added RRN support from NNTP 1.5
- *
- * Revision 4.3.1.5 85/09/10 11:05:00 lwall
- * Improved %m in in_char().
- *
- * Revision 4.3.1.4 85/05/23 17:24:49 lwall
- * Now allows 'r' and 'f' on null articles.
- *
- * Revision 4.3.1.3 85/05/15 14:42:32 lwall
- * Removed duplicate include of intrp.h.
- *
- * Revision 4.3.1.2 85/05/14 08:55:15 lwall
- * Default for normal/mailbox question was applied to wrong buffer.
- *
- * Revision 4.3.1.1 85/05/10 11:37:33 lwall
- * Branch for patches.
- *
- * Revision 4.3 85/05/01 11:47:04 lwall
- * Baseline for release with 4.3bsd.
- *
- */
-
- #include "EXTERN.h"
- #include "common.h"
- #include "intrp.h"
- #include "head.h"
- #include "term.h"
- #include "ng.h"
- #include "util.h"
- #include "rn.h"
- #include "artio.h"
- #include "final.h"
- #include "uudecode.h"
- #include "INTERN.h"
- #include "respond.h"
-
- static char nullart[] = "\nNull article\n";
-
- void
- respond_init()
- {
- ;
- }
-
- int
- save_article()
- {
- bool use_pref, cut_line();
- 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);
- #ifdef ASYNC_PARSE
- parse_maybe(art);
- #endif
- savefrom = (cmd == 'w' || cmd == 'e' ? 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? */
- 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 (extractprog) {
- free(extractprog);
- extractprog = Nullch;
- }
- 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 (strEQ(s,"-"))
- cmdstr = Nullch;
- else {
- extractprog = savestr(s); /* put extracter in %e */
- if (uu_out != Nullfp)
- uud_end();
- }
- } else
- cmdstr = Nullch;
- s = buf;
- } else
- cmdstr = Nullch;
-
- fseek(artfp,savefrom,0);
- if ((cmd = *s) == '\0')
- interp(s = buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
- if (*s != '/') { /* relative path? */
- c = (s==buf ? altbuf : buf);
- sprintf(c, "%s/%s", cwd, s);
- s = c; /* absolutize it */
- }
- if (uu_out != Nullfp) {
- printf("Continuing %s:%s\n", uu_fname,
- cmd != '\0' && strNE(savedest,s) ?
- " (Ignoring conflicting directory)" : nullstr );
- uudecode(artfp);
- }
- else {
- if (savedest)
- free(savedest);
- s = savedest = savestr(s); /* make it handy for %b */
- if (makedir(s, MD_DIR)) { /* ensure directory exists */
- int_count++;
- return SAVE_DONE;
- }
- if (chdir(s)) {
- printf(nocd,s) FLUSH;
- sig_catcher(0);
- }
- s = getwd(buf); /* simplify path for output */
- while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
- if (*art_buf <= ' ')
- continue; /* Ignore empty or initially-whitespace lines */
- if (found_cut && cmdstr) {
- printf("Extracting data into %s using %s:\n",
- s, extractprog);
- 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)) {
- fseek(artfp,(long)-strlen(art_buf)-NL_SIZE+1,1);
- savefrom = ftell(artfp);
- if (cmdstr) {
- printf("Extracting shar into %s using %s:\n",
- s, extractprog);
- goto extract_it;
- }
- /* Check for special-case of shar'ed-uuencoded file */
- while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
- if (*art_buf == '#' || *art_buf == ':'
- || strnEQ(art_buf, "echo ", 5)
- || strnEQ(art_buf, "sed ", 4))
- continue;
- if (strnEQ(art_buf, "Xbegin ", 7))
- goto uu_decode;
- break;
- }
- printf("Extracting shar into %s:\n", s);
- extractprog = savestr(filexp(getval("UNSHAR",UNSHAR)));
- extract_it:
- cnt = 0;
- interp(cmd_buf,(sizeof cmd_buf),getval("EXSAVER",EXSAVER));
- resetty(); /* restore tty state */
- doshell(SH,cmd_buf);
- noecho(); /* revert to cbreaking */
- crmode();
- break;
- }
- else
- if (!cmdstr
- && (strnEQ(art_buf,"table ", 6)
- || strnEQ(art_buf,"table\n", 6)
- || strnEQ(art_buf,"begin ", 6))) {
- uu_decode:
- printf("Extracting uuencoded file into %s:\n", s);
- extractprog = savestr("-");
- cnt = 0;
- fseek(artfp,(long)-strlen(art_buf)-NL_SIZE+1,1);
- savefrom = ftell(artfp);
- uud_start(s);
- uudecode(artfp);
- break;
- }
- else {
- if (cut_line(art_buf)) {
- savefrom = ftell(artfp);
- found_cut = TRUE;
- }
- else if (found_cut || ++cnt == 200) {
- break;
- }
- }
- }/* while */
- if (cnt) {
- if (!cmdstr)
- extractprog = savestr("-");
- printf("Unable to determine type of file.\n");
- }
- }/* 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);
- interp(cmd_buf, (sizeof cmd_buf), getval("PIPESAVER",PIPESAVER));
- /* then set up for command */
- 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 */
- }
- 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 (! index(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) &&
- (filestat.st_mode & S_IFDIR);
- 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 */
- if (index(c,'/')) { /* yikes, a '/' in the filename */
- 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") ? "nyq" : "ynq");
-
- sprintf(cmd_buf,
- "\nFile %s doesn't exist--\n use mailbox format? [%s] ",
- s,dflt);
- reask_save:
- in_char(cmd_buf, 'M');
- putchar('\n') FLUSH;
- setdef(buf,dflt);
- #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 (filestat.st_mode & S_IFCHR)
- mailbox = FALSE;
- else {
- int tmpfd;
-
- tmpfd = open(s,0);
- if (tmpfd == -1)
- mailbox = FALSE;
- else {
- read(tmpfd,buf,LBUFLEN);
- c = buf;
- if (!isspace(MBOXCHAR))
- while (isspace(*c))
- c++;
- mailbox = (*c == MBOXCHAR);
- close(tmpfd);
- }
- }
-
- safecpy(cmd_buf, filexp(mailbox ?
- getval("MBOXSAVER",MBOXSAVER) :
- getval("NORMSAVER",NORMSAVER) ), sizeof cmd_buf);
- /* format the command */
- resetty(); /* make terminal behave */
- if (doshell(use_pref?Nullch:SH,cmd_buf))
- fputs("Not saved",stdout);
- else
- 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 SERVER
- if (chdir(spool)) {
- #else /* not SERVER */
- if (chdir(spool) || chdir(ngdir)) {
- #endif /* SERVER */
- printf(nocd,ngdir) FLUSH;
- sig_catcher(0);
- }
- return SAVE_DONE;
- }
-
- int
- cancel_article()
- {
- char *artid_buf;
- 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\
- Cancelling 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);
- artid_buf = fetchlines(art,ARTID_LINE);
- ngs_buf = fetchlines(art,NGS_LINE);
- if (!instr(from_buf,sitename) ||
- (!instr(from_buf,logname) &&
- !instr(reply_buf,logname) &&
- #ifdef NEWSADMIN
- myuid != newsuid &&
- #endif
- myuid != ROOTID ) )
- #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(artid_buf);
- free(ngs_buf);
- free(from_buf);
- free(reply_buf);
- return r;
- }
-
- void
- reply()
- {
- bool incl_body = (*buf == 'R');
- char *maildoer = savestr(filexp(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"))
- #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);
- #ifdef ASYNC_PARSE
- parse_maybe(art);
- #endif
- fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
- while (fgets(buf,LBUFLEN,artfp) != Nullch) {
- fprintf(tmpfp,"%s%s",indstr,buf);
- }
- fprintf(tmpfp,"\n");
- }
- fclose(tmpfp);
- interp(cmd_buf, (sizeof cmd_buf), maildoer);
- invoke(cmd_buf,origdir);
- UNLINK(headname); /* kill the header file */
- no_reply:
- free(maildoer);
- }
-
- void
- followup()
- {
- bool incl_body = (*buf == 'F');
- char hbuf[4*LBUFLEN]; /* four times the old size */
-
- artopen(art);
- tmpfp = fopen(headname,"w");
- if (tmpfp == Nullfp) {
- printf(cantcreate,headname) FLUSH;
- 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);
- #ifdef ASYNC_PARSE
- parse_maybe(art);
- #endif
- fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
- while (fgets(buf,LBUFLEN,artfp) != Nullch) {
- fprintf(tmpfp,"%s%s",indstr,buf);
- }
- fprintf(tmpfp,"\n");
- }
- fclose(tmpfp);
- safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),sizeof cmd_buf);
- invoke(cmd_buf,origdir);
- UNLINK(headname);
- }
-
- void
- invoke(cmd,dir)
- char *cmd,*dir;
- {
- if (chdir(dir)) {
- printf(nocd,dir) FLUSH;
- return;
- }
- #ifdef VERBOSE
- IF(verbose)
- printf("\n(leaving cbreak mode; cwd=%s)\nInvoking command: %s\n\n",
- dir,cmd) FLUSH;
- ELSE
- #endif
- #ifdef TERSE
- printf("\n(-cbreak; cwd=%s)\nInvoking: %s\n\n",dir,cmd) FLUSH;
- #endif
- 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
- #ifdef SERVER
- if (chdir(spool)) {
- #else /* not SERVER */
- if (chdir(spool) || chdir(ngdir)) {
- #endif /* SERVER */
- 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;
-
- /* Disallow any single-/double-quoted, parenthetical or c-commented
- ** string lines. Make sure it has the cut-phrase and at least 20
- ** '-'s or '='s. If only four '-'s are present, check for a duplicate
- ** of the cut phrase. If we succeed, return TRUE.
- */
- for (cp = str, dash_cnt = equal_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;
- }
- }
- if (dash_cnt < 4 && equal_cnt < 20)
- 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"))
- return TRUE;
- break;
- case 1:
- if (!strcmp(word, "this"))
- got_flag = 2;
- if (!strcmp(word, "here")) {
- if (dash_cnt >= 20 || equal_cnt >= 20)
- return TRUE;
- dash_cnt = 20;
- got_flag = 0;
- }
- break;
- case 0:
- if (!strcmp( word, "cut")
- || !strcmp( word, "snip")
- || !strcmp( word, "tear"))
- got_flag = 1;
- break;
- }
- *(cp = word) = '\0';
- }
- }
- } /* for *str */
-
- return FALSE;
- }
-