home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume14 / vn.nntp.pch / std.c < prev   
C/C++ Source or Header  |  1988-04-19  |  32KB  |  1,714 lines

  1. #include <stdio.h>
  2. #include <pwd.h>
  3. #include <ctype.h>
  4. #include <sys/param.h>
  5. #ifdef NNTP
  6. #include <response_codes.h>
  7. #endif
  8. #include "server.h"
  9. #include "config_std.h"
  10. #include "std.h"
  11.  
  12. #ifndef MAXPATHLEN
  13. #define MAXPATHLEN 240
  14. #endif
  15.  
  16. extern NODE *hashfind();
  17. extern FILE *fopen();
  18. extern char *index(), *rindex();
  19. extern char *malloc();
  20. extern char *str_tstore(), *str_tpool(), *str_store();
  21. extern char *strtok(), *strpbrk();
  22. extern char *regex(), *regcmp();
  23.  
  24. #ifdef MAILCHOOSE
  25. extern int (*Massage)();
  26. #endif
  27.  
  28. /*
  29.     global flags signifying options set
  30. */
  31. #define GF_ALL 1    /* -x option - scan everything */
  32. #define GF_SPEC 2    /* -n option(s) - user specified groups */
  33. #define GF_OVER 4    /* command line specification - overide marks */
  34.  
  35. #ifdef NNTP
  36. char *nntp_get();
  37. static char *Machine;
  38. static char *Fmach;
  39. char *Vns_version = "nntp1.2";
  40. static FILE *Fp_trace = NULL;
  41. extern int (*Postfunc)();
  42. static int Server_open = 0;
  43. #else
  44. char *Vns_version = "res1.2";
  45. #endif
  46.  
  47. static char *Home;
  48. static char *Username, *Userdesc;
  49. static char *Onews, *Newsrc;
  50. static int Ntopt, Nntopt, Nwopt, Nnwopt;
  51.  
  52. static char *Wopt[NUMFILTER];        /* regular expressions for -w options */
  53. static char *Topt[NUMFILTER];        /* for -t options */
  54. static char *Negwopt[NUMFILTER];    /* for negated -w options */
  55. static char *Negtopt[NUMFILTER];    /* for negated -t options */
  56.  
  57. static char *Options[OPTLINES];
  58. static int Max_name, Optlines;
  59. static unsigned Gflags = 0;
  60. static char **Active;
  61. static int Actnum;
  62. static char *Mailer, *Poster;
  63.  
  64. static char *RT_head = RTHEAD;
  65. static char *P_head = PHEAD;
  66. static char *M_head = MHEAD;
  67. static char *R_head = RHEAD;
  68. static char *TO_head = TOHEAD;
  69. static char *F_head = FHEAD;
  70. static char *FT_head = FTHEAD;
  71. static char *T_head = THEAD;
  72. static char *DIS_head = DISHEAD;
  73. static char *L_head = LHEAD;
  74. static char *N_head = NHEAD;
  75.  
  76. static char *Fpfix = FPFIX;
  77.  
  78. /*
  79. **    environment setup.
  80. */
  81. vns_envir()
  82. {
  83.      char dbuf[MAXPATHLEN], *rcname;
  84.     char *vn_env();
  85.     struct passwd *ptr, *getpwuid();
  86.     char *machine;
  87. #ifdef NNTP
  88. #ifndef SHOW_FROM
  89.     int nntp_post();
  90. #endif
  91. #endif
  92. #ifdef MAILCHOOSE
  93.     int mail_prompt();
  94.  
  95.     Massage = mail_prompt;
  96. #endif
  97.  
  98.     ptr = getpwuid (getuid());
  99.     Home = str_store(ptr->pw_dir);
  100.     Username = str_store(ptr->pw_name);
  101.     Userdesc = str_store(ptr->pw_gecos);
  102.  
  103. #ifdef NNTP
  104.     Machine = vn_env("VNMACHINE",DEF_MACHINE);
  105. #ifndef SHOW_FROM
  106.     Postfunc = nntp_post;
  107. #endif
  108. #endif
  109.  
  110.     rcname = vn_env("MAILER",DEF_MAIL);
  111. #ifdef INLETTER
  112.     sprintf(dbuf,"cat %%s | %s",rcname);
  113. #else
  114.     /* used as a format string TWICE (%%%% -> %% -> %) */
  115.     sprintf(dbuf,"cat %%%%s | %s %%s",rcname);
  116. #endif
  117.     Mailer = str_store(dbuf);
  118.  
  119.     rcname = vn_env("NEWSRC",DEF_NEWSRC);
  120.     if (*rcname != '/')
  121.     {
  122.         sprintf (dbuf, "%s/%s",Home,rcname);
  123.         Newsrc = str_store (dbuf);
  124.     }
  125.     else
  126.         Newsrc = str_store (rcname);
  127. }
  128.  
  129. /*
  130.     change directory to group
  131. */
  132. vns_gset(grp)
  133. char *grp;
  134. {
  135.     char dbuf [RECLEN];
  136.  
  137. #ifdef NNTP
  138.     if (Machine != NULL)
  139.     {
  140.         sprintf(dbuf,"group %s",grp);
  141.         if (nntp_put(dbuf,dbuf) < 0)
  142.             printex("can't find newsgroup (server: %s)",dbuf);
  143.         return;
  144.     }
  145. #endif
  146.     g_dir (grp,dbuf);
  147.     if (chdir(dbuf) < 0)
  148.         printex("can't change to newsgroup directory");
  149. }
  150.  
  151. /*
  152.     g_dir converts newsgroup name to directory string
  153. */
  154. static
  155. g_dir(s,t)
  156. char *s,*t;
  157. {
  158.     char *ptr;
  159.     sprintf (t,"%s/%s",SPOOLDIR,s);
  160.     for (ptr=t+strlen(SPOOLDIR)+1; (ptr = index(ptr,'.')) != NULL; *ptr = '/')
  161.         ;
  162. }
  163.  
  164. /*
  165. ** myfind is used for hashfind() calls which aren't supposed to fail.
  166. */
  167. static NODE *
  168. myfind(name)
  169. char *name;
  170. {
  171.     NODE *n;
  172.  
  173.     n = hashfind(name);
  174.     if (n == NULL)
  175.         printex("Unexpected table lookup failure");
  176.     return (n);
  177. }
  178.  
  179. vns_news(argc,argv,lfirst,nun)
  180. int argc;
  181. char **argv;
  182. int *lfirst, *nun;
  183. {
  184.     FILE *fp;
  185.     static char marks[] =
  186.     { 
  187.         NEWS_ON, NEWS_OFF, '\0' 
  188.     };
  189.     int line, len, num;
  190.     char buf [RECLEN], trail, submark, *fret, *ptr;
  191.     int optpflag;
  192.  
  193.     ++argv;
  194.     --argc;
  195.  
  196.     /*
  197.     ** get .newsrc / server connection affecting options before 
  198.     ** calling fill_active.
  199.     */
  200.     arg_opt(argc,argv);
  201.  
  202.     /*
  203.     ** fill table with active newsgroups - initiates server connection
  204.     ** if we're talking to NNTP.
  205.     */
  206.     fill_active ();
  207.  
  208.     /*
  209.     ** handle options, now that fill_active has been called.
  210.     ** Set GF_OVER before calling newsrc_opt, since -S may override it.
  211.     */
  212.     if (Optlines > 0)
  213.     {
  214.         optpflag = 1;
  215.         Gflags |= GF_OVER;
  216.         newsrc_opt(lfirst,nun);
  217.     }
  218.     else
  219.         optpflag = 0;
  220.  
  221.     if ((fp = fopen (Newsrc,"r")) == NULL)
  222.         printex ("can't open %s for reading",Newsrc);
  223.  
  224.     Optlines = 0;
  225.  
  226.     for (line = 1; (fret = fgets(buf,RECLEN-1,fp)) != NULL && emptyline(buf) == 1; ++line)
  227.         ;
  228.     if (fret != NULL && strncmp (buf,"options",7) == 0)
  229.     {
  230.         Options[0] = str_store(buf);
  231.         Optlines = 1;
  232.         trail = buf [strlen(buf)-2];
  233.         for ( ; (fret = fgets(buf,RECLEN-1,fp)) != NULL; ++line)
  234.         {
  235.             if (trail != '\\' && buf[0] != ' ' && buf[0] != '\t')
  236.                 break;
  237.             if (Optlines >= OPTLINES)
  238.                 printex ("%s - too many option lines (%d allowed)",Newsrc,OPTLINES);
  239.             Options[Optlines] = str_store(buf);
  240.             ++Optlines;
  241.             if ((len = strlen(buf)) >= 2 && buf[len-2] != '\\')
  242.                 trail = buf[len-2];
  243.             else
  244.                 trail = '\0';
  245.         }
  246.     }
  247.  
  248.     /* do the options from the newsrc file if there weren't command line args */
  249.     if (Optlines > 0 && ! optpflag )
  250.         newsrc_opt (lfirst,nun);
  251.  
  252.     for ( ; fret != NULL; ++line, fret = fgets(buf,RECLEN-1,fp))
  253.     {
  254.         if (emptyline(buf) == 1)
  255.             continue;
  256.         if ((ptr = strpbrk(buf,marks)) == NULL)
  257.         {
  258.             fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
  259.             line,Newsrc,buf);
  260.             continue;
  261.         }
  262.         submark = *ptr;
  263.         *ptr = '\0';
  264.         ++ptr;
  265.         num = 0;
  266.         for (ptr = strtok(ptr," ,-\n"); ptr != NULL; ptr = strtok(NULL," ,-\n"))
  267.         {
  268.             len = atoi (ptr);
  269.             for ( ; *ptr >= '0' && *ptr <= '9'; ++ptr)
  270.                 ;
  271.             if (*ptr != '\0' || len < num)
  272.             {
  273.                 num = -1;
  274.                 fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
  275.                 line,Newsrc,buf);
  276.                 break;
  277.             }
  278.             num = len;
  279.         }
  280.         if (num < 0)
  281.             continue;
  282.         chkgroup (buf,submark,num,0);
  283.     }
  284.     fclose (fp);
  285.  
  286.     /* now take care of groups not specified in .newsrc */
  287.     art_active();
  288.  
  289.     /* free up the option string storage */
  290.     for (num=0; num < Ntopt; ++num)
  291.         regfree (Topt[num]);
  292.     for (num=0; num < Nwopt; ++num)
  293.         regfree (Wopt[num]);
  294.     for (num=0; num < Nntopt; ++num)
  295.         regfree (Negtopt[num]);
  296.     for (num=0; num < Nnwopt; ++num)
  297.         regfree (Negwopt[num]);
  298.     Ntopt = Nwopt = Nntopt = Nnwopt = 0;
  299.  
  300.     /* free the active list */
  301.     free ((char *) Active);
  302. }
  303.  
  304. static
  305. emptyline(s)
  306. char *s;
  307. {
  308.     while (isspace(*s))
  309.         ++s;
  310.     if (*s == '\0')
  311.         return (1);
  312.     return (0);
  313. }
  314.  
  315. /*
  316.     fill hash table from active news group list
  317.     This is needed to be able to process options
  318.     before scanning user order.  Constructs an array
  319.     of active newsgroup names for the rest of vns_nws().
  320. */
  321. static
  322. fill_active ()
  323. {
  324.     FILE *f;
  325.     char *nread, act_rec[RECLEN];
  326.     int num,lownum,rcount;
  327.     char *(*getfn)();
  328.  
  329.     Max_name = 0;
  330.  
  331. #ifdef NNTP
  332.     if (Machine != NULL)
  333.     {
  334.         if (server_init(Machine) < 0)
  335.         {
  336.             printex ("Cannot connect to NNTP server on %s",Machine);
  337.         }
  338.         Server_open = 1;
  339.         getfn = nntp_get;
  340.         if (nntp_put("list",act_rec) < 0)
  341.             printex ("Couldn't get newsgroup list (server: %s)",act_rec);
  342.     }
  343.     else
  344.     {
  345.         getfn = fgets;
  346.         if ((f = fopen (ACTFILE,"r")) == NULL)
  347.             printex ("couldn't open %s\n",ACTFILE);
  348.     }
  349. #else
  350.     getfn = fgets;
  351.     if ((f = fopen (ACTFILE,"r")) == NULL)
  352.         printex ("couldn't open %s\n",ACTFILE);
  353. #endif
  354.  
  355.     /*
  356.     ** we do things this way so that we only examine active records
  357.     ** once, minimizing the window where changes could screw us up
  358.     ** at the cost of possibly alloc'ing a few extra bytes.  We start
  359.     ** with a count of one to have a positive rcount for alloc.
  360.     */
  361.     for(rcount=1; (*getfn)(act_rec, RECLEN-1, f) != NULL; ++rcount)
  362.         ;
  363.     if ((Active = (char **) malloc(rcount*sizeof(char *))) == NULL)
  364.         printex("Memory allocation failure");
  365.  
  366. #ifdef NNTP
  367.     if (Machine != NULL)
  368.     {
  369.         if (nntp_put("list",act_rec) < 0)
  370.             printex ("Couldn't re-get newsgroup list (server: %s)",act_rec);
  371.     }
  372.     else
  373.         rewind(f);
  374. #else
  375.     rewind(f);
  376. #endif
  377.  
  378.     Actnum = 0;
  379.     while (Actnum < rcount && (*getfn)(act_rec, RECLEN-1, f) != NULL)
  380.     {
  381.         if (strtok (act_rec," \n") == NULL)
  382.             continue;
  383.         nread = strtok (NULL, " \n");
  384.         if (nread != NULL)
  385.             num = atoi(nread);
  386.         else
  387.             num = 0;
  388.         nread = strtok (NULL, " \n");
  389.         if (nread != NULL)
  390.             lownum = atoi(nread);
  391.         else
  392.             lownum = 0;
  393.         if (lownum > 0)
  394.             --lownum;
  395.         if (strlen(act_rec) > Max_name)
  396.             Max_name = strlen(act_rec);
  397.  
  398.         /* enter newsgroup, point to permanent copy of name */
  399.         hashenter (act_rec, num, lownum);
  400.         Active[Actnum] = (myfind(act_rec))->nd_name;
  401.         ++Actnum;
  402.     }
  403.  
  404. #ifdef NNTP
  405.     if (Machine == NULL)
  406.         fclose (f);
  407. #else
  408.     fclose (f);
  409. #endif
  410. }
  411.  
  412. /*
  413.     check active newsgroups not mentioned in NEWSRC file
  414.     (SFLG_SCAN not set)
  415. */
  416. static
  417. art_active ()
  418. {
  419.     int i;
  420.     NODE *ptr;
  421.  
  422.     for( i=0; i < Actnum; ++i)
  423.     {
  424.         ptr = myfind(Active[i]);
  425.         if ((ptr->state & SFLG_SCAN) == 0)
  426.             chkgroup (ptr->nd_name, NEWS_ON, 0, 1);
  427.     }
  428. }
  429.  
  430. /*
  431.     check group for new articles:
  432.     s - group
  433.     c - subscription indicator from NEWSRC
  434.     n - number read
  435.     new - new newsgroup flag
  436. */
  437. static
  438. chkgroup (s,c,n,new)
  439. char *s,c;
  440. int n;
  441. int new;
  442. {
  443.     NODE *ptr;
  444.     char sub;
  445.     int nrd;
  446.     int lowart;
  447.     int st;
  448.  
  449.     if ((ptr = hashfind(s)) != NULL && (ptr->state & SFLG_SCAN) == 0)
  450.     {
  451.         ptr->state |= SFLG_SCAN;
  452.  
  453. #ifdef SYN_CHECK
  454.         /* if "read" more than exist, reset */
  455.         if (n > ptr->highnum)
  456.         {
  457.             n = ptr->highnum - SYN_SETBACK;
  458.             fgprintf("%s: .newsrc out of synch, resetting\n",s);
  459.         }
  460. #endif
  461.         lowart = ptr->lownum;
  462.         if (n < ptr->lownum)
  463.             n = ptr->lownum;
  464.  
  465.         nrd = n;
  466.         sub = c;
  467.  
  468.         /*
  469.         ** scan decision is rather complex, since GF_ALL setting
  470.         ** overides "n" value, GF_SPEC indicates SFLG_SPEC flag used.
  471.         ** if GF_OVER set, SFLG_SPEC overides subscription mark, else
  472.         ** SFLG_SPEC AND subscribed is neccesary.
  473.         */
  474.         if ((Gflags & GF_SPEC) != 0)
  475.         {
  476.             if ((ptr->state & SFLG_SPEC) == 0)
  477.                 c = NEWS_OFF;
  478.             else
  479.             {
  480.                 if ((Gflags & GF_OVER) != 0)
  481.                     c = NEWS_ON;
  482.             }
  483.         }
  484.         if ((Gflags & GF_ALL) != 0)
  485.             n = lowart;
  486.         fw_group(s, new, sub == NEWS_ON, nrd, c == NEWS_ON);
  487.         if (c == NEWS_ON && ptr->highnum > n)
  488.         {
  489.             st = outgroup (s,n,ptr->highnum);
  490.             if (st > nrd)
  491.                 fw_chg(new, sub == NEWS_ON, st, c == NEWS_ON);
  492.         }
  493.     }
  494. #ifdef KEEP_UNK
  495.     else
  496.     {
  497.         /*
  498.         ** enter unknown group into the list with no articles and
  499.         ** no scanning for statistics.  Simply a device so we'll
  500.         ** write it back out again after we're done.
  501.         */
  502.         if (ptr == NULL)
  503.         {
  504.             hashenter (s, n, n);
  505.             fw_group(s, 0, c == NEWS_ON, n, 0);
  506.         }
  507.     }
  508. #endif
  509. }
  510.  
  511. /*
  512.     vns_write writes the .newsrc file
  513. */
  514. vns_write(news,ncount)
  515. NODE **news;
  516. int ncount;
  517. {
  518.     FILE *fp;
  519.     NODE *p;
  520.     char c;
  521.     int i,rc;
  522.  
  523.     if (link(Newsrc,Onews) < 0)
  524.         printex ("can't backup %s to %s before writing",Newsrc,Onews);
  525.  
  526.     if (unlink(Newsrc) < 0 || (fp = fopen(Newsrc,"w")) == NULL)
  527.         printex ("can't open %s for writing (backed up in %s)",Newsrc,Onews);
  528.     else
  529.     {
  530.         clearerr(fp);
  531.         for (i=0; (rc = ferror(fp)) == 0 && i < Optlines; ++i)
  532.             fprintf (fp,"%s",Options[i]);
  533.         for (i=0; rc == 0 && i < ncount; ++i)
  534.         {
  535.             p = news[i];
  536.             if ((p->flags & FLG_SUB) == 0)
  537.                 c = NEWS_OFF;
  538.             else
  539.                 c = NEWS_ON;
  540. #ifdef OLDRC
  541.             fprintf (fp,"%s%c %d\n",p->nd_name,c,p->rdnum);
  542. #else
  543.             if (p->rdnum > 0)
  544.                 fprintf(fp,"%s%c 1-%d\n",p->nd_name,c,p->rdnum);
  545.             else
  546.                 fprintf(fp,"%s%c 0\n",p->nd_name,c);
  547. #endif
  548.             rc = ferror(fp);
  549.         }
  550.         fclose (fp);
  551.         if (rc != 0)
  552.             printex ("write of %s failed, old copy stored in %s",Newsrc,Onews);
  553.         else
  554.             unlink (Onews);
  555.     }
  556. }
  557.  
  558. /*
  559.     arg_opt must be called prior to option scanning, since
  560.     it uses the options array.  This is a bit of a kludge,
  561.     but it saves a bunch of work.  NOTE - no command name argument
  562.  
  563.     This also processes the arguments which don't correspond to
  564.     the .newsrc options - these arguments are all flagged with '+'
  565. */
  566. static
  567. arg_opt (argc,argv)
  568. int argc;
  569. char **argv;
  570. {
  571.     int i;
  572.     char bufr[RECLEN];
  573.  
  574.     Optlines = 0;
  575.     for (i=0; i < argc; ++i,++argv)
  576.     {
  577.         if (**argv == '+')
  578.         {
  579.             ++(*argv);
  580.             switch (**argv)
  581.             {
  582. #ifdef NNTP
  583.             case 't':
  584.                 ++(*argv);
  585.                 if (**argv == '\0')
  586.                 {
  587.                     ++argv;
  588.                     ++i;
  589.                 }
  590.                 Fp_trace = fopen(*argv,"w");
  591.                 break;
  592.             case 'l':
  593.                 Machine = NULL;
  594.                 break;
  595.             case 'm':
  596.                 ++(*argv);
  597.                 if (*(Machine = *argv) == '\0')
  598.                 {
  599.                     ++argv;
  600.                     ++i;
  601.                     Machine = *argv;
  602.                 }
  603.                 break;
  604. #endif
  605.             case 'n':
  606.                 ++(*argv);
  607.                 if (*(Newsrc = *argv) == '\0')
  608.                 {
  609.                     ++argv;
  610.                     ++i;
  611.                     Newsrc = *argv;
  612.                 }
  613.                 if (*Newsrc != '/')
  614.                 {
  615.                     sprintf(bufr,"%s/%s",Home,Newsrc);
  616.                     Newsrc = str_store(bufr);
  617.                 }
  618.                 break;
  619.             default:
  620.                 printex("unknown option, +%c",**argv);
  621.             }
  622.             continue;
  623.         }
  624.  
  625.         if (Optlines >= OPTLINES)
  626.             printex ("too many command line options (%d allowed)\n",
  627.                             OPTLINES);
  628.         Options[Optlines] = *argv;
  629.         ++Optlines;
  630.     }
  631.  
  632.     /* now that we have machine name, resolve Poster command, Fmach */
  633. #ifdef NNTP
  634.  
  635.     /* make an empty machine synonomous with NULL */
  636.     if (Machine != NULL && *Machine == '\0')
  637.         Machine = NULL;
  638.     if (Machine != NULL)
  639.     {
  640. #ifdef FROM_REAL
  641.         gethostname(bufr,RECLEN/2);
  642.         Fmach = str_store(bufr);
  643. #ifdef MACH_CONCAT
  644.         sprintf(bufr,"%s!%s",Machine,Fmach);
  645.         Fmach = str_store(bufr);
  646. #endif
  647. #else
  648.         Fmach = Machine;
  649. #endif
  650.         Poster = vn_env("VNPOSTER",DEF_POST);
  651.         sprintf(bufr,Poster,Machine);
  652.         Poster = str_store(bufr);
  653.     }
  654.     else
  655.     {
  656.         Postfunc = NULL;
  657.         Poster = vn_env("VNPOSTER",LOC_POST);
  658.     }
  659. #else
  660.     Poster = vn_env("VNPOSTER",DEF_POST);
  661. #endif /* NNTP */
  662.     sprintf(bufr,"%s %%s",Poster);
  663.     Poster = str_store(bufr);
  664.  
  665.     if (access (Newsrc,0) != 0)
  666.         creat (Newsrc,0666);
  667.  
  668.     strcpy(bufr,Newsrc);
  669.     strcpy(rindex(bufr,'/')+1,".vnXXXXXX");
  670.     mktemp(bufr);
  671.     Onews = str_store (bufr);
  672. }
  673.  
  674. /*
  675.     option setting routine:
  676.     sets global flags: GF_ALL for -x option GF_SPEC for -n.
  677.     sets up filter array for article scanning
  678. */
  679. static
  680. newsrc_opt(lfirst,nun)
  681. int *lfirst, *nun;
  682. {
  683.     int i;
  684.     char curopt,tmp[RECLEN],*tok;
  685.  
  686.     *nun = *lfirst = 0;
  687.     Ntopt = Nwopt = Nnwopt = Nntopt = 0;
  688.     curopt = '\0';
  689.     for (i=0; i < Optlines; ++i)
  690.     {
  691.         strcpy(tmp,Options[i]);
  692.         for (tok = strtok(tmp,",\\ \t\n"); tok != NULL; tok = strtok(NULL,",\\ \t\n"))
  693.         {
  694.             if (*tok != '-')
  695.                 do_opt (curopt,tok);
  696.             else
  697.             {
  698.                 for (++tok; index("nwt",*tok) == NULL; ++tok)
  699.                 {
  700.                     /* options with no strings */
  701.                     switch(*tok)
  702.                     {
  703.                     case 'S':
  704.                         Gflags &= ~GF_OVER;
  705.                         break;
  706.                     case '%':
  707.                         *lfirst = 1;
  708.                         break;
  709.                     case 'U':
  710.                         *nun = 1;
  711.                         break;
  712. #ifdef OLDRC
  713.                     case 'i':
  714.                     /* Treat "-i" as synonym for "-x" */
  715. #endif
  716.                     case 'x':
  717.                         Gflags |= GF_ALL;
  718.                     default:
  719.                         break;
  720.                     }
  721.                 }
  722.                 curopt = *tok;
  723.                 if (*(++tok) != '\0')
  724.                     do_opt (curopt,tok);
  725.             }
  726.         }
  727.     }
  728. }
  729.  
  730. /* do_opt is for options with strings attached */
  731. static
  732. do_opt (opt,str)
  733. char opt, *str;
  734. {
  735.     switch (opt)
  736.     {
  737.     case 'n':
  738.         Gflags |= GF_SPEC;
  739.         specmark(str);
  740.         break;
  741.     case 'w':
  742.         specfilter (FIL_AUTHOR,str);
  743.         break;
  744.     case 't':
  745.         specfilter (FIL_TITLE,str);
  746.         break;
  747.     default:
  748. #ifdef OLDRC
  749.         Gflags |= GF_SPEC;    /* Assume anything else is newsgroup */
  750.         specmark(str);
  751. #endif
  752.         break;
  753.     }
  754. }
  755.  
  756. static
  757. specfilter (comp,str)
  758. char comp,*str;
  759. {
  760.     int *count;
  761.     char **rex;
  762.  
  763.     /*
  764.     ** we may set rex one past end of array.  we will error before
  765.     ** referencing it if that's the case, however.
  766.     */
  767.     if (*str == '!')
  768.     {
  769.         if (comp == FIL_TITLE)
  770.         {
  771.             count = &Nntopt;
  772.             rex = Negtopt + *count;
  773.         }
  774.         else
  775.         {
  776.             count = &Nnwopt;
  777.             rex = Negwopt + *count;
  778.         }
  779.         ++str;
  780.     }
  781.     else
  782.     {
  783.         if (comp == FIL_TITLE)
  784.         {
  785.             count = &Ntopt;
  786.             rex = Topt + *count;
  787.         }
  788.         else
  789.         {
  790.             count = &Nwopt;
  791.             rex = Wopt + *count;
  792.         }
  793.     }
  794.     if (*count >= NUMFILTER)
  795.         printex ("too many %c options, %d allowed",comp,NUMFILTER);
  796.     if ((*rex = regcmp(str,(char *) 0)) == NULL)
  797.         printex ("%c option regular expression syntax: %s",comp,str);
  798.     ++(*count);
  799. }
  800.  
  801. /*
  802.     handle the newsgroup specification string.
  803.     ("all" convention - braack!!!)
  804. */
  805. static
  806. specmark (s)
  807. char *s;
  808. {
  809.     unsigned ormask,andmask;
  810.     int i,len;
  811.     char *ptr,*re,pattern[RECLEN];
  812.     NODE *nptr;
  813.  
  814.     if (*s == '!')
  815.     {
  816.         ++s;
  817.         ormask = 0;
  818.         andmask = ~SFLG_SPEC;
  819.         if (*s == '\0')
  820.             return;
  821.     }
  822.     else
  823.     {
  824.         ormask = SFLG_SPEC;
  825.         andmask = 0xffff;
  826.     }
  827.  
  828.     /* convert "all" not bounded by alphanumerics to ".*". ".all" becomes ".*" */
  829.     for (ptr = s; (len = findall(ptr)) >= 0; ptr += len+1)
  830.     {
  831.         if (len > 0 && isalnum (ptr[len-1]))
  832.             continue;
  833.         if (isalnum (ptr[len+3]))
  834.             continue;
  835.         if (len > 0 && ptr[len-1] == '.')
  836.         {
  837.             --len;
  838.             strcpy (ptr+len,ptr+len+1);
  839.         }
  840.         ptr[len] = '.';
  841.         ptr[len+1] = '*';
  842.         strcpy (ptr+len+2,ptr+len+3);
  843.     }
  844.  
  845.     /* now use regular expressions */
  846.     sprintf (pattern,"^%s$",s);
  847.     if ((re = regcmp(pattern,(char *) 0)) == NULL)
  848.         printex ("n option regular expression syntax: %s",s);
  849.     for (i=0; i < Actnum; ++i)
  850.     {
  851.         nptr = myfind(Active[i]);
  852.         if (regex(re,nptr->nd_name) != NULL)
  853.         {
  854.             nptr->state |= ormask;
  855.             nptr->state &= andmask;
  856.         }
  857.     }
  858.     regfree (re);
  859. }
  860.  
  861. static
  862. findall (s)
  863. char *s;
  864. {
  865.     int len;
  866.     for (len=0; *s != '\0'; ++s,++len)
  867.     {
  868.         if (*s == 'a' && strncmp(s,"all",3) == 0)
  869.             return (len);
  870.     }
  871.     return (-1);
  872. }
  873.  
  874. static
  875. grp_indic (s,ok,serr)
  876. char *s;
  877. int ok;
  878. char *serr;    /* only used for NNTP */
  879. {
  880.     if (ok)
  881.     {
  882.         fgprintf("    %s\n",s);
  883.         return;
  884.     }
  885. #ifdef NNTP
  886.     if (Machine != NULL)
  887.     {
  888.         fgprintf("    %s, server: %s\n",s,serr);
  889.         return;
  890.     }
  891. #endif
  892.     fgprintf("    %s - Can't access spool directory\n",s);
  893. }
  894.  
  895. /*
  896.     enter newsgroup articles.
  897.     all articles between low and hi are to be included.
  898.  
  899.     Returns the highest number less than an OPENED (not neccesarily
  900.     accepted) article to allow caller to revise "articles read"
  901.     number beyond non-existent articles.
  902. */
  903. outgroup (s,low,hi)
  904. char *s;
  905. int low,hi;
  906. {
  907.     int i;
  908.     char subj[RECLEN], lines[RECLEN], auth[RECLEN], gd[RECLEN];
  909.     int ret,op;
  910.  
  911.     ret = low;
  912.     op = 1;
  913.  
  914.     if ((hi-low) > MAXARTRANGE)
  915.         low = hi - MAXARTRANGE;
  916.  
  917. #ifdef NNTP
  918.     if (Machine != NULL)
  919.     {
  920.         sprintf(gd,"group %s",s);
  921.         if (nntp_put(gd,gd) < 0)
  922.         {
  923.             grp_indic(s,0,gd);
  924.             return (ret);
  925.         }
  926.     }
  927.     else
  928.     {
  929.         g_dir(s,gd);
  930.         if (chdir(gd) < 0)
  931.         {
  932.             grp_indic(s,0);
  933.             return (ret);
  934.         }
  935.     }
  936. #else
  937.     g_dir(s,gd);
  938.     if (chdir(gd) < 0)
  939.     {
  940.         grp_indic(s,0);
  941.         return (ret);
  942.     }
  943. #endif /* NNTP */
  944.  
  945.     grp_indic(s,1);
  946.  
  947.     for (i=low+1; i <= hi; ++i)
  948.     {
  949.         if (digname(i,subj,lines,auth,&op) >= 0)
  950.         {
  951.             fw_art(i,subj,lines,auth);
  952.         }
  953.         else
  954.         {
  955.             if (op)
  956.                 ret = i;
  957.         }
  958.     }
  959.  
  960.     return(ret);
  961. }
  962.  
  963. /*
  964. ** open article and interpret options, if any.  The op parameter is set
  965. ** to ZERO if and only if an article is opened.  Used above as a flag to
  966. ** indicate no articles opened yet.
  967. */
  968. static digname (n, subj, lines, auth, op)
  969. int n;
  970. char *subj, *lines, *auth;
  971. int *op;
  972. {
  973.     int i,j;
  974.     char t[RECLEN];
  975.     FILE *fp;
  976.     char *(*getfn)();
  977.     char *nfgets();
  978.     char *got;
  979.  
  980.     /* open article */
  981. #ifdef NNTP
  982.     if (Machine != NULL)
  983.     {
  984.         sprintf (t,"head %d", n);
  985.         if (nntp_put(t,t) < 0)
  986.             return (-1);
  987.         getfn = nntp_get;
  988.     }
  989.     else
  990.     {
  991.         sprintf (t,"%d", n);
  992.         if ((fp = fopen(t,"r")) == NULL)
  993.             return (-1);
  994.         getfn = nfgets;
  995.     }
  996. #else
  997.     getfn = nfgets;
  998.     sprintf (t,"%d", n);
  999.     if ((fp = fopen(t,"r")) == NULL)
  1000.         return (-1);
  1001. #endif
  1002.     *op = 0;
  1003.  
  1004.     /* get subject, from and lines by reading article */
  1005.     subj[0] = lines[0] = auth[0] = '?';
  1006.     subj[1] = lines[1] = auth[1] = '\0';
  1007.  
  1008.     for (i = 0; i < HDR_LINES && (got = (*getfn)(t,RECLEN-1,fp)) != NULL; ++i)
  1009.     {
  1010.         if (index(CHFIRST,t[0]) == NULL)
  1011.             continue;
  1012.         t[strlen(t) - 1] = '\0';
  1013.         if (strncmp(T_head,t,THDLEN) == 0)
  1014.         {
  1015.             for (j=0; j < Nntopt; ++j)
  1016.             {
  1017.                 if (regex(Negtopt[j],t+THDLEN) != NULL)
  1018.                 {
  1019.                     digclose(fp,got);
  1020.                     return(-1);
  1021.                 }
  1022.             }
  1023.             if (Ntopt > 0)
  1024.             {
  1025.                 for (j=0; j < Ntopt; ++j)
  1026.                 {
  1027.                     if (regex(Topt[j],t+THDLEN) != NULL)
  1028.                         break;
  1029.                 }
  1030.                 if (j >= Ntopt)
  1031.                 {
  1032.                     digclose(fp,got);
  1033.                     return(-1);
  1034.                 }
  1035.             }
  1036.             strcpy(subj,t+THDLEN);
  1037.             continue;
  1038.         }
  1039.         if (strncmp(F_head,t,FHDLEN) == 0)
  1040.         {
  1041.             for (j=0; j < Nnwopt; ++j)
  1042.             {
  1043.                 if (regex(Negwopt[j],t+FHDLEN) != NULL)
  1044.                 {
  1045.                     digclose(fp,got);
  1046.                     return(-1);
  1047.                 }
  1048.             }
  1049.             if (Nwopt > 0)
  1050.             {
  1051.                 for (j=0; j < Nwopt; ++j)
  1052.                 {
  1053.                     if (regex(Wopt[j],t+FHDLEN) != NULL)
  1054.                         break;
  1055.                 }
  1056.                 if (j >= Nwopt)
  1057.                 {
  1058.                     digclose(fp,got);
  1059.                     return(-1);
  1060.                 }
  1061.             }
  1062.             strcpy(auth,t+FHDLEN);
  1063.             continue;
  1064.         }
  1065.         if (strncmp(L_head,t,LHDLEN) == 0)
  1066.         {
  1067.             strcpy(lines,t+LHDLEN);
  1068.             break;
  1069.         }
  1070.     }
  1071.  
  1072.     digclose(fp,got);
  1073.  
  1074.     /* reject empty or 1 line files */
  1075.     if (i < 2)
  1076.         return (-1);
  1077.  
  1078.     return (0);
  1079. }
  1080.  
  1081. /*
  1082. ** "close" open article from digname - "got" is not used in non-NNTP case
  1083. */
  1084. digclose(fp,got)
  1085. FILE *fp;
  1086. char *got;
  1087. {
  1088. #ifdef NNTP
  1089.     char bufr[RECLEN];
  1090.  
  1091.     if (Machine == NULL)
  1092.         fclose (fp);
  1093.     else
  1094.     {
  1095.         /*
  1096.         ** have to finish getting the header lines from the
  1097.         ** server
  1098.         */
  1099.         while (got != NULL)
  1100.             got = nntp_get(bufr,RECLEN-1,fp);
  1101.     }
  1102. #else
  1103.     fclose (fp);
  1104. #endif
  1105. }
  1106.  
  1107. /*
  1108. ** special fgets for reading header lines, which unfolds continued lines
  1109. ** and throws away trailing stuff on buffer overflow.
  1110. */
  1111. static char *
  1112. nfgets(buf, size, fp)
  1113. char    *buf;
  1114. int    size;
  1115. FILE    *fp;
  1116. {
  1117.     register int c;
  1118.  
  1119.     while (!feof(fp))
  1120.     {
  1121.         if ((c = getc(fp)) == '\n')
  1122.         {
  1123.             if ((c = getc(fp)) == '\t' || c == ' ')
  1124.                 continue;
  1125.             ungetc(c, fp);
  1126.             *buf = '\n';
  1127.             ++buf;
  1128.             *buf = '\0';
  1129.             ++buf;
  1130.             return (buf);
  1131.         }
  1132.  
  1133.         /* prevent "terminal bombs" */
  1134.         if (c < ' ' || c == '\177')
  1135.         {
  1136.             switch(c)
  1137.             {
  1138.             case '\r':
  1139.             case '\010':
  1140.             case '\07':
  1141.                 break;
  1142.             case '\177':
  1143.                 c = '~';
  1144.                 break;
  1145.             case '\t':
  1146.                 c = ' ';
  1147.                 break;
  1148.             default:
  1149.                 if (size > 1)
  1150.                 {
  1151.                     *buf = '^';
  1152.                     ++buf;
  1153.                     --size;
  1154.                 }
  1155.                 c += 'A' - 1;
  1156.                 break;
  1157.             }
  1158.         }
  1159.  
  1160.         if (size > 0)
  1161.         {
  1162.             *buf = c;
  1163.             ++buf;
  1164.             --size;
  1165.         }
  1166.         if (c == '\r')
  1167.         {
  1168.             if ((c = getc(fp)) != '\n')
  1169.             {
  1170.                 ungetc(c, fp);
  1171.                 continue;
  1172.             }
  1173.             if ((c = getc(fp)) != ' ' && c != '\t')
  1174.             {
  1175.                 *buf = '\0';
  1176.                 ++buf;
  1177.                 ungetc(c, fp);
  1178.                 return (buf);
  1179.             }
  1180.             --buf;
  1181.             ++size;
  1182.             continue;
  1183.         }
  1184.     }
  1185.  
  1186.     *buf = '\0';
  1187.     ++buf;
  1188.     return (NULL);
  1189. }
  1190.  
  1191. static char *Mail[2], *Show[6], *Post[5];
  1192. static char *Priv[8];
  1193. static char *Pool = NULL;
  1194.  
  1195. FILE *
  1196. vns_aopen(art,hdr)
  1197. int art;
  1198. ARTHEADER *hdr;
  1199. {
  1200.     char buf[RECLEN];
  1201.     char *dist, *reply, *from, *ngrp, *flto, *path, *resubj;
  1202.     FILE *fp;
  1203.     FILE *a_open();
  1204.     int n;
  1205.     char *mail_trim();
  1206.  
  1207.     dist = resubj = path = reply = from = ngrp = flto = NULL;
  1208.  
  1209.     fp = a_open(art);
  1210.     if (fp == NULL)
  1211.         return(NULL);
  1212.  
  1213.     /*
  1214.     ** we only really need a lot extra if MAILCHOOSE, but allocating
  1215.     ** a temporary array of pointers isn't that much.  Similarly, a
  1216.     ** few assignments, and the "Priv" declaration are only needed
  1217.     ** with some define settings.  Not worth ifdef'ing.
  1218.     */
  1219.     Pool = str_tpool(100);
  1220.  
  1221.     hdr->artid = "<some article>";
  1222.     hdr->from = "<somebody>";
  1223.     hdr->priv = Priv;
  1224.     hdr->postcmd = Poster;
  1225.     hdr->mail = Mail;
  1226.     hdr->show = Show;
  1227.     hdr->post = Post;
  1228.     hdr->priv_num = hdr->show_num = hdr->post_num = hdr->mail_num = 0;
  1229.  
  1230.     /* for conditional is abnormal - expected exit is break */
  1231.     for (n=0; n < HDR_LINES && fgets(buf,RECLEN-1,fp) != NULL; ++n)
  1232.     {
  1233.         /* bail out at first non-header line */
  1234.         if (buf[0] == '\n')
  1235.             break;
  1236.         if (strncmp(buf,RT_head,RTHDLEN) == 0)
  1237.         {
  1238.             buf [strlen(buf)-1] = '\0';
  1239.             reply = str_tstore(Pool,buf+RTHDLEN);
  1240.             continue;
  1241.         }
  1242.         if (strncmp(buf,P_head,PHDLEN) == 0)
  1243.         {
  1244.             buf [strlen(buf)-1] = '\0';
  1245.             path = str_tstore(Pool,buf+PHDLEN);
  1246.             continue;
  1247.         }
  1248.         if (strncmp(buf,DIS_head,DISHDLEN) == 0)
  1249.         {
  1250.             buf [strlen(buf)-1] = '\0';
  1251.             dist = str_tstore(Pool,buf);
  1252.             continue;
  1253.         }
  1254.         if (strncmp(buf,M_head,MHDLEN) == 0)
  1255.         {
  1256.             buf [strlen(buf)-1] = '\0';
  1257.             hdr->artid = str_tstore(Pool,buf+MHDLEN);
  1258.             continue;
  1259.         }
  1260.         if (strncmp(buf,F_head,FHDLEN) == 0)
  1261.         {
  1262.             buf [strlen(buf)-1] = '\0';
  1263.             (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1264.             from = hdr->from = (hdr->show)[hdr->show_num]+FHDLEN;
  1265.             ++(hdr->show_num);
  1266.             continue;
  1267.         }
  1268.         if (strncmp(buf,T_head,THDLEN) == 0)
  1269.         {
  1270.             buf [strlen(buf)-1] = '\0';
  1271.             (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1272.             if (strncmp(buf+THDLEN,Fpfix,FPFLEN) != 0)
  1273.             {
  1274.                 sprintf(buf,"%s%s%s",T_head,Fpfix,
  1275.                     ((hdr->show)[hdr->show_num])+THDLEN);
  1276.                 resubj = str_tstore(Pool,buf);
  1277.             }
  1278.             else
  1279.                 resubj = (hdr->show)[hdr->show_num];
  1280.             ++(hdr->show_num);
  1281.             continue;
  1282.         }
  1283.         if (strncmp(buf,N_head,NHDLEN) == 0)
  1284.         {
  1285.             buf [strlen(buf)-1] = '\0';
  1286.  
  1287.             /* if multiple newsgroups, include in "show" */
  1288.             if (index(buf,',') != NULL)
  1289.             {
  1290.                 (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1291.                 ngrp = (hdr->show)[hdr->show_num] + NHDLEN;
  1292.                 ++(hdr->show_num);
  1293.             }
  1294.             else
  1295.                 ngrp = str_tstore(Pool,buf+NHDLEN);
  1296.             continue;
  1297.         }
  1298.         if (strncmp(buf,FT_head,FTHDLEN) == 0)
  1299.         {
  1300.             buf [strlen(buf)-1] = '\0';
  1301.             (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1302.             flto = (hdr->show)[hdr->show_num] + FTHDLEN;
  1303.             ++(hdr->show_num);
  1304.             continue;
  1305.         }
  1306.         if (strncmp(buf,L_head,LHDLEN) == 0)
  1307.         {
  1308.             buf [strlen(buf)-1] = '\0';
  1309.             hdr->lines = atoi(buf+LHDLEN);
  1310.             (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1311.             ++(hdr->show_num);
  1312.             continue;
  1313.         }
  1314.     }
  1315.  
  1316.     hdr->hlines = n;
  1317.  
  1318. #ifdef MAILCHOOSE
  1319.     (hdr->priv)[hdr->priv_num] = resubj;
  1320.     ++(hdr->priv_num);
  1321.     if (reply != NULL)
  1322.     {
  1323.         (hdr->priv)[hdr->priv_num] = mail_trim(reply);
  1324.         ++(hdr->priv_num);
  1325.     }
  1326.     if (from != NULL)
  1327.     {
  1328.         (hdr->priv)[hdr->priv_num] = mail_trim(from);
  1329.         ++(hdr->priv_num);
  1330.     }
  1331.     if (path != NULL)
  1332.     {
  1333.         (hdr->priv)[hdr->priv_num] = mail_trim(path);
  1334.         ++(hdr->priv_num);
  1335.     }
  1336. #else
  1337. #ifdef MAILSMART
  1338.     if (reply == NULL)
  1339.         if (from != NULL)
  1340.             reply = from;
  1341.         else
  1342.         {
  1343.             if (path != NULL)
  1344.                 reply = path;
  1345.         }
  1346. #else
  1347.     if (path != NULL)
  1348.         reply = path;
  1349. #endif
  1350.     if (reply != NULL)
  1351.         reply =  mail_trim(reply);
  1352.     mail_cmd(hdr,reply,resubj);
  1353. #endif /* MAILCHOOSE */
  1354.  
  1355.     if (flto == NULL)
  1356.     {
  1357.         if ((flto = ngrp) == NULL)
  1358.             flto = "group.unknown";
  1359.     }
  1360.     ngrp = rindex(flto,'.');
  1361.  
  1362.     if (strncmp("mod.",flto,4) == 0 ||
  1363.             (ngrp != NULL && strcmp(".announce",ngrp) == 0))
  1364.     {
  1365.         sprintf(buf,"Cannot post a follow-up to \"%s\", reply with mail to moderator",flto);
  1366.         hdr->post_err = str_tstore(Pool,buf);
  1367.         return (fp);
  1368.     }
  1369.  
  1370.     if (ngrp != NULL && strcmp(ngrp,".general") == 0)
  1371.     {
  1372.         *ngrp = '\0';
  1373.         sprintf(buf,"%s%s.followup",N_head,flto);
  1374.     }
  1375.     else
  1376.         sprintf(buf,"%s%s",N_head,flto);
  1377.     flto = str_tstore(Pool,buf);
  1378.  
  1379.     hdr->post_err = NULL;
  1380.  
  1381.     if (resubj != NULL)
  1382.     {
  1383.         (hdr->post)[hdr->post_num] = resubj;
  1384.         ++(hdr->post_num);
  1385.     }
  1386.  
  1387. #ifdef NNTP
  1388. #ifdef SHOW_FROM
  1389.     if (Machine != NULL)
  1390.     {
  1391.         sprintf(buf,FROM_CR_FORM, F_head, Username, Fmach, Userdesc);
  1392.         (hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
  1393.         ++(hdr->post_num);
  1394.     }
  1395. #else
  1396. #ifdef REPLY_CR_FORM
  1397.     if (Machine != NULL)
  1398.     {
  1399.         sprintf(buf,REPLY_CR_FORM, RT_head, Username, Fmach);
  1400.         (hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
  1401.         ++(hdr->post_num);
  1402.     }
  1403. #endif
  1404. #endif
  1405. #endif
  1406.  
  1407.     (hdr->post)[hdr->post_num] = flto;
  1408.     ++(hdr->post_num);
  1409.  
  1410.     sprintf(buf,"%s%s",R_head,hdr->artid);
  1411.     (hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
  1412.     ++(hdr->post_num);
  1413.  
  1414.     if (dist != NULL)
  1415.     {
  1416.         (hdr->post)[hdr->post_num] = dist;
  1417.         ++(hdr->post_num);
  1418.     }
  1419.  
  1420.     return (fp);
  1421. }
  1422.  
  1423. #ifdef MAILCHOOSE
  1424. /*
  1425. ** routine to prompt user for mail path approval
  1426. */
  1427. static
  1428. mail_prompt(hdr)
  1429. ARTHEADER *hdr;
  1430. {
  1431.     int i;
  1432.     char buf[RECLEN],*ptr;
  1433.  
  1434.     tty_set(SAVEMODE);
  1435.     for (i=1; i < hdr->priv_num; ++i)
  1436.     {
  1437.         printf("%d - %s\n",i,(hdr->priv)[i]);
  1438.     }
  1439.     printf("\nType number to choose one of the above, or input address: ");
  1440.     fgets(buf,RECLEN-1,stdin);
  1441.     tty_set(RESTORE);
  1442.  
  1443.     ptr = strtok(buf," \t\n");
  1444.     if (ptr == NULL)
  1445.         ptr = "";
  1446.  
  1447.     i = strlen(ptr);
  1448.     if (i == 1)
  1449.     {
  1450.         i = atoi(ptr);
  1451.         if (i > 0 && i <= hdr->priv_num)
  1452.             ptr = (hdr->priv)[i];
  1453.         i = 1;
  1454.     }
  1455.  
  1456.     /*
  1457.     ** If the user keeps cycling through here on the same article,
  1458.     ** we will eventually run out of strings.  We made Pool large
  1459.     ** enough to make it unlikely (user will have to retry about 80
  1460.     ** times without switching articles).  Hardly elegant, but should
  1461.     ** be sufficient.
  1462.     */
  1463.     if (i > 1 && hdr->priv_num < 8)
  1464.     {
  1465.         (hdr->priv)[hdr->priv_num] = str_tstore(Pool,ptr);
  1466.         ++(hdr->priv_num);
  1467.     }
  1468.     mail_cmd(hdr,ptr,(hdr->priv)[0]);
  1469. }
  1470. #endif
  1471.  
  1472. /*
  1473. ** trim () off potential mail address, and make copy if needed.
  1474. ** addr must be allocated string.
  1475. */
  1476. static char *
  1477. mail_trim(addr)
  1478. char *addr;
  1479. {
  1480.     char buf[RECLEN];
  1481.     char *ptr;
  1482.  
  1483.     if (index(addr,'(') == NULL)
  1484.         return(addr);
  1485.  
  1486.     strcpy(buf,addr);
  1487.     ptr = index(buf,'(');
  1488.     for (--ptr; *ptr == ' ' || *ptr == '\t'; --ptr)
  1489.         ;
  1490.     ++ptr;
  1491.     *ptr = '\0';
  1492.     return (str_tstore(Pool,buf));
  1493. }
  1494.  
  1495. /*
  1496. ** format mail command.  Subj must point to allocated string.
  1497. */
  1498. static
  1499. mail_cmd(hdr,addr,subj)
  1500. ARTHEADER *hdr;
  1501. char *addr, *subj;
  1502. {
  1503.     char buf[RECLEN];
  1504.  
  1505.     if (addr == NULL || *addr == '\0')
  1506.     {
  1507.         hdr->mail_err = "No address";
  1508.         return;
  1509.     }
  1510.  
  1511.     hdr->mail_err = NULL;
  1512.             ;
  1513.  
  1514. #ifdef INLETTER
  1515.     hdr->mailcmd = Mailer;
  1516.     sprintf(buf,"%s%s",TO_head,addr);
  1517.     (hdr->mail)[0] = str_tstore(Pool,buf);
  1518.     hdr->mail_num = 1;
  1519. #else
  1520.     sprintf(buf,Mailer,addr);
  1521.     hdr->mailcmd = str_tstore(Pool,buf);
  1522.     hdr->mail_num = 0;
  1523. #endif
  1524.     if (subj != NULL)
  1525.     {
  1526.         (hdr->mail)[hdr->mail_num] = subj;
  1527.         ++(hdr->mail_num);
  1528.     }
  1529. }
  1530.  
  1531. static FILE
  1532. *a_open(art)
  1533. int art;
  1534. {
  1535.     FILE *fp;
  1536.     char buf[RECLEN];
  1537. #ifdef NNTP
  1538.     char cmd[RECLEN];
  1539.  
  1540.     if (Machine == NULL)
  1541.     {
  1542.         sprintf(buf,"%d",art);
  1543.         fp = fopen(buf,"r");
  1544.         return (fp);
  1545.     }
  1546.  
  1547.     tmpnam(buf);
  1548.     if ((fp = fopen(buf,"w")) == NULL)
  1549.         return (NULL);
  1550.  
  1551.     sprintf(cmd,"head %d",art);
  1552.     if (nntp_put(cmd,cmd) < 0)
  1553.     {
  1554.         fclose(fp);
  1555.         unlink(buf);
  1556.         return(NULL);
  1557.     }
  1558.     while (nntp_get(cmd,RECLEN) != NULL)
  1559.         fprintf(fp,"%s",cmd);
  1560.     fprintf(fp,"\n");
  1561.     sprintf(cmd,"body %d",art);
  1562.     if (nntp_put(cmd,cmd) >= 0)
  1563.     {
  1564.         while (nntp_get(cmd,RECLEN) != NULL)
  1565.             fprintf(fp,"%s",cmd);
  1566.     }
  1567.     fclose(fp);
  1568.     fp = fopen(buf,"r");
  1569.  
  1570.     /* "invisible" article - FP opened to unlinked file */
  1571.     unlink(buf);
  1572.  
  1573.     return(fp);
  1574. #else
  1575.     sprintf(buf,"%d",art);
  1576.     fp = fopen(buf,"r");
  1577.     return (fp);
  1578. #endif
  1579. }
  1580.  
  1581. vns_aclose(fp)
  1582. FILE *fp;
  1583. {
  1584.     if (Pool != NULL)
  1585.         str_tfree(Pool);
  1586.     Pool = NULL;
  1587.     fclose(fp);
  1588. }
  1589.  
  1590. /*
  1591. ** we don't use the count / name / mode arguments because this doesn't
  1592. ** implement any fancy article massaging
  1593. */
  1594. vns_asave(art,fp)
  1595. int art;
  1596. FILE *fp;
  1597. {
  1598.     char buf[RECLEN];
  1599.     FILE *fin;
  1600.  
  1601.     fin = a_open(art);
  1602.  
  1603.     while (fgets(buf,RECLEN-1,fin) != NULL)
  1604.         fputs(buf,fp);
  1605.     fclose(fin);
  1606. }
  1607.  
  1608. vns_exit()
  1609. {
  1610. #ifdef NNTP
  1611.     if (Fp_trace != NULL)
  1612.     {
  1613.         fprintf(Fp_trace,"Close Server\n");
  1614.         fclose(Fp_trace);
  1615.     }
  1616.     if (Server_open)
  1617.         close_server();
  1618. #endif
  1619. }
  1620.  
  1621. #ifdef NNTP
  1622. /*
  1623. ** nntp_get returns char* so it can be used interchangeably with fgets
  1624. ** it appends a newline for the same reason.
  1625. */
  1626. char *
  1627. nntp_get(buf,len)
  1628. char *buf;
  1629. int len;
  1630. {
  1631.     if (get_server(buf,len-1) < 0)
  1632.         return(NULL);
  1633.  
  1634.     len = strlen(buf);
  1635.     if (len == 0 || (len > 0 && buf[len-1] != '\n'))
  1636.         strcpy(buf+len,"\n");
  1637.  
  1638.     if (Fp_trace != NULL)
  1639.         fprintf(Fp_trace,"Got - %s",buf);
  1640.  
  1641.     if (buf[0] == '.' && buf[1] == '\n')
  1642.         return(NULL);
  1643.  
  1644.     return(buf);
  1645. }
  1646.  
  1647. /*
  1648. ** returns failure explanation in estr - estr = str is legal
  1649. */
  1650. nntp_put(str,estr)
  1651. char *str;
  1652. char *estr;
  1653. {
  1654.     if (Fp_trace != NULL)
  1655.         fprintf(Fp_trace,"Send - %s\n",str);
  1656.  
  1657.     put_server(str);
  1658.     estr[0] = CHAR_INF;
  1659.     while (estr[0] == CHAR_INF)
  1660.     {
  1661.         if (get_server(estr,RECLEN-1) < 0)
  1662.         {
  1663.             if (Fp_trace != NULL)
  1664.                 fprintf(Fp_trace,"Ack - no response\n",estr);
  1665.             strcpy(estr,"no response");
  1666.             return(-1);
  1667.         }
  1668.  
  1669.         if (Fp_trace != NULL)
  1670.             fprintf(Fp_trace,"Ack - %s\n",estr);
  1671.     }
  1672.  
  1673.     if (estr[0] != CHAR_OK)
  1674.         return (-1);
  1675.     return(0);
  1676. }
  1677.  
  1678. /*
  1679. ** if not letting the user edit the From line, we have to hack one in
  1680. ** ourselves to prevent getting the thing posted from "news".  This
  1681. ** will effectively defeat any that the user may have added, also.
  1682. */
  1683. #ifndef SHOW_FROM
  1684. nntp_post(hdr,fn)
  1685. ARTHEADER *hdr;
  1686. char *fn;
  1687. {
  1688.     char tname[80];
  1689.     char bufr[RECLEN];
  1690.     FILE *fin,*fout;
  1691.  
  1692.     tmpnam(tname);
  1693.  
  1694.     if ((fin = fopen(fn,"r")) == NULL || (fout = fopen(tname,"w")) == NULL)
  1695.     {
  1696.         printf("Can't open article files\n");
  1697.         return;
  1698.     }
  1699.  
  1700.     fprintf(fout,FROM_CR_FORM, F_head, Username, Fmach, Userdesc);
  1701.     fprintf(fout,"\n");
  1702.     while (fgets(bufr,RECLEN-1,fin) != NULL)
  1703.         fprintf(fout,"%s",bufr);
  1704.     fclose(fin);
  1705.     fclose(fout);
  1706.  
  1707.     sprintf(bufr,hdr->postcmd,tname);
  1708.     system(bufr);
  1709.     printf("Given to posting program.\n");
  1710.     unlink(tname);
  1711. }
  1712. #endif /* SHOW_FROM */
  1713. #endif /* NNTP */
  1714.