home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / trn / part07 / respond.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-02  |  19.3 KB  |  827 lines

  1. /* $Id: respond.c,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
  2.  *
  3.  * $Log: respond.c,v $
  4.  * Revision 4.4.2.1  1991/12/01  18:05:42  sob
  5.  * Patchlevel 2 changes
  6.  *
  7.  * Revision 4.4.1.1  1991/09/25  19:38:08  sob
  8.  * Some adaptions for CNEWS
  9.  *
  10.  * Revision 4.4  1991/09/09  20:27:37  sob
  11.  * release 4.4
  12.  *
  13.  *
  14.  * 
  15.  */
  16. /* This software is Copyright 1991 by Stan Barber. 
  17.  *
  18.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  19.  * use this software as long as: there is no monetary profit gained
  20.  * specifically from the use or reproduction or this software, it is not
  21.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  22.  * included prominently in any copy made. 
  23.  *
  24.  * The author make no claims as to the fitness or correctness of this software
  25.  * for any use whatsoever, and it is provided as is. Any use of this software
  26.  * is at the user's own risk. 
  27.  */
  28.  
  29. #include "EXTERN.h"
  30. #include "common.h"
  31. #include "intrp.h"
  32. #include "head.h"
  33. #include "term.h"
  34. #include "ng.h"
  35. #include "util.h"
  36. #include "rn.h"
  37. #include "artio.h"
  38. #include "final.h"
  39. #include "bits.h"
  40. #include "decode.h"
  41. #include "INTERN.h"
  42. #include "respond.h"
  43.  
  44. static char nullart[] = "\nNull article\n";
  45.  
  46. void
  47. respond_init()
  48. {
  49.     ;
  50. }
  51.  
  52. int
  53. save_article()
  54. {
  55.     bool use_pref, cut_line();
  56.     register char *s, *c;
  57.     char altbuf[CBUFLEN];
  58.     int iter;
  59.     bool interactive = (buf[1] == FINISHCMD);
  60.     char cmd = *buf;
  61.     
  62.     if (!finish_command(interactive))    /* get rest of command */
  63.     return SAVE_ABORT;
  64.     if ((use_pref = isupper(cmd)) != 0)
  65.     cmd = tolower(cmd);
  66. #ifdef ASYNC_PARSE
  67.     parse_maybe(art);
  68. #endif
  69.     savefrom = (cmd == 'w' || cmd == 'e' ? htype[PAST_HEADER].ht_minpos : 0);
  70.     if (artopen(art) == Nullfp) {
  71. #ifdef VERBOSE
  72.     IF(verbose)
  73.         fputs("\n\
  74. Saving null articles is not very productive!  :-)\n\
  75. ",stdout) FLUSH;
  76.     ELSE
  77. #endif
  78. #ifdef TERSE
  79.         fputs(nullart,stdout) FLUSH;
  80. #endif
  81.     return SAVE_DONE;
  82.     }
  83.     if (chdir(cwd)) {
  84.     printf(nocd,cwd) FLUSH;
  85.     sig_catcher(0);
  86.     }
  87.     if (cmd == 'e') {        /* is this an extract command? */
  88.     static bool custom_extract = FALSE;
  89.     int cnt = 0;
  90.     bool found_cut = FALSE;
  91.     char art_buf[LBUFLEN], *cmdstr;
  92.  
  93.     s = buf+1;        /* skip e */
  94.     while (*s == ' ') s++;    /* skip leading spaces */
  95.     safecpy(altbuf,filexp(s),sizeof altbuf);
  96.     s = altbuf;
  97.     if (*s) {
  98.         cmdstr = cpytill(buf,s,'|');    /* check for | */
  99.         s = buf + strlen(buf)-1;
  100.         while (*s == ' ') s--;        /* trim trailing spaces */
  101.         *++s = '\0';
  102.         if (*cmdstr) {
  103.         s = cmdstr+1;            /* skip | */
  104.         while (*s == ' ') s++;
  105.         if (*s)    {            /* if new command, use it */
  106.             if (extractprog)
  107.             free(extractprog);
  108.             extractprog = savestr(s);    /* put extracter in %e */
  109.         }
  110.         else
  111.             cmdstr = extractprog;
  112.         }
  113.         else
  114.         cmdstr = Nullch;
  115.         s = buf;
  116.     }
  117.     else {
  118.         if (extractdest)
  119.         strcpy(s, extractdest);
  120.         if (custom_extract)
  121.         cmdstr = extractprog;
  122.         else
  123.         cmdstr = Nullch;
  124.     }
  125.     if (cmdstr) {
  126.         if (strEQ(extractprog,"-"))
  127.         cmdstr = Nullch;
  128.         else if (decode_fp != Nullfp)
  129.         decode_end();
  130.     }
  131.     custom_extract = (cmdstr != 0);
  132.  
  133.     fseek(artfp,savefrom,0);
  134.     if (*s != '/') {        /* relative path? */
  135.         c = (s==buf ? altbuf : buf);
  136.         interp(c, (sizeof buf), getval("SAVEDIR",SAVEDIR));
  137.         if (makedir(c,MD_DIR))    /* ensure directory exists */
  138.         strcpy(c,cwd);
  139.         if (*s) {
  140.         while (*c) c++;
  141.         *c++ = '/';
  142.         strcpy(c,s);        /* add filename */
  143.         }
  144.         s = (s==buf ? altbuf : buf);
  145.     }
  146.     if (*s != '/') {        /* path still relative? */
  147.         c = (s==buf ? altbuf : buf);
  148.         sprintf(c, "%s/%s", cwd, s);
  149.         s = c;            /* absolutize it */
  150.     }
  151.     if (decode_fp != Nullfp) {
  152.         printf("Continuing %s:%s\n", decode_fname,
  153.         cmd != '\0' && strNE(extractdest,s) ?
  154.          " (Ignoring conflicting directory)" : nullstr ) FLUSH;
  155.         if (decode_type == UUDECODE)
  156.         uudecode(artfp);
  157.         else
  158.         unship(artfp);
  159.     }
  160.     else {
  161.         if (extractdest)
  162.         free(extractdest);
  163.         s = extractdest = savestr(s); /* make it handy for %E */
  164.         if (makedir(s, MD_DIR)) {    /* ensure directory exists */
  165.         int_count++;
  166.         return SAVE_DONE;
  167.         }
  168.         if (chdir(s)) {
  169.         printf(nocd,s) FLUSH;
  170.         sig_catcher(0);
  171.         }
  172.         s = getwd(buf);        /* simplify path for output */
  173.         while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
  174.         if (*art_buf <= ' ')
  175.             continue;    /* Ignore empty or initially-whitespace lines */
  176.         if (found_cut && custom_extract) {
  177.             printf("Extracting data into %s using %s:\n",
  178.             s, extractprog) FLUSH;
  179.             goto extract_it;
  180.         }
  181.         if (((*art_buf == '#' || *art_buf == ':')
  182.           && (strnEQ(art_buf+1, "! /bin/sh", 9)
  183.            || strnEQ(art_buf+1, "!/bin/sh", 8)
  184.            || strnEQ(art_buf+2, "This is ", 8)))
  185.          || strnEQ(art_buf, "sed ", 4)
  186.          || strnEQ(art_buf, "cat ", 4)
  187.          || strnEQ(art_buf, "echo ", 5)) {
  188.             fseek(artfp,-(long)strlen(art_buf)-NL_SIZE+1,1);
  189.             savefrom = ftell(artfp);
  190.             if (custom_extract) {
  191.             printf("Extracting shar into %s using %s:\n",
  192.                 s, extractprog) FLUSH;
  193.             goto extract_it;
  194.             }
  195.             /* Check for special-case of shar'ed-uuencoded file */
  196.             while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
  197.             if (*art_buf == '#' || *art_buf == ':'
  198.              || strnEQ(art_buf, "echo ", 5)
  199.              || strnEQ(art_buf, "sed ", 4))
  200.                 continue;
  201.             if (strnEQ(art_buf, "Xbegin ", 7)) {
  202.                 decode_type = UUDECODE;
  203.                 goto decode_it;
  204.             }
  205.             break;
  206.             }
  207.             printf("Extracting shar into %s:\n", s) FLUSH;
  208.             if (extractprog)
  209.             free(extractprog);
  210.             extractprog = savestr(filexp(getval("UNSHAR",UNSHAR)));
  211.           extract_it:
  212.             cnt = 0;
  213.             interp(cmd_buf,(sizeof cmd_buf),getval("EXSAVER",EXSAVER));
  214.             termlib_reset();
  215.             resetty();        /* restore tty state */
  216.             doshell(SH,cmd_buf);
  217.             noecho();        /* revert to cbreaking */
  218.             crmode();
  219.             termlib_init();
  220.             break;
  221.         }
  222.         else
  223.         if (!custom_extract
  224.          && (strEQ(art_buf,"$\n")
  225.           || strEQ(art_buf,"$ f\n"))) {
  226.             savefrom = ftell(artfp)-strlen(art_buf)-NL_SIZE+1;
  227.             if (found_cut
  228.              || (fgets(art_buf,LBUFLEN,artfp) != Nullch
  229.               && (strnEQ(art_buf, "ship ", 5)
  230.                || strnEQ(art_buf, "cont ", 5)))) {
  231.             decode_type = UNSHIP;
  232.             goto decode_it;
  233.             }
  234.         }
  235.         else
  236.         if (!custom_extract
  237.          && (strEQ(art_buf,"table\n")
  238.           || strnEQ(art_buf,"begin ", 6))) {
  239.             decode_type = UUDECODE;
  240.             savefrom = ftell(artfp)-strlen(art_buf)-NL_SIZE+1;
  241.          decode_it:
  242.             printf("Extracting %s file into %s:\n",
  243.             decode_type == UNSHIP? "shipped":"uuencoded", s) FLUSH;
  244.             if (extractprog)
  245.             free(extractprog);
  246.             extractprog = savestr("-");
  247.             fseek(artfp, savefrom, 0);
  248.             cnt = 0;
  249.             if (decode_type == UUDECODE) {
  250.             uud_start();
  251.             uudecode(artfp);
  252.             } else
  253.             unship(artfp);
  254.             break;
  255.         }
  256.         else {
  257.             if (cut_line(art_buf)) {
  258.             savefrom = ftell(artfp);
  259.             found_cut = TRUE;
  260.             }
  261.             else if (found_cut || ++cnt == 300) {
  262.             break;
  263.             }
  264.         }
  265.         }/* while */
  266.         if (cnt) {
  267.         if (custom_extract)
  268.             printf("Didn't find cut line for extraction to '%s'.\n",
  269.             extractprog) FLUSH;
  270.         else
  271.             printf("Unable to determine type of file.\n") FLUSH;
  272.         }
  273.     }/* if */
  274.     }
  275.     else if ((s = index(buf,'|')) != Nullch) {
  276.                 /* is it a pipe command? */
  277.     s++;            /* skip the | */
  278.     while (*s == ' ') s++;
  279.     safecpy(altbuf,filexp(s),sizeof altbuf);
  280.     if (savedest)
  281.         free(savedest);
  282.     savedest = savestr(altbuf);
  283.     interp(cmd_buf, (sizeof cmd_buf), getval("PIPESAVER",PIPESAVER));
  284.                 /* then set up for command */
  285.     termlib_reset();
  286.     resetty();        /* restore tty state */
  287.     if (use_pref)        /* use preferred shell? */
  288.         doshell(Nullch,cmd_buf);
  289.                 /* do command with it */
  290.     else
  291.         doshell(sh,cmd_buf);    /* do command with sh */
  292.     noecho();        /* and stop echoing */
  293.     crmode();        /* and start cbreaking */
  294.     termlib_init();
  295.     }
  296.     else {            /* normal save */
  297.     bool there, mailbox;
  298.     char *savename = getval("SAVENAME",SAVENAME);
  299.  
  300.     s = buf+1;        /* skip s or S */
  301.     if (*s == '-') {    /* if they are confused, skip - also */
  302. #ifdef VERBOSE
  303.         IF(verbose)
  304.         fputs("Warning: '-' ignored.  This isn't readnews.\n",stdout)
  305.           FLUSH;
  306.         ELSE
  307. #endif
  308. #ifdef TERSE
  309.         fputs("'-' ignored.\n",stdout) FLUSH;
  310. #endif
  311.         s++;
  312.     }
  313.     for (; *s == ' '; s++);    /* skip spaces */
  314.     safecpy(altbuf,filexp(s),sizeof altbuf);
  315.     s = altbuf;
  316.     if (! index(s,'/')) {
  317.         interp(buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
  318.         if (makedir(buf,MD_DIR))    /* ensure directory exists */
  319.         strcpy(buf,cwd);
  320.         if (*s) {
  321.         for (c = buf; *c; c++) ;
  322.         *c++ = '/';
  323.         strcpy(c,s);        /* add filename */
  324.         }
  325.         s = buf;
  326.     }
  327.     for (iter = 0;
  328.         (there = stat(s,&filestat) >= 0) &&
  329.         (filestat.st_mode & S_IFDIR);
  330.         iter++) {            /* is it a directory? */
  331.  
  332.         c = (s+strlen(s));
  333.         *c++ = '/';            /* put a slash before filename */
  334.         interp(c, s==buf?(sizeof buf):(sizeof altbuf),
  335.         iter ? "News" : savename );
  336.                 /* generate a default name somehow or other */
  337.     }
  338.     makedir(s,MD_FILE);
  339.     if (*s != '/') {        /* relative path? */
  340.         c = (s==buf ? altbuf : buf);
  341.         sprintf(c, "%s/%s", cwd, s);
  342.         s = c;            /* absolutize it */
  343.     }
  344.     if (savedest)
  345.         free(savedest);
  346.     s = savedest = savestr(s);    /* doesn't move any more */
  347.                     /* make it handy for %b */
  348.     if (!there) {
  349.         if (mbox_always)
  350.         mailbox = TRUE;
  351.         else if (norm_always)
  352.         mailbox = FALSE;
  353.         else {
  354.         char *dflt = (instr(savename,"%a", TRUE) ? "nyq" : "ynq");
  355.         
  356.         sprintf(cmd_buf,
  357.         "\nFile %s doesn't exist--\n    use mailbox format? [%s] ",
  358.           s,dflt);
  359.           reask_save:
  360.         in_char(cmd_buf, 'M');
  361.         putchar('\n') FLUSH;
  362.         setdef(buf,dflt);
  363. #ifdef VERIFY
  364.         printcmd();
  365. #endif
  366.         if (*buf == 'h') {
  367. #ifdef VERBOSE
  368.             IF(verbose)
  369.             printf("\n\
  370. Type y to create %s as a mailbox.\n\
  371. Type n to create it as a normal file.\n\
  372. Type q to abort the save.\n\
  373. ",s) FLUSH;
  374.             ELSE
  375. #endif
  376. #ifdef TERSE
  377.             fputs("\n\
  378. y to create mailbox.\n\
  379. n to create normal file.\n\
  380. q to abort.\n\
  381. ",stdout) FLUSH;
  382. #endif
  383.             goto reask_save;
  384.         }
  385.         else if (*buf == 'n') {
  386.             mailbox = FALSE;
  387.         }
  388.         else if (*buf == 'y') {
  389.             mailbox = TRUE;
  390.         }
  391.         else if (*buf == 'q') {
  392.             goto s_bomb;
  393.         }
  394.         else {
  395.             fputs(hforhelp,stdout) FLUSH;
  396.             settle_down();
  397.             goto reask_save;
  398.         }
  399.         }
  400.     }
  401.     else if (filestat.st_mode & S_IFCHR)
  402.         mailbox = FALSE;
  403.     else {
  404.         int tmpfd;
  405.         
  406.         tmpfd = open(s,0);
  407.         if (tmpfd == -1)
  408.         mailbox = FALSE;
  409.         else {
  410.         if (read(tmpfd,buf,LBUFLEN)) {
  411.             c = buf;
  412.             if (!isspace(MBOXCHAR))   /* if non-zero, */
  413.             while (isspace(*c))   /* check the first character */
  414.                 c++;
  415.             mailbox = (*c == MBOXCHAR);
  416.         } else {
  417.             mailbox = mbox_always;    /* if zero length, recheck -M */
  418.         }
  419.         close(tmpfd);
  420.         }
  421.     }
  422.  
  423.     safecpy(cmd_buf, filexp(mailbox ?
  424.         getval("MBOXSAVER",MBOXSAVER) :
  425.         getval("NORMSAVER",NORMSAVER) ), sizeof cmd_buf);
  426.                 /* format the command */
  427.     termlib_reset();
  428.     resetty();        /* make terminal behave */
  429.     if (doshell(use_pref?Nullch:SH,cmd_buf)) {
  430.         termlib_init();
  431.         fputs("Not saved",stdout);
  432.     } else {
  433.         termlib_init();
  434.         printf("%s to %s %s",
  435.           there?"Appended":"Saved",
  436.           mailbox?"mailbox":"file",
  437.           s);
  438.     }
  439.     if (interactive)
  440.         putchar('\n') FLUSH;
  441.     noecho();        /* make terminal do what we want */
  442.     crmode();
  443.     }
  444. s_bomb:
  445. #ifdef SERVER
  446.     if (chdir(spool)) {
  447. #else /* not SERVER */
  448.     if (chdir(spool) || chdir(ngdir)) {
  449. #endif /* SERVER */
  450.     printf(nocd,ngdir) FLUSH;
  451.     sig_catcher(0);
  452.     }
  453.     return SAVE_DONE;
  454. }
  455.  
  456. int
  457. cancel_article()
  458. {
  459.     char *artid_buf;
  460.     char *ngs_buf;
  461.     char *from_buf;
  462.     char *reply_buf;
  463.     int myuid = getuid();
  464.     int r = -1;
  465.  
  466.     if (artopen(art) == Nullfp) {
  467. #ifdef VERBOSE
  468.     IF(verbose)
  469.         fputs("\n\
  470. Cancelling null articles is your idea of fun?  :-)\n\
  471. ",stdout) FLUSH;
  472.     ELSE
  473. #endif
  474. #ifdef TERSE
  475.         fputs(nullart,stdout) FLUSH;
  476. #endif
  477.     return r;
  478.     }
  479.     reply_buf = fetchlines(art,REPLY_LINE);
  480.     from_buf = fetchlines(art,FROM_LINE);
  481.     artid_buf = fetchlines(art,ARTID_LINE);
  482.     ngs_buf = fetchlines(art,NGS_LINE);
  483.     if (!instr(from_buf,sitename,FALSE) ||
  484.     (!instr(from_buf,logname,TRUE) &&
  485.      !instr(reply_buf,logname,TRUE) &&
  486. #ifdef NEWSADMIN
  487.      myuid != newsuid &&
  488. #endif
  489.      myuid != ROOTID ) ) {
  490. #ifdef DEBUGGING
  491.         if (debug)
  492.         printf("\n%s@%s != %s\n",logname,sitename,from_buf) FLUSH;
  493. #endif
  494. #ifdef VERBOSE
  495.         IF(verbose)
  496.         fputs("\nYou can't cancel someone else's article\n",stdout)
  497.           FLUSH;
  498.         ELSE
  499. #endif
  500. #ifdef TERSE
  501.         fputs("\nNot your article\n",stdout) FLUSH;
  502. #endif
  503.     }
  504.     else {
  505.     tmpfp = fopen(headname,"w");    /* open header file */
  506.     if (tmpfp == Nullfp) {
  507.         printf(cantcreate,headname) FLUSH;
  508.         goto no_cancel;
  509.     }
  510.     interp(buf, (sizeof buf), getval("CANCELHEADER",CANCELHEADER));
  511.     fputs(buf,tmpfp);
  512.     fclose(tmpfp);
  513.     fputs("\nCanceling...\n",stdout) FLUSH;
  514.     r = doshell(sh,filexp(getval("CANCEL",CANCEL)));
  515.     }
  516. no_cancel:
  517.     free(artid_buf);
  518.     free(ngs_buf);
  519.     free(from_buf);
  520.     free(reply_buf);
  521.     return r;
  522. }
  523.  
  524. int
  525. supersede_article()        /* Supersedes: */
  526. {
  527.     char *artid_buf;
  528.     char *ngs_buf;
  529.     char *from_buf;
  530.     char *reply_buf;
  531.     int myuid = getuid();
  532.     int r = -1;
  533.  
  534.     if (artopen(art) == Nullfp) {
  535. #ifdef VERBOSE
  536.     IF(verbose)
  537.         fputs("\n\
  538. Superceding null articles is your idea of fun?  :-)\n\
  539. ",stdout) FLUSH;
  540.     ELSE
  541. #endif
  542. #ifdef TERSE
  543.         fputs(nullart,stdout) FLUSH;
  544. #endif
  545.     return r;
  546.     }
  547.     reply_buf = fetchlines(art,REPLY_LINE);
  548.     from_buf = fetchlines(art,FROM_LINE);
  549.     artid_buf = fetchlines(art,ARTID_LINE);
  550.     ngs_buf = fetchlines(art,NGS_LINE);
  551.     if (!instr(from_buf,sitename,FALSE) ||
  552.     (!instr(from_buf,logname,TRUE) &&
  553.      !instr(reply_buf,logname,TRUE) &&
  554. #ifdef NEWSADMIN
  555.      myuid != newsuid &&
  556. #endif
  557.      myuid != ROOTID ) ) {
  558. #ifdef DEBUGGING
  559.         if (debug)
  560.         printf("\n%s@%s != %s\n",logname,sitename,from_buf) FLUSH;
  561. #endif
  562. #ifdef VERBOSE
  563.         IF(verbose)
  564.         fputs("\nYou can't supersede someone else's article\n",stdout)
  565.           FLUSH;
  566.         ELSE
  567. #endif
  568. #ifdef TERSE
  569.         fputs("\nNot your article\n",stdout) FLUSH;
  570. #endif
  571.     }
  572.     else {
  573.     tmpfp = fopen(headname,"w");    /* open header file */
  574.     if (tmpfp == Nullfp) {
  575.         printf(cantcreate,headname) FLUSH;
  576.         goto no_commute;
  577.     }
  578.     interp(buf, (sizeof buf), getval("SUPERSEDEHEADER",SUPERSEDEHEADER));
  579.     fputs(buf,tmpfp);
  580.     fclose(tmpfp);
  581.         safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),
  582.         sizeof cmd_buf);
  583.         invoke(cmd_buf,origdir);
  584.     r = 0;
  585.     }
  586. no_commute:
  587.     free(artid_buf);
  588.     free(ngs_buf);
  589.     free(from_buf);
  590.     free(reply_buf);
  591.     return r;
  592. }
  593.  
  594. void
  595. reply()
  596. {
  597.     bool incl_body = (*buf == 'R');
  598.     char *maildoer = savestr(filexp(getval("MAILPOSTER",MAILPOSTER)));
  599.  
  600.     artopen(art);
  601.     tmpfp = fopen(headname,"w");    /* open header file */
  602.     if (tmpfp == Nullfp) {
  603.     printf(cantcreate,headname) FLUSH;
  604.     goto no_reply;
  605.     }
  606.     interp(buf, (sizeof buf), getval("MAILHEADER",MAILHEADER));
  607.     fputs(buf,tmpfp);
  608.     if (!instr(maildoer,"%h",TRUE))
  609. #ifdef VERBOSE
  610.     IF(verbose)
  611.         printf("\n%s\n(Above lines saved in file %s)\n",buf,headname)
  612.           FLUSH;
  613.     ELSE
  614. #endif
  615. #ifdef TERSE
  616.         printf("\n%s\n(Header in %s)\n",buf,headname) FLUSH;
  617. #endif
  618.     if (incl_body && artfp != Nullfp) {
  619.     interp(buf, (sizeof buf), getval("YOUSAID",YOUSAID));
  620.     fprintf(tmpfp,"%s\n",buf);
  621. #ifdef ASYNC_PARSE
  622.     parse_maybe(art);
  623. #endif
  624.     fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
  625.     while (fgets(buf,LBUFLEN,artfp) != Nullch) {
  626.         fprintf(tmpfp,"%s%s",indstr,buf);
  627.     }
  628.     fprintf(tmpfp,"\n");
  629.     }
  630.     fclose(tmpfp);
  631.     interp(cmd_buf, (sizeof cmd_buf), maildoer);
  632.     invoke(cmd_buf,origdir);
  633.     UNLINK(headname);        /* kill the header file */
  634. no_reply:
  635.     free(maildoer);
  636. }
  637.  
  638. void
  639. followup()
  640. {
  641.     bool incl_body = (*buf == 'F');
  642.     char hbuf[4*LBUFLEN];    /* four times the old size */
  643.     ART_NUM oldart = art;
  644.  
  645.     if (!incl_body && art <= lastart) {
  646.     in_char("\n\nAre you starting an unrelated topic? [yn] ", 'F');
  647.     setdef(buf,"y");
  648.     if (*buf != 'n')
  649.         art = lastart + 1;
  650.     }
  651.     artopen(art);
  652.     tmpfp = fopen(headname,"w");
  653.     if (tmpfp == Nullfp) {
  654.     printf(cantcreate,headname) FLUSH;
  655.     art = oldart;
  656.     return;
  657.     }
  658.     interp(hbuf, (sizeof hbuf), getval("NEWSHEADER",NEWSHEADER));
  659.     fprintf(tmpfp,"%s",hbuf);
  660.     if (incl_body && artfp != Nullfp) {
  661. #ifdef VERBOSE
  662.     if (verbose)
  663.         fputs("\n\
  664. (Be sure to double-check the attribution against the signature, and\n\
  665. trim the quoted article down as much as possible.)\n\
  666. ",stdout) FLUSH;
  667. #endif
  668.     interp(buf, (sizeof buf), getval("ATTRIBUTION",ATTRIBUTION));
  669.     fprintf(tmpfp,"%s\n",buf);
  670. #ifdef ASYNC_PARSE
  671.     parse_maybe(art);
  672. #endif
  673.     fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
  674.     while (fgets(buf,LBUFLEN,artfp) != Nullch) {
  675.         fprintf(tmpfp,"%s%s",indstr,buf);
  676.     }
  677.     fprintf(tmpfp,"\n");
  678.     }
  679.     fclose(tmpfp);
  680.     safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),sizeof cmd_buf);
  681.     invoke(cmd_buf,origdir);
  682.     UNLINK(headname);
  683.     art = oldart;
  684. }
  685.  
  686. void
  687. invoke(cmd,dir)
  688. char *cmd,*dir;
  689. {
  690.     if (chdir(dir)) {
  691.     printf(nocd,dir) FLUSH;
  692.     return;
  693.     }
  694.     termlib_reset();
  695. #ifdef VERBOSE
  696.     IF(verbose)
  697.     printf("\n(leaving cbreak mode; cwd=%s)\nInvoking command: %s\n\n",
  698.         dir,cmd) FLUSH;
  699.     ELSE
  700. #endif
  701. #ifdef TERSE
  702.     printf("\n(-cbreak; cwd=%s)\nInvoking: %s\n\n",dir,cmd) FLUSH;
  703. #endif
  704.     resetty();            /* make terminal well-behaved */
  705.     doshell(sh,cmd);        /* do the command */
  706.     noecho();            /* set no echo */
  707.     crmode();            /* and cbreak mode */
  708. #ifdef VERBOSE
  709.     IF(verbose)
  710.     fputs("\n(re-entering cbreak mode)\n",stdout) FLUSH;
  711.     ELSE
  712. #endif
  713. #ifdef TERSE
  714.     fputs("\n(+cbreak)\n",stdout) FLUSH;
  715. #endif
  716.     termlib_init();
  717. #ifdef SERVER
  718.     if (chdir(spool)) {
  719. #else /* not SERVER */
  720.     if (chdir(spool) || chdir(ngdir)) {
  721. #endif /* SERVER */
  722.     printf(nocd,ngdir) FLUSH;
  723.     sig_catcher(0);
  724.     }
  725. }
  726.  
  727. /*
  728. ** cut_line() determines if a line is meant as a "cut here" marker.
  729. ** Some examples that we understand:
  730. **
  731. **  BEGIN--cut here--cut here
  732. **
  733. **  ------------------ tear at this line ------------------
  734. **
  735. **  #----cut here-----cut here-----cut here-----cut here----#
  736. */
  737. bool
  738. cut_line(str)
  739. char *str;
  740. {
  741.     char *cp, got_flag;
  742.     char word[80];
  743.     int  dash_cnt, equal_cnt, other_cnt;
  744.  
  745.     /* Disallow any single-/double-quoted, parenthetical or c-commented
  746.     ** string lines.  Make sure it has the cut-phrase and at least six
  747.     ** '-'s or '='s.  If only four '-'s are present, check for a duplicate
  748.     ** of the cut phrase.  If over 20 unknown characters are encountered,
  749.     ** assume it isn't a cut line.  If we succeed, return TRUE.
  750.     */
  751.     for (cp = str, dash_cnt = equal_cnt = other_cnt = 0; *cp; cp++) {
  752.     switch (*cp) {
  753.     case '-':
  754.         dash_cnt++;
  755.         break;
  756.     case '=':
  757.         equal_cnt++;
  758.         break;
  759.     case '/':
  760.         if(*(cp+1) != '*') {
  761.         break;
  762.         }
  763.     case '"':
  764.     case '\'':
  765.     case '(':
  766.     case ')':
  767.     case '[':
  768.     case ']':
  769.     case '{':
  770.     case '}':
  771.         return FALSE;
  772.     default:
  773.         other_cnt++;
  774.         break;
  775.     }
  776.     }
  777.     if (dash_cnt < 4 && equal_cnt < 6)
  778.     return FALSE;
  779.  
  780.     got_flag = 0;
  781.  
  782.     for (*(cp = word) = '\0'; *str; str++) {
  783.     if (islower(*str))
  784.         *cp++ = *str;
  785.     else if (isupper(*str))
  786.         *cp++ = tolower(*str);
  787.     else {
  788.         if (*word) {
  789.         *cp = '\0';
  790.         switch (got_flag) {
  791.         case 2:
  792.             if (!strcmp(word, "line")
  793.              || !strcmp(word, "here"))
  794.             if ((other_cnt -= 4) <= 20)
  795.                 return TRUE;
  796.             break;
  797.         case 1:
  798.             if (!strcmp(word, "this")) {
  799.             got_flag = 2;
  800.             other_cnt -= 4;
  801.             }
  802.             else if (!strcmp(word, "here")) {
  803.             other_cnt -= 4;
  804.             if ((dash_cnt >= 6 || equal_cnt >= 6)
  805.              && other_cnt <= 20)
  806.                 return TRUE;
  807.             dash_cnt = 6;
  808.             got_flag = 0;
  809.             }
  810.             break;
  811.         case 0:
  812.             if (!strcmp(word, "cut")
  813.              || !strcmp(word, "snip")
  814.              || !strcmp(word, "tear")) {
  815.             got_flag = 1;
  816.             other_cnt -= strlen(word);
  817.             }
  818.             break;
  819.         }
  820.         *(cp = word) = '\0';
  821.         }
  822.     }
  823.     } /* for *str */
  824.  
  825.     return FALSE;
  826. }
  827.