home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume14
/
vn.nntp.pch
/
std.c
< prev
Wrap
C/C++ Source or Header
|
1988-04-19
|
32KB
|
1,714 lines
#include <stdio.h>
#include <pwd.h>
#include <ctype.h>
#include <sys/param.h>
#ifdef NNTP
#include <response_codes.h>
#endif
#include "server.h"
#include "config_std.h"
#include "std.h"
#ifndef MAXPATHLEN
#define MAXPATHLEN 240
#endif
extern NODE *hashfind();
extern FILE *fopen();
extern char *index(), *rindex();
extern char *malloc();
extern char *str_tstore(), *str_tpool(), *str_store();
extern char *strtok(), *strpbrk();
extern char *regex(), *regcmp();
#ifdef MAILCHOOSE
extern int (*Massage)();
#endif
/*
global flags signifying options set
*/
#define GF_ALL 1 /* -x option - scan everything */
#define GF_SPEC 2 /* -n option(s) - user specified groups */
#define GF_OVER 4 /* command line specification - overide marks */
#ifdef NNTP
char *nntp_get();
static char *Machine;
static char *Fmach;
char *Vns_version = "nntp1.2";
static FILE *Fp_trace = NULL;
extern int (*Postfunc)();
static int Server_open = 0;
#else
char *Vns_version = "res1.2";
#endif
static char *Home;
static char *Username, *Userdesc;
static char *Onews, *Newsrc;
static int Ntopt, Nntopt, Nwopt, Nnwopt;
static char *Wopt[NUMFILTER]; /* regular expressions for -w options */
static char *Topt[NUMFILTER]; /* for -t options */
static char *Negwopt[NUMFILTER]; /* for negated -w options */
static char *Negtopt[NUMFILTER]; /* for negated -t options */
static char *Options[OPTLINES];
static int Max_name, Optlines;
static unsigned Gflags = 0;
static char **Active;
static int Actnum;
static char *Mailer, *Poster;
static char *RT_head = RTHEAD;
static char *P_head = PHEAD;
static char *M_head = MHEAD;
static char *R_head = RHEAD;
static char *TO_head = TOHEAD;
static char *F_head = FHEAD;
static char *FT_head = FTHEAD;
static char *T_head = THEAD;
static char *DIS_head = DISHEAD;
static char *L_head = LHEAD;
static char *N_head = NHEAD;
static char *Fpfix = FPFIX;
/*
** environment setup.
*/
vns_envir()
{
char dbuf[MAXPATHLEN], *rcname;
char *vn_env();
struct passwd *ptr, *getpwuid();
char *machine;
#ifdef NNTP
#ifndef SHOW_FROM
int nntp_post();
#endif
#endif
#ifdef MAILCHOOSE
int mail_prompt();
Massage = mail_prompt;
#endif
ptr = getpwuid (getuid());
Home = str_store(ptr->pw_dir);
Username = str_store(ptr->pw_name);
Userdesc = str_store(ptr->pw_gecos);
#ifdef NNTP
Machine = vn_env("VNMACHINE",DEF_MACHINE);
#ifndef SHOW_FROM
Postfunc = nntp_post;
#endif
#endif
rcname = vn_env("MAILER",DEF_MAIL);
#ifdef INLETTER
sprintf(dbuf,"cat %%s | %s",rcname);
#else
/* used as a format string TWICE (%%%% -> %% -> %) */
sprintf(dbuf,"cat %%%%s | %s %%s",rcname);
#endif
Mailer = str_store(dbuf);
rcname = vn_env("NEWSRC",DEF_NEWSRC);
if (*rcname != '/')
{
sprintf (dbuf, "%s/%s",Home,rcname);
Newsrc = str_store (dbuf);
}
else
Newsrc = str_store (rcname);
}
/*
change directory to group
*/
vns_gset(grp)
char *grp;
{
char dbuf [RECLEN];
#ifdef NNTP
if (Machine != NULL)
{
sprintf(dbuf,"group %s",grp);
if (nntp_put(dbuf,dbuf) < 0)
printex("can't find newsgroup (server: %s)",dbuf);
return;
}
#endif
g_dir (grp,dbuf);
if (chdir(dbuf) < 0)
printex("can't change to newsgroup directory");
}
/*
g_dir converts newsgroup name to directory string
*/
static
g_dir(s,t)
char *s,*t;
{
char *ptr;
sprintf (t,"%s/%s",SPOOLDIR,s);
for (ptr=t+strlen(SPOOLDIR)+1; (ptr = index(ptr,'.')) != NULL; *ptr = '/')
;
}
/*
** myfind is used for hashfind() calls which aren't supposed to fail.
*/
static NODE *
myfind(name)
char *name;
{
NODE *n;
n = hashfind(name);
if (n == NULL)
printex("Unexpected table lookup failure");
return (n);
}
vns_news(argc,argv,lfirst,nun)
int argc;
char **argv;
int *lfirst, *nun;
{
FILE *fp;
static char marks[] =
{
NEWS_ON, NEWS_OFF, '\0'
};
int line, len, num;
char buf [RECLEN], trail, submark, *fret, *ptr;
int optpflag;
++argv;
--argc;
/*
** get .newsrc / server connection affecting options before
** calling fill_active.
*/
arg_opt(argc,argv);
/*
** fill table with active newsgroups - initiates server connection
** if we're talking to NNTP.
*/
fill_active ();
/*
** handle options, now that fill_active has been called.
** Set GF_OVER before calling newsrc_opt, since -S may override it.
*/
if (Optlines > 0)
{
optpflag = 1;
Gflags |= GF_OVER;
newsrc_opt(lfirst,nun);
}
else
optpflag = 0;
if ((fp = fopen (Newsrc,"r")) == NULL)
printex ("can't open %s for reading",Newsrc);
Optlines = 0;
for (line = 1; (fret = fgets(buf,RECLEN-1,fp)) != NULL && emptyline(buf) == 1; ++line)
;
if (fret != NULL && strncmp (buf,"options",7) == 0)
{
Options[0] = str_store(buf);
Optlines = 1;
trail = buf [strlen(buf)-2];
for ( ; (fret = fgets(buf,RECLEN-1,fp)) != NULL; ++line)
{
if (trail != '\\' && buf[0] != ' ' && buf[0] != '\t')
break;
if (Optlines >= OPTLINES)
printex ("%s - too many option lines (%d allowed)",Newsrc,OPTLINES);
Options[Optlines] = str_store(buf);
++Optlines;
if ((len = strlen(buf)) >= 2 && buf[len-2] != '\\')
trail = buf[len-2];
else
trail = '\0';
}
}
/* do the options from the newsrc file if there weren't command line args */
if (Optlines > 0 && ! optpflag )
newsrc_opt (lfirst,nun);
for ( ; fret != NULL; ++line, fret = fgets(buf,RECLEN-1,fp))
{
if (emptyline(buf) == 1)
continue;
if ((ptr = strpbrk(buf,marks)) == NULL)
{
fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
line,Newsrc,buf);
continue;
}
submark = *ptr;
*ptr = '\0';
++ptr;
num = 0;
for (ptr = strtok(ptr," ,-\n"); ptr != NULL; ptr = strtok(NULL," ,-\n"))
{
len = atoi (ptr);
for ( ; *ptr >= '0' && *ptr <= '9'; ++ptr)
;
if (*ptr != '\0' || len < num)
{
num = -1;
fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
line,Newsrc,buf);
break;
}
num = len;
}
if (num < 0)
continue;
chkgroup (buf,submark,num,0);
}
fclose (fp);
/* now take care of groups not specified in .newsrc */
art_active();
/* free up the option string storage */
for (num=0; num < Ntopt; ++num)
regfree (Topt[num]);
for (num=0; num < Nwopt; ++num)
regfree (Wopt[num]);
for (num=0; num < Nntopt; ++num)
regfree (Negtopt[num]);
for (num=0; num < Nnwopt; ++num)
regfree (Negwopt[num]);
Ntopt = Nwopt = Nntopt = Nnwopt = 0;
/* free the active list */
free ((char *) Active);
}
static
emptyline(s)
char *s;
{
while (isspace(*s))
++s;
if (*s == '\0')
return (1);
return (0);
}
/*
fill hash table from active news group list
This is needed to be able to process options
before scanning user order. Constructs an array
of active newsgroup names for the rest of vns_nws().
*/
static
fill_active ()
{
FILE *f;
char *nread, act_rec[RECLEN];
int num,lownum,rcount;
char *(*getfn)();
Max_name = 0;
#ifdef NNTP
if (Machine != NULL)
{
if (server_init(Machine) < 0)
{
printex ("Cannot connect to NNTP server on %s",Machine);
}
Server_open = 1;
getfn = nntp_get;
if (nntp_put("list",act_rec) < 0)
printex ("Couldn't get newsgroup list (server: %s)",act_rec);
}
else
{
getfn = fgets;
if ((f = fopen (ACTFILE,"r")) == NULL)
printex ("couldn't open %s\n",ACTFILE);
}
#else
getfn = fgets;
if ((f = fopen (ACTFILE,"r")) == NULL)
printex ("couldn't open %s\n",ACTFILE);
#endif
/*
** we do things this way so that we only examine active records
** once, minimizing the window where changes could screw us up
** at the cost of possibly alloc'ing a few extra bytes. We start
** with a count of one to have a positive rcount for alloc.
*/
for(rcount=1; (*getfn)(act_rec, RECLEN-1, f) != NULL; ++rcount)
;
if ((Active = (char **) malloc(rcount*sizeof(char *))) == NULL)
printex("Memory allocation failure");
#ifdef NNTP
if (Machine != NULL)
{
if (nntp_put("list",act_rec) < 0)
printex ("Couldn't re-get newsgroup list (server: %s)",act_rec);
}
else
rewind(f);
#else
rewind(f);
#endif
Actnum = 0;
while (Actnum < rcount && (*getfn)(act_rec, RECLEN-1, f) != NULL)
{
if (strtok (act_rec," \n") == NULL)
continue;
nread = strtok (NULL, " \n");
if (nread != NULL)
num = atoi(nread);
else
num = 0;
nread = strtok (NULL, " \n");
if (nread != NULL)
lownum = atoi(nread);
else
lownum = 0;
if (lownum > 0)
--lownum;
if (strlen(act_rec) > Max_name)
Max_name = strlen(act_rec);
/* enter newsgroup, point to permanent copy of name */
hashenter (act_rec, num, lownum);
Active[Actnum] = (myfind(act_rec))->nd_name;
++Actnum;
}
#ifdef NNTP
if (Machine == NULL)
fclose (f);
#else
fclose (f);
#endif
}
/*
check active newsgroups not mentioned in NEWSRC file
(SFLG_SCAN not set)
*/
static
art_active ()
{
int i;
NODE *ptr;
for( i=0; i < Actnum; ++i)
{
ptr = myfind(Active[i]);
if ((ptr->state & SFLG_SCAN) == 0)
chkgroup (ptr->nd_name, NEWS_ON, 0, 1);
}
}
/*
check group for new articles:
s - group
c - subscription indicator from NEWSRC
n - number read
new - new newsgroup flag
*/
static
chkgroup (s,c,n,new)
char *s,c;
int n;
int new;
{
NODE *ptr;
char sub;
int nrd;
int lowart;
int st;
if ((ptr = hashfind(s)) != NULL && (ptr->state & SFLG_SCAN) == 0)
{
ptr->state |= SFLG_SCAN;
#ifdef SYN_CHECK
/* if "read" more than exist, reset */
if (n > ptr->highnum)
{
n = ptr->highnum - SYN_SETBACK;
fgprintf("%s: .newsrc out of synch, resetting\n",s);
}
#endif
lowart = ptr->lownum;
if (n < ptr->lownum)
n = ptr->lownum;
nrd = n;
sub = c;
/*
** scan decision is rather complex, since GF_ALL setting
** overides "n" value, GF_SPEC indicates SFLG_SPEC flag used.
** if GF_OVER set, SFLG_SPEC overides subscription mark, else
** SFLG_SPEC AND subscribed is neccesary.
*/
if ((Gflags & GF_SPEC) != 0)
{
if ((ptr->state & SFLG_SPEC) == 0)
c = NEWS_OFF;
else
{
if ((Gflags & GF_OVER) != 0)
c = NEWS_ON;
}
}
if ((Gflags & GF_ALL) != 0)
n = lowart;
fw_group(s, new, sub == NEWS_ON, nrd, c == NEWS_ON);
if (c == NEWS_ON && ptr->highnum > n)
{
st = outgroup (s,n,ptr->highnum);
if (st > nrd)
fw_chg(new, sub == NEWS_ON, st, c == NEWS_ON);
}
}
#ifdef KEEP_UNK
else
{
/*
** enter unknown group into the list with no articles and
** no scanning for statistics. Simply a device so we'll
** write it back out again after we're done.
*/
if (ptr == NULL)
{
hashenter (s, n, n);
fw_group(s, 0, c == NEWS_ON, n, 0);
}
}
#endif
}
/*
vns_write writes the .newsrc file
*/
vns_write(news,ncount)
NODE **news;
int ncount;
{
FILE *fp;
NODE *p;
char c;
int i,rc;
if (link(Newsrc,Onews) < 0)
printex ("can't backup %s to %s before writing",Newsrc,Onews);
if (unlink(Newsrc) < 0 || (fp = fopen(Newsrc,"w")) == NULL)
printex ("can't open %s for writing (backed up in %s)",Newsrc,Onews);
else
{
clearerr(fp);
for (i=0; (rc = ferror(fp)) == 0 && i < Optlines; ++i)
fprintf (fp,"%s",Options[i]);
for (i=0; rc == 0 && i < ncount; ++i)
{
p = news[i];
if ((p->flags & FLG_SUB) == 0)
c = NEWS_OFF;
else
c = NEWS_ON;
#ifdef OLDRC
fprintf (fp,"%s%c %d\n",p->nd_name,c,p->rdnum);
#else
if (p->rdnum > 0)
fprintf(fp,"%s%c 1-%d\n",p->nd_name,c,p->rdnum);
else
fprintf(fp,"%s%c 0\n",p->nd_name,c);
#endif
rc = ferror(fp);
}
fclose (fp);
if (rc != 0)
printex ("write of %s failed, old copy stored in %s",Newsrc,Onews);
else
unlink (Onews);
}
}
/*
arg_opt must be called prior to option scanning, since
it uses the options array. This is a bit of a kludge,
but it saves a bunch of work. NOTE - no command name argument
This also processes the arguments which don't correspond to
the .newsrc options - these arguments are all flagged with '+'
*/
static
arg_opt (argc,argv)
int argc;
char **argv;
{
int i;
char bufr[RECLEN];
Optlines = 0;
for (i=0; i < argc; ++i,++argv)
{
if (**argv == '+')
{
++(*argv);
switch (**argv)
{
#ifdef NNTP
case 't':
++(*argv);
if (**argv == '\0')
{
++argv;
++i;
}
Fp_trace = fopen(*argv,"w");
break;
case 'l':
Machine = NULL;
break;
case 'm':
++(*argv);
if (*(Machine = *argv) == '\0')
{
++argv;
++i;
Machine = *argv;
}
break;
#endif
case 'n':
++(*argv);
if (*(Newsrc = *argv) == '\0')
{
++argv;
++i;
Newsrc = *argv;
}
if (*Newsrc != '/')
{
sprintf(bufr,"%s/%s",Home,Newsrc);
Newsrc = str_store(bufr);
}
break;
default:
printex("unknown option, +%c",**argv);
}
continue;
}
if (Optlines >= OPTLINES)
printex ("too many command line options (%d allowed)\n",
OPTLINES);
Options[Optlines] = *argv;
++Optlines;
}
/* now that we have machine name, resolve Poster command, Fmach */
#ifdef NNTP
/* make an empty machine synonomous with NULL */
if (Machine != NULL && *Machine == '\0')
Machine = NULL;
if (Machine != NULL)
{
#ifdef FROM_REAL
gethostname(bufr,RECLEN/2);
Fmach = str_store(bufr);
#ifdef MACH_CONCAT
sprintf(bufr,"%s!%s",Machine,Fmach);
Fmach = str_store(bufr);
#endif
#else
Fmach = Machine;
#endif
Poster = vn_env("VNPOSTER",DEF_POST);
sprintf(bufr,Poster,Machine);
Poster = str_store(bufr);
}
else
{
Postfunc = NULL;
Poster = vn_env("VNPOSTER",LOC_POST);
}
#else
Poster = vn_env("VNPOSTER",DEF_POST);
#endif /* NNTP */
sprintf(bufr,"%s %%s",Poster);
Poster = str_store(bufr);
if (access (Newsrc,0) != 0)
creat (Newsrc,0666);
strcpy(bufr,Newsrc);
strcpy(rindex(bufr,'/')+1,".vnXXXXXX");
mktemp(bufr);
Onews = str_store (bufr);
}
/*
option setting routine:
sets global flags: GF_ALL for -x option GF_SPEC for -n.
sets up filter array for article scanning
*/
static
newsrc_opt(lfirst,nun)
int *lfirst, *nun;
{
int i;
char curopt,tmp[RECLEN],*tok;
*nun = *lfirst = 0;
Ntopt = Nwopt = Nnwopt = Nntopt = 0;
curopt = '\0';
for (i=0; i < Optlines; ++i)
{
strcpy(tmp,Options[i]);
for (tok = strtok(tmp,",\\ \t\n"); tok != NULL; tok = strtok(NULL,",\\ \t\n"))
{
if (*tok != '-')
do_opt (curopt,tok);
else
{
for (++tok; index("nwt",*tok) == NULL; ++tok)
{
/* options with no strings */
switch(*tok)
{
case 'S':
Gflags &= ~GF_OVER;
break;
case '%':
*lfirst = 1;
break;
case 'U':
*nun = 1;
break;
#ifdef OLDRC
case 'i':
/* Treat "-i" as synonym for "-x" */
#endif
case 'x':
Gflags |= GF_ALL;
default:
break;
}
}
curopt = *tok;
if (*(++tok) != '\0')
do_opt (curopt,tok);
}
}
}
}
/* do_opt is for options with strings attached */
static
do_opt (opt,str)
char opt, *str;
{
switch (opt)
{
case 'n':
Gflags |= GF_SPEC;
specmark(str);
break;
case 'w':
specfilter (FIL_AUTHOR,str);
break;
case 't':
specfilter (FIL_TITLE,str);
break;
default:
#ifdef OLDRC
Gflags |= GF_SPEC; /* Assume anything else is newsgroup */
specmark(str);
#endif
break;
}
}
static
specfilter (comp,str)
char comp,*str;
{
int *count;
char **rex;
/*
** we may set rex one past end of array. we will error before
** referencing it if that's the case, however.
*/
if (*str == '!')
{
if (comp == FIL_TITLE)
{
count = &Nntopt;
rex = Negtopt + *count;
}
else
{
count = &Nnwopt;
rex = Negwopt + *count;
}
++str;
}
else
{
if (comp == FIL_TITLE)
{
count = &Ntopt;
rex = Topt + *count;
}
else
{
count = &Nwopt;
rex = Wopt + *count;
}
}
if (*count >= NUMFILTER)
printex ("too many %c options, %d allowed",comp,NUMFILTER);
if ((*rex = regcmp(str,(char *) 0)) == NULL)
printex ("%c option regular expression syntax: %s",comp,str);
++(*count);
}
/*
handle the newsgroup specification string.
("all" convention - braack!!!)
*/
static
specmark (s)
char *s;
{
unsigned ormask,andmask;
int i,len;
char *ptr,*re,pattern[RECLEN];
NODE *nptr;
if (*s == '!')
{
++s;
ormask = 0;
andmask = ~SFLG_SPEC;
if (*s == '\0')
return;
}
else
{
ormask = SFLG_SPEC;
andmask = 0xffff;
}
/* convert "all" not bounded by alphanumerics to ".*". ".all" becomes ".*" */
for (ptr = s; (len = findall(ptr)) >= 0; ptr += len+1)
{
if (len > 0 && isalnum (ptr[len-1]))
continue;
if (isalnum (ptr[len+3]))
continue;
if (len > 0 && ptr[len-1] == '.')
{
--len;
strcpy (ptr+len,ptr+len+1);
}
ptr[len] = '.';
ptr[len+1] = '*';
strcpy (ptr+len+2,ptr+len+3);
}
/* now use regular expressions */
sprintf (pattern,"^%s$",s);
if ((re = regcmp(pattern,(char *) 0)) == NULL)
printex ("n option regular expression syntax: %s",s);
for (i=0; i < Actnum; ++i)
{
nptr = myfind(Active[i]);
if (regex(re,nptr->nd_name) != NULL)
{
nptr->state |= ormask;
nptr->state &= andmask;
}
}
regfree (re);
}
static
findall (s)
char *s;
{
int len;
for (len=0; *s != '\0'; ++s,++len)
{
if (*s == 'a' && strncmp(s,"all",3) == 0)
return (len);
}
return (-1);
}
static
grp_indic (s,ok,serr)
char *s;
int ok;
char *serr; /* only used for NNTP */
{
if (ok)
{
fgprintf(" %s\n",s);
return;
}
#ifdef NNTP
if (Machine != NULL)
{
fgprintf(" %s, server: %s\n",s,serr);
return;
}
#endif
fgprintf(" %s - Can't access spool directory\n",s);
}
/*
enter newsgroup articles.
all articles between low and hi are to be included.
Returns the highest number less than an OPENED (not neccesarily
accepted) article to allow caller to revise "articles read"
number beyond non-existent articles.
*/
outgroup (s,low,hi)
char *s;
int low,hi;
{
int i;
char subj[RECLEN], lines[RECLEN], auth[RECLEN], gd[RECLEN];
int ret,op;
ret = low;
op = 1;
if ((hi-low) > MAXARTRANGE)
low = hi - MAXARTRANGE;
#ifdef NNTP
if (Machine != NULL)
{
sprintf(gd,"group %s",s);
if (nntp_put(gd,gd) < 0)
{
grp_indic(s,0,gd);
return (ret);
}
}
else
{
g_dir(s,gd);
if (chdir(gd) < 0)
{
grp_indic(s,0);
return (ret);
}
}
#else
g_dir(s,gd);
if (chdir(gd) < 0)
{
grp_indic(s,0);
return (ret);
}
#endif /* NNTP */
grp_indic(s,1);
for (i=low+1; i <= hi; ++i)
{
if (digname(i,subj,lines,auth,&op) >= 0)
{
fw_art(i,subj,lines,auth);
}
else
{
if (op)
ret = i;
}
}
return(ret);
}
/*
** open article and interpret options, if any. The op parameter is set
** to ZERO if and only if an article is opened. Used above as a flag to
** indicate no articles opened yet.
*/
static digname (n, subj, lines, auth, op)
int n;
char *subj, *lines, *auth;
int *op;
{
int i,j;
char t[RECLEN];
FILE *fp;
char *(*getfn)();
char *nfgets();
char *got;
/* open article */
#ifdef NNTP
if (Machine != NULL)
{
sprintf (t,"head %d", n);
if (nntp_put(t,t) < 0)
return (-1);
getfn = nntp_get;
}
else
{
sprintf (t,"%d", n);
if ((fp = fopen(t,"r")) == NULL)
return (-1);
getfn = nfgets;
}
#else
getfn = nfgets;
sprintf (t,"%d", n);
if ((fp = fopen(t,"r")) == NULL)
return (-1);
#endif
*op = 0;
/* get subject, from and lines by reading article */
subj[0] = lines[0] = auth[0] = '?';
subj[1] = lines[1] = auth[1] = '\0';
for (i = 0; i < HDR_LINES && (got = (*getfn)(t,RECLEN-1,fp)) != NULL; ++i)
{
if (index(CHFIRST,t[0]) == NULL)
continue;
t[strlen(t) - 1] = '\0';
if (strncmp(T_head,t,THDLEN) == 0)
{
for (j=0; j < Nntopt; ++j)
{
if (regex(Negtopt[j],t+THDLEN) != NULL)
{
digclose(fp,got);
return(-1);
}
}
if (Ntopt > 0)
{
for (j=0; j < Ntopt; ++j)
{
if (regex(Topt[j],t+THDLEN) != NULL)
break;
}
if (j >= Ntopt)
{
digclose(fp,got);
return(-1);
}
}
strcpy(subj,t+THDLEN);
continue;
}
if (strncmp(F_head,t,FHDLEN) == 0)
{
for (j=0; j < Nnwopt; ++j)
{
if (regex(Negwopt[j],t+FHDLEN) != NULL)
{
digclose(fp,got);
return(-1);
}
}
if (Nwopt > 0)
{
for (j=0; j < Nwopt; ++j)
{
if (regex(Wopt[j],t+FHDLEN) != NULL)
break;
}
if (j >= Nwopt)
{
digclose(fp,got);
return(-1);
}
}
strcpy(auth,t+FHDLEN);
continue;
}
if (strncmp(L_head,t,LHDLEN) == 0)
{
strcpy(lines,t+LHDLEN);
break;
}
}
digclose(fp,got);
/* reject empty or 1 line files */
if (i < 2)
return (-1);
return (0);
}
/*
** "close" open article from digname - "got" is not used in non-NNTP case
*/
digclose(fp,got)
FILE *fp;
char *got;
{
#ifdef NNTP
char bufr[RECLEN];
if (Machine == NULL)
fclose (fp);
else
{
/*
** have to finish getting the header lines from the
** server
*/
while (got != NULL)
got = nntp_get(bufr,RECLEN-1,fp);
}
#else
fclose (fp);
#endif
}
/*
** special fgets for reading header lines, which unfolds continued lines
** and throws away trailing stuff on buffer overflow.
*/
static char *
nfgets(buf, size, fp)
char *buf;
int size;
FILE *fp;
{
register int c;
while (!feof(fp))
{
if ((c = getc(fp)) == '\n')
{
if ((c = getc(fp)) == '\t' || c == ' ')
continue;
ungetc(c, fp);
*buf = '\n';
++buf;
*buf = '\0';
++buf;
return (buf);
}
/* prevent "terminal bombs" */
if (c < ' ' || c == '\177')
{
switch(c)
{
case '\r':
case '\010':
case '\07':
break;
case '\177':
c = '~';
break;
case '\t':
c = ' ';
break;
default:
if (size > 1)
{
*buf = '^';
++buf;
--size;
}
c += 'A' - 1;
break;
}
}
if (size > 0)
{
*buf = c;
++buf;
--size;
}
if (c == '\r')
{
if ((c = getc(fp)) != '\n')
{
ungetc(c, fp);
continue;
}
if ((c = getc(fp)) != ' ' && c != '\t')
{
*buf = '\0';
++buf;
ungetc(c, fp);
return (buf);
}
--buf;
++size;
continue;
}
}
*buf = '\0';
++buf;
return (NULL);
}
static char *Mail[2], *Show[6], *Post[5];
static char *Priv[8];
static char *Pool = NULL;
FILE *
vns_aopen(art,hdr)
int art;
ARTHEADER *hdr;
{
char buf[RECLEN];
char *dist, *reply, *from, *ngrp, *flto, *path, *resubj;
FILE *fp;
FILE *a_open();
int n;
char *mail_trim();
dist = resubj = path = reply = from = ngrp = flto = NULL;
fp = a_open(art);
if (fp == NULL)
return(NULL);
/*
** we only really need a lot extra if MAILCHOOSE, but allocating
** a temporary array of pointers isn't that much. Similarly, a
** few assignments, and the "Priv" declaration are only needed
** with some define settings. Not worth ifdef'ing.
*/
Pool = str_tpool(100);
hdr->artid = "<some article>";
hdr->from = "<somebody>";
hdr->priv = Priv;
hdr->postcmd = Poster;
hdr->mail = Mail;
hdr->show = Show;
hdr->post = Post;
hdr->priv_num = hdr->show_num = hdr->post_num = hdr->mail_num = 0;
/* for conditional is abnormal - expected exit is break */
for (n=0; n < HDR_LINES && fgets(buf,RECLEN-1,fp) != NULL; ++n)
{
/* bail out at first non-header line */
if (buf[0] == '\n')
break;
if (strncmp(buf,RT_head,RTHDLEN) == 0)
{
buf [strlen(buf)-1] = '\0';
reply = str_tstore(Pool,buf+RTHDLEN);
continue;
}
if (strncmp(buf,P_head,PHDLEN) == 0)
{
buf [strlen(buf)-1] = '\0';
path = str_tstore(Pool,buf+PHDLEN);
continue;
}
if (strncmp(buf,DIS_head,DISHDLEN) == 0)
{
buf [strlen(buf)-1] = '\0';
dist = str_tstore(Pool,buf);
continue;
}
if (strncmp(buf,M_head,MHDLEN) == 0)
{
buf [strlen(buf)-1] = '\0';
hdr->artid = str_tstore(Pool,buf+MHDLEN);
continue;
}
if (strncmp(buf,F_head,FHDLEN) == 0)
{
buf [strlen(buf)-1] = '\0';
(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
from = hdr->from = (hdr->show)[hdr->show_num]+FHDLEN;
++(hdr->show_num);
continue;
}
if (strncmp(buf,T_head,THDLEN) == 0)
{
buf [strlen(buf)-1] = '\0';
(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
if (strncmp(buf+THDLEN,Fpfix,FPFLEN) != 0)
{
sprintf(buf,"%s%s%s",T_head,Fpfix,
((hdr->show)[hdr->show_num])+THDLEN);
resubj = str_tstore(Pool,buf);
}
else
resubj = (hdr->show)[hdr->show_num];
++(hdr->show_num);
continue;
}
if (strncmp(buf,N_head,NHDLEN) == 0)
{
buf [strlen(buf)-1] = '\0';
/* if multiple newsgroups, include in "show" */
if (index(buf,',') != NULL)
{
(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
ngrp = (hdr->show)[hdr->show_num] + NHDLEN;
++(hdr->show_num);
}
else
ngrp = str_tstore(Pool,buf+NHDLEN);
continue;
}
if (strncmp(buf,FT_head,FTHDLEN) == 0)
{
buf [strlen(buf)-1] = '\0';
(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
flto = (hdr->show)[hdr->show_num] + FTHDLEN;
++(hdr->show_num);
continue;
}
if (strncmp(buf,L_head,LHDLEN) == 0)
{
buf [strlen(buf)-1] = '\0';
hdr->lines = atoi(buf+LHDLEN);
(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
++(hdr->show_num);
continue;
}
}
hdr->hlines = n;
#ifdef MAILCHOOSE
(hdr->priv)[hdr->priv_num] = resubj;
++(hdr->priv_num);
if (reply != NULL)
{
(hdr->priv)[hdr->priv_num] = mail_trim(reply);
++(hdr->priv_num);
}
if (from != NULL)
{
(hdr->priv)[hdr->priv_num] = mail_trim(from);
++(hdr->priv_num);
}
if (path != NULL)
{
(hdr->priv)[hdr->priv_num] = mail_trim(path);
++(hdr->priv_num);
}
#else
#ifdef MAILSMART
if (reply == NULL)
if (from != NULL)
reply = from;
else
{
if (path != NULL)
reply = path;
}
#else
if (path != NULL)
reply = path;
#endif
if (reply != NULL)
reply = mail_trim(reply);
mail_cmd(hdr,reply,resubj);
#endif /* MAILCHOOSE */
if (flto == NULL)
{
if ((flto = ngrp) == NULL)
flto = "group.unknown";
}
ngrp = rindex(flto,'.');
if (strncmp("mod.",flto,4) == 0 ||
(ngrp != NULL && strcmp(".announce",ngrp) == 0))
{
sprintf(buf,"Cannot post a follow-up to \"%s\", reply with mail to moderator",flto);
hdr->post_err = str_tstore(Pool,buf);
return (fp);
}
if (ngrp != NULL && strcmp(ngrp,".general") == 0)
{
*ngrp = '\0';
sprintf(buf,"%s%s.followup",N_head,flto);
}
else
sprintf(buf,"%s%s",N_head,flto);
flto = str_tstore(Pool,buf);
hdr->post_err = NULL;
if (resubj != NULL)
{
(hdr->post)[hdr->post_num] = resubj;
++(hdr->post_num);
}
#ifdef NNTP
#ifdef SHOW_FROM
if (Machine != NULL)
{
sprintf(buf,FROM_CR_FORM, F_head, Username, Fmach, Userdesc);
(hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
++(hdr->post_num);
}
#else
#ifdef REPLY_CR_FORM
if (Machine != NULL)
{
sprintf(buf,REPLY_CR_FORM, RT_head, Username, Fmach);
(hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
++(hdr->post_num);
}
#endif
#endif
#endif
(hdr->post)[hdr->post_num] = flto;
++(hdr->post_num);
sprintf(buf,"%s%s",R_head,hdr->artid);
(hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
++(hdr->post_num);
if (dist != NULL)
{
(hdr->post)[hdr->post_num] = dist;
++(hdr->post_num);
}
return (fp);
}
#ifdef MAILCHOOSE
/*
** routine to prompt user for mail path approval
*/
static
mail_prompt(hdr)
ARTHEADER *hdr;
{
int i;
char buf[RECLEN],*ptr;
tty_set(SAVEMODE);
for (i=1; i < hdr->priv_num; ++i)
{
printf("%d - %s\n",i,(hdr->priv)[i]);
}
printf("\nType number to choose one of the above, or input address: ");
fgets(buf,RECLEN-1,stdin);
tty_set(RESTORE);
ptr = strtok(buf," \t\n");
if (ptr == NULL)
ptr = "";
i = strlen(ptr);
if (i == 1)
{
i = atoi(ptr);
if (i > 0 && i <= hdr->priv_num)
ptr = (hdr->priv)[i];
i = 1;
}
/*
** If the user keeps cycling through here on the same article,
** we will eventually run out of strings. We made Pool large
** enough to make it unlikely (user will have to retry about 80
** times without switching articles). Hardly elegant, but should
** be sufficient.
*/
if (i > 1 && hdr->priv_num < 8)
{
(hdr->priv)[hdr->priv_num] = str_tstore(Pool,ptr);
++(hdr->priv_num);
}
mail_cmd(hdr,ptr,(hdr->priv)[0]);
}
#endif
/*
** trim () off potential mail address, and make copy if needed.
** addr must be allocated string.
*/
static char *
mail_trim(addr)
char *addr;
{
char buf[RECLEN];
char *ptr;
if (index(addr,'(') == NULL)
return(addr);
strcpy(buf,addr);
ptr = index(buf,'(');
for (--ptr; *ptr == ' ' || *ptr == '\t'; --ptr)
;
++ptr;
*ptr = '\0';
return (str_tstore(Pool,buf));
}
/*
** format mail command. Subj must point to allocated string.
*/
static
mail_cmd(hdr,addr,subj)
ARTHEADER *hdr;
char *addr, *subj;
{
char buf[RECLEN];
if (addr == NULL || *addr == '\0')
{
hdr->mail_err = "No address";
return;
}
hdr->mail_err = NULL;
;
#ifdef INLETTER
hdr->mailcmd = Mailer;
sprintf(buf,"%s%s",TO_head,addr);
(hdr->mail)[0] = str_tstore(Pool,buf);
hdr->mail_num = 1;
#else
sprintf(buf,Mailer,addr);
hdr->mailcmd = str_tstore(Pool,buf);
hdr->mail_num = 0;
#endif
if (subj != NULL)
{
(hdr->mail)[hdr->mail_num] = subj;
++(hdr->mail_num);
}
}
static FILE
*a_open(art)
int art;
{
FILE *fp;
char buf[RECLEN];
#ifdef NNTP
char cmd[RECLEN];
if (Machine == NULL)
{
sprintf(buf,"%d",art);
fp = fopen(buf,"r");
return (fp);
}
tmpnam(buf);
if ((fp = fopen(buf,"w")) == NULL)
return (NULL);
sprintf(cmd,"head %d",art);
if (nntp_put(cmd,cmd) < 0)
{
fclose(fp);
unlink(buf);
return(NULL);
}
while (nntp_get(cmd,RECLEN) != NULL)
fprintf(fp,"%s",cmd);
fprintf(fp,"\n");
sprintf(cmd,"body %d",art);
if (nntp_put(cmd,cmd) >= 0)
{
while (nntp_get(cmd,RECLEN) != NULL)
fprintf(fp,"%s",cmd);
}
fclose(fp);
fp = fopen(buf,"r");
/* "invisible" article - FP opened to unlinked file */
unlink(buf);
return(fp);
#else
sprintf(buf,"%d",art);
fp = fopen(buf,"r");
return (fp);
#endif
}
vns_aclose(fp)
FILE *fp;
{
if (Pool != NULL)
str_tfree(Pool);
Pool = NULL;
fclose(fp);
}
/*
** we don't use the count / name / mode arguments because this doesn't
** implement any fancy article massaging
*/
vns_asave(art,fp)
int art;
FILE *fp;
{
char buf[RECLEN];
FILE *fin;
fin = a_open(art);
while (fgets(buf,RECLEN-1,fin) != NULL)
fputs(buf,fp);
fclose(fin);
}
vns_exit()
{
#ifdef NNTP
if (Fp_trace != NULL)
{
fprintf(Fp_trace,"Close Server\n");
fclose(Fp_trace);
}
if (Server_open)
close_server();
#endif
}
#ifdef NNTP
/*
** nntp_get returns char* so it can be used interchangeably with fgets
** it appends a newline for the same reason.
*/
char *
nntp_get(buf,len)
char *buf;
int len;
{
if (get_server(buf,len-1) < 0)
return(NULL);
len = strlen(buf);
if (len == 0 || (len > 0 && buf[len-1] != '\n'))
strcpy(buf+len,"\n");
if (Fp_trace != NULL)
fprintf(Fp_trace,"Got - %s",buf);
if (buf[0] == '.' && buf[1] == '\n')
return(NULL);
return(buf);
}
/*
** returns failure explanation in estr - estr = str is legal
*/
nntp_put(str,estr)
char *str;
char *estr;
{
if (Fp_trace != NULL)
fprintf(Fp_trace,"Send - %s\n",str);
put_server(str);
estr[0] = CHAR_INF;
while (estr[0] == CHAR_INF)
{
if (get_server(estr,RECLEN-1) < 0)
{
if (Fp_trace != NULL)
fprintf(Fp_trace,"Ack - no response\n",estr);
strcpy(estr,"no response");
return(-1);
}
if (Fp_trace != NULL)
fprintf(Fp_trace,"Ack - %s\n",estr);
}
if (estr[0] != CHAR_OK)
return (-1);
return(0);
}
/*
** if not letting the user edit the From line, we have to hack one in
** ourselves to prevent getting the thing posted from "news". This
** will effectively defeat any that the user may have added, also.
*/
#ifndef SHOW_FROM
nntp_post(hdr,fn)
ARTHEADER *hdr;
char *fn;
{
char tname[80];
char bufr[RECLEN];
FILE *fin,*fout;
tmpnam(tname);
if ((fin = fopen(fn,"r")) == NULL || (fout = fopen(tname,"w")) == NULL)
{
printf("Can't open article files\n");
return;
}
fprintf(fout,FROM_CR_FORM, F_head, Username, Fmach, Userdesc);
fprintf(fout,"\n");
while (fgets(bufr,RECLEN-1,fin) != NULL)
fprintf(fout,"%s",bufr);
fclose(fin);
fclose(fout);
sprintf(bufr,hdr->postcmd,tname);
system(bufr);
printf("Given to posting program.\n");
unlink(tname);
}
#endif /* SHOW_FROM */
#endif /* NNTP */