v09i073: newsclip 1.1, part 4 of 15
Brad Templeton
brad at looking.ON.CA
Wed Dec 20 12:23:44 AEST 1989
Posting-number: Volume 9, Issue 73
Submitted-by: brad at looking.ON.CA (Brad Templeton)
Archive-name: newsclip/part04
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 4 (of 15)."
# Contents: article.c comp/lex.c comp/predef.c group.c userlib.c
# whoami.c
# Wrapped by allbery at uunet on Tue Dec 19 20:09:55 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'article.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'article.c'\"
else
echo shar: Extracting \"'article.c'\" \(7411 characters\)
sed "s/^X//" >'article.c' <<'END_OF_FILE'
X
X
X#include "nl.h"
X
X/*
X * Master routine to call the user's code on an article
X * Returns true if the article is to be accepted.
X */
X
X /*
X * Newsclip(TM) Library Source Code.
X * Copyright 1989 Looking Glass Software Limited. All Rights Reserved.
X * Unless otherwise licenced, the only authorized use of this source
X * code is compilation into a binary of the newsclip library for the
X * use of licenced Newsclip customers. Minor source code modifications
X * are allowed.
X * Use of this code for a short term evaluation of the product, as defined
X * in the associated file, 'Licence', is permitted.
X */
X
X
Xint num_links; /* number of links to file */
Xint article_size; /* size of article in bytes */
Xdatehold write_time; /* time article was written */
Xnewsgroup dir_newsgroup; /* directory newsgroup */
Xint distribution_level; /* level of distribution for this article */
Xint accept_all = 0; /* accept all articles in a group? */
Xint reject_all = 0; /* reject all articles in a group? */
X
Xusername dummy_user = {
X"", ""
X};
X
X#include <sys/stat.h>
X
Xstatic FILE *art_desc; /* article descriptor */
X
Xbool
Xaccept_article( filename )
Xchar *filename; /* name of the article file, or null if a pipe */
X{
X struct stat ourstat; /* stat of file, if possible */
X extern bool needs_stat; /* is a stat of the article needed? */
X extern datehold time_now; /* time this program was run */
X extern newsgroup main_newsgroup; /* the 'current newsgroup' */
X extern array *newsgroups; /* array of newsgroups for this art */
X extern int extra_groups; /* number of temporary groups */
X extern int ex_group_base; /* base for temporary group count */
X extern int score; /* score of article test */
X extern int io_mode; /* style of article reading */
X FILE *art; /* file stream of the article */
X bool filemode; /* are we using a file */
X extern char *article_filename; /* global for user program */
X extern int reading_mode; /* style of file reading */
X
X /* first we check if global accept/reject flags are on for this group */
X
X if( accept_all ) {
X score = 1000;
X return TRUE;
X }
X else if( reject_all ) {
X score = -1000;
X return FALSE;
X }
X
X score = 1; /* default is to accept */
X
X filemode = reading_mode != PIPE_READ;
X
X /* Next open the file, if the article is indeed in a file */
X
X if( filemode ) {
X art = fopen( filename, "r" );
X
X if( !art ) {
X warning( 3, "Could not open article %s\n", filename );
X score = -1;
X return FALSE;
X }
X article_filename = filename;
X }
X else {
X art = (FILE *)0;
X article_filename = "";
X }
X
X /* Get statistics from the inode if the article is in a file and
X the user program wants these statistics */
X
X if( needs_stat && reading_mode == FILE_FULL &&
X fstat( fileno(art), &ourstat ) == 0 ) {
X num_links = ourstat.st_nlink;
X if( (int)ourstat.st_size != ourstat.st_size )
X article_size = MAXINT;
X else
X article_size = ourstat.st_size;
X write_time = (datehold)ourstat.st_mtime;
X }
X else {
X num_links = 1;
X article_size = -1;
X write_time = time_now;
X }
X
X /* clear region for temporary newsgroups */
X extra_groups = ex_group_base;
X
X /* scan the header. If there are fewer than 3 header items
X in it, it's a bogus article and is rejected */
X if( reading_mode != FILE_FULL )
X if( ask_for_header() == ERRCODE )
X return ERRCODE;
X
X if( read_header( art ) < 3 ) {
X warning( 3, "Invalid header in file %s\n", article_filename );
X return FALSE;
X }
X
X
X /* An article without a Newsgroups line is a bogus one */
X if( newsgroups == (array *)0 ) {
X warning( 3, "Missing Newsgroups in file %s\n", article_filename );
X return FALSE;
X }
X
X /* Initialize the routines that might scan the article body */
X
X prepare_body( io_mode );
X
X /* If there isn't really a current newsgroup, invent one by
X taking the first group on the newsgroups line */
X
X if( main_newsgroup == NULL_NEWSGROUP )
X main_newsgroup = newsgroups->vals[0].uinteger;
X
X /* Set the newsgroup expanded in ~N codes in filenames */
X
X dir_newsgroup = main_newsgroup;
X
X /* prepare the calculated items */
X calc_items();
X
X /* now run the code on the article */
X
X art_desc = art; /* external with file descriptor */
X
X /* call the user routines that set the score and deal with it */
X
X Uarticle();
X Upost_article(score);
X
X
X if( filemode && art )
X fclose( art );
X
X /* A positive score means accept. 0 or less is reject */
X
X return score > 0;
X}
X
Xusername *rsender; /* Sender, or From: if no sender */
Xusername *rreply_to; /* Reply-to, or From: if no reply-to */
Xarray *rdistribution; /* Distribution, or newsgroups if none */
Xarray *rfollowup_to; /* followup-to, or newsgroups if none */
Xint followup; /* indicates if the message is a followup */
X
X/* This routine generates the guaranteed defined field variables, for
X header items that are optional, but which have a default should they
X not be present */
X
Xcalc_items()
X{
X /* various header items we calculate from */
X extern username *sender;
X extern username *from;
X extern username *reply_to;
X extern char *subject;
X extern char *message_id;
X extern array *distribution;
X extern array *followup_to;
X extern array *newsgroups;
X extern int followup;
X extern array *references;
X extern bool wants_dist; /* does the user need a
X distribution calculation? */
X extern int distribution_level;
X
X /* Set up dummys if the required headers are missing */
X /* Usually if this happens we have a manged article and should
X probably reject it */
X
X if( from == (username *)0 )
X from = &dummy_user;
X if( subject == (char *)0 )
X subject = "";
X if( message_id == (char *)0 )
X message_id = "<NULL>";
X
X rsender = sender ? sender : from;
X rreply_to = reply_to ? reply_to : from;
X rdistribution = distribution && distribution->arsize > 0 ?
X distribution : newsgroups;
X rfollowup_to = followup_to ? followup_to : newsgroups;
X followup = references && references->arsize > 0;
X
X /* figure out the integer representing the widest distribution
X this article will get */
X
X if( wants_dist ) {
X int i;
X int gdist;
X int newsgroup_glevel;
X distribution_level = 1; /* local */
X
X /* find the maximal distribution from dist line */
X for( i = 0; i < rdistribution->arsize; i++ ) {
X gdist = ngarray[rdistribution->vals[i].uinteger]
X ->distribution;
X if( gdist > distribution_level )
X distribution_level = gdist;
X }
X newsgroup_glevel = 1;
X for( i = 0; i < newsgroups->arsize; i++ ) {
X gdist = ngarray[newsgroups->vals[i].uinteger]
X ->distribution;
X if( gdist > newsgroup_glevel )
X newsgroup_glevel = gdist;
X }
X /* if the groups had a smaller distribution, use it, as
X the distribution line only restricts distribution,
X it does not expand it */
X if( newsgroup_glevel < distribution_level )
X distribution_level = newsgroup_glevel;
X }
X
X}
X
X/* Routine called by body reading code to get file descriptor */
X
XFILE *
Xget_body_desc(size)
Xint size;
X{
X extern int reading_mode;
X if( reading_mode != FILE_FULL )
X ask_for_body();
X return art_desc;
X}
X
X/* This function gets the size of the article for user programs */
X
Xart_bytes()
X{
X extern int header_size;
X long calc_size;
X
X if( article_size >= 0 )
X return article_size;
X else
X return makeint((long)header_size + byte_count(7));
X}
X
X/* When the current group changes, we call user code and clear global
X accept/reject flags */
X
Xfinish_group()
X{
X extern int accept_all, reject_all; /* global flags */
X
X Uendgroup();
X accept_all = reject_all = FALSE;
X}
END_OF_FILE
if test 7411 -ne `wc -c <'article.c'`; then
echo shar: \"'article.c'\" unpacked with wrong size!
fi
# end of 'article.c'
fi
if test -f 'comp/lex.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'comp/lex.c'\"
else
echo shar: Extracting \"'comp/lex.c'\" \(6997 characters\)
sed "s/^X//" >'comp/lex.c' <<'END_OF_FILE'
X
X/*
X * Scanner for the Newsclip compiler. A fairly simple scanner.
X * Handwritten scanners are not complex and are usually smaller and faster
X * than those generated by lex.
X *
X * The only thing fancy here are the 'newsgroup name' tokens, which are
X * always preceded by either a '#' or the 'is' operator/token. These are
X * special because they are not otherwise quoted and can contain things
X * like dashes and plus signs, which would otherwise delimit tokens.
X */
X /*
X * Newsclip(TM) Compiler Source Code.
X * Copyright 1989 Looking Glass Software Limited. All Rights Reserved.
X * Unless otherwise licenced, the only authorized use of this source
X * code is compilation into a binary of the newsclip compiler for the
X * use of licenced Newsclip customers. Minor source code modifications
X * are allowed before compiling.
X * A short time evaluation of this product is also permitted. See the file
X * 'Licence' in the library source directory for details.
X */
X
X#include "nc.h"
X
X#include "y.tab.h"
X
X
X#define EOFCHAR -1
X
Xchar yytext[MAX_LLEN];
Xint yylineno = 0;
Xint column = 0;
Xchar *yyfilename;
Xextern YYSTYPE yylval;
Xint lookaheadchar;
XFILE *yyin; /* Input stream */
X
X#define scanerror yyerror
X
Xextern char *allocstring();
Xextern FILE *trace;
X
X/* number - string base for newsgroup names */
X
X
Xint
Xyylex()
X{
X register c;
X register char *cp;
X int f;
X int toktype;
X char delim;
X/* Temporary violation of indent to give room for bit switch */
X
Xif (yylineno == 0)
X yylineno++;
X
Xwhile(1) {
X /*
X * skip white space
X */
X if (c = lookaheadchar ) {
X lookaheadchar = 0;
X }
X else
X c = readkey();
X
X cp = yytext;
X while (c == ' ' || c == '\t' || c == 0 || c == 12 /* FF */) {
X c = readkey();
X }
X yytext[0] = c; yytext[1] = yytext[2] = 0;
X if( isascii(c) && (isalpha( c ) || c == '_') ) {
X do {
X *cp++ = lowcase(c);
X c = readkey();
X } while (isascii(c) && (isalnum(c) || c == '_'));
X *cp = 0;
X
X lookaheadchar = c;
X /* special newsgroup op */
X if( strcmp( yytext, "is" ) == 0 ) {
X scanng();
X return YQUERYGROUP;
X }
X else {
X c = look_kw(yytext);
X if (c == 0) {
X yylval.strval = allocstring(yytext);
X return (YID);
X }
X return c;
X }
X }
X
X else if( isascii(c) && isdigit(c) ) {
X do {
X *cp++ = c;
X c = readkey();
X } while (isascii(c) && isdigit(c));
X *cp = 0;
X lookaheadchar = c;
X yylval.intval = atoi(yytext);
X return (YINT);
X }
X /* printt2("Select on char %d - %c\n", c, c ); */
X switch (c) {
X case EOF:
X strcpy( yytext, "<End-of-File>" );
X return 0;
X case ' ':
X case '\t':
X case 12: /* form feed */
X break;
X case '"': {
X int backflag;
X backflag = FALSE;
X for(;;){
X c = readkey();
X if( c == '"' && !backflag )
X break;
X if( c == '\n' ) {
X parerror( "Newline in string constant" );
X return YILLCH;
X }
X if( !backflag && c == '\\' )
X backflag = TRUE;
X else
X backflag = FALSE;
X *cp++ = c;
X }
X *cp = 0;
X yylval.strval = allocstring(yytext);
X return (YSTRING);
X }
X case '\'':
X c = readkey();
X if( c == '\\' ) {
X c = readkey();
X switch(c) {
X case 'n':
X c = '\n';
X break;
X case 'r':
X c = '\r';
X break;
X case 't':
X c = '\t';
X break;
X case 'f':
X c = '\f';
X break;
X }
X }
X if( readkey() != '\'' )
X parerror( "Invalid character constant" );
X yylval.intval = c;
X return YINT;
X
X case '\n':
X break;
X case '/':
X c = readkey();
X if( c == '*' ) {/* comment */
X char oldc;
X c = 0;
X do {
X oldc = c;
X c = readkey();
X if( c == EOF )
X parerror( "End of File inside comment" );
X } while( c != '/' || oldc != '*' );
X break;
X }
X else {
X lookaheadchar = c;
X return '/';
X }
X
X /*NOTREACHED*/
X break;
X case '#':
X /* newsgroup or query if a newsgroup is present */
X scanng();
X return YNEWSGROUP;
X case '+':
X if( (c=readkey()) == '+' )
X return INC_OP;
X lookaheadchar = c;
X return '+';
X
X case '-':
X if( (c=readkey()) == '-' )
X return DEC_OP;
X lookaheadchar = c;
X return '-';
X
X case '<':
X if( (c=readkey()) == '=' )
X return LE_OP;
X lookaheadchar = c;
X return '<';
X
X case '>':
X if( (c=readkey()) == '=' )
X return GE_OP;
X lookaheadchar = c;
X return '>';
X
X case '!':
X if( (c=readkey()) == '=' )
X return NE_OP;
X lookaheadchar = c;
X return '!';
X
X case '=':
X if( (c=readkey()) == '=' )
X return EQ_OP;
X lookaheadchar = c;
X return '=';
X case '&':
X if( (c=readkey()) == '&' )
X return AND_OP;
X lookaheadchar = c;
X return '&';
X case '|':
X if( (c=readkey()) == '|' )
X return OR_OP;
X lookaheadchar = c;
X return '|';
X
X case ';':
X case ',':
X case '*':
X case '[':
X case ']':
X case '{':
X case '}':
X case '%':
X case '^':
X case '?':
X case '(':
X case ')':
X case '.':
X case ':':
X return c;
X
X default:
X if (c <= 0)
X return (0);
X do
X lookaheadchar = readkey();
X while (lookaheadchar == c);
X /* printt1("illegal char in scanner %o\n", c); */
X return (YILLCH);
X }
X
X } /* big while */
X}
X
X
Xstruct kwtab {
X char *word;
X int ttype;
X} kwtab[] = {
X "accept", YACCEPT,
X "adjust", YADJUST,
X "array", YARRAY,
X "break", YBREAK,
X "case", YCASE,
X "continue", YCONTINUE,
X "database", YTDATABASE,
X "datetime", YTDATE,
X "default", YDEFAULT,
X "else", YELSE,
X "extern", YEXTERN,
X "for", YFOR,
X "forward", YFORWARD,
X "goto", YGOTO,
X "has", YHAS,
X "header", YHEADER,
X "if", YIF,
X "in", YIN,
X "int", YTINT,
X "newsgroup", YTNEWSGROUP,
X "parse", YPARSE,
X "procedure", YPROCEDURE,
X "reject", YREJECT,
X "return", YRETURN,
X "string", YTSTRING,
X "switch", YSWITCH,
X "userid", YTUSERID,
X "while", YWHILE,
X 0, 0,
X};
X
X
X
Xint
Xlook_kw(str)
Xregister char *str;
X{
X register int l;
X int h, m, r;
X
X
X l=0; h=sizeof(kwtab) / sizeof(kwtab[0]) - 2;
X while (l <= h) {
X m = (l+h)/2;
X r = strcmp(kwtab[m].word, str);
X if (r < 0)
X l = m+1;
X else if (r > 0)
X h = m-1;
X else {
X return kwtab[m].ttype;
X }
X }
X return 0;
X}
X
Xreadkey()
X{
X int c;
X extern int listing;
X
X c = getc(yyin);
X
X if( column == 0 && c == '#' ) {
X char buf[MAX_FNAME+20];
X char *p, *eq;
X char *space;
X int len;
X
X fgets( buf, sizeof(buf), yyin );
X /* accept both # and #line directives */
X space = strchr( buf, ' ' );
X if( space )
X yylineno = atoi( space+1 );
X /* get filename */
X p = strchr( buf, '"' );
X if( p ) {
X p++;
X eq = strchr( p, '"' );
X if( eq )
X *eq = 0;
X if( strcmp( p, yyfilename ) != 0 )
X yyfilename = allocstring( p );
X }
X c = getc(yyin);
X }
X
X if (c == '\n') {
X yylineno++;
X column = 0;
X }
X else
X column++;
X return c;
X}
X
X/* numbered group database structure */
X
Xstruct stringmap thegroups = { 0, 0, 0, 0 };
X
X/* scan a newsgroup name after a newsgroup name prefix token (is|#) */
X
Xscanng()
X{
X int c; /* byte read */
X char *cp; /* pointer into yytext */
X
X cp = yytext;
X
X /* skip whitespace */
X
X do {
X c = readkey();
X } while( isspace(c) );
X while (isascii(c) && (isalnum(c) ||
X strchr( "_-.+", c ) != NULL) ) {
X *cp++ = c;
X c = readkey();
X }
X *cp = 0;
X yylval.intval = nums_lookup( &thegroups, yytext );
X lookaheadchar = c;
X}
X
Xyyerror(s)
Xchar *s;
X{
X parerror( "%s at or near %s", s, yytext );
X}
END_OF_FILE
if test 6997 -ne `wc -c <'comp/lex.c'`; then
echo shar: \"'comp/lex.c'\" unpacked with wrong size!
fi
# end of 'comp/lex.c'
fi
if test -f 'comp/predef.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'comp/predef.c'\"
else
echo shar: Extracting \"'comp/predef.c'\" \(6938 characters\)
sed "s/^X//" >'comp/predef.c' <<'END_OF_FILE'
X#include "nc.h"
X
X/*
X * The predefined symbols
X */
X
X/* These symbols come in a variety of types. Most must be declared as
X an external to be referenced. Some can be referenced without being
X declared. Such variables have OSF_PREDEF on.
X
X Some trigger special actions, such as the inclusion of a header line
X in the header parse list, or the setting of a boolean variable in the
X user code. Header items have SPC_HEADER on.
X
X Various other codes are defined in "nc.h"
X */
X /*
X * Newsclip(TM) Compiler Source Code.
X * Copyright 1989 Looking Glass Software Limited. All Rights Reserved.
X * Unless otherwise licenced, the only authorized use of this source
X * code is compilation into a binary of the newsclip compiler for the
X * use of licenced Newsclip customers. Minor source code modifications
X * are allowed before compiling.
X * A short time evaluation of this product is also permitted. See the file
X * 'Licence' in the library source directory for details.
X */
X
X#define TL static struct typelist
X#define TLL static dtype
X
XTLL dta[] = {T_INTEGER};
XTL oneint = { 1, 1, 1, dta };
X
XTLL doneng[] = {T_NEWSGROUP};
XTL oneng = { 1, 1, 1, doneng };
X
XTLL dts[] = {T_STRING};
XTL onestring = { 1, 1, 1, dts };
X
XTLL dttext[] = {T_TEXT};
XTL onetext = { 1, 1, 1, dttext };
X
XTLL dt2s[] = {T_STRING,T_STRING};
XTL twostring = { 2, 2, 2, dt2s };
X
XTLL dtsi[] = {T_STRING, T_INTEGER};
XTL stringint = { 2, 2, 2, dtsi };
X
XTLL dunam[] = { T_USERNAME };
XTL oneuname = { 1, 1, 1, dunam };
X
XTLL donear[] = { T_GENARRAY };
XTL onearray = { 1, 1, 1, donear };
X
XTLL donedb[] = { T_DATABASE };
XTL onedb = { 1, 1, 1, donedb };
X
XTLL ddbstring[] = { T_DATABASE, T_STRING };
XTL dbstring = { 2, 2, 2, ddbstring };
X
XTLL darb[] = { T_STRING }; /* printf arbitrary arg stream */
XTL strarb = { 1, 255, 1, darb };
X
XTL none = { 0, 0, 0 };
X
XTLL dwrdb[] = { T_DATABASE, T_STRING, T_DATE };
XTL wrdb = { 3, 3, 3, dwrdb };
X
Xstruct outsym predefs[] = {
X{ "approved", ST_VAR, T_USERNAME, SPC_HEADER },
X{ "control", ST_VAR, T_STRING, SPC_HEADER },
X{ "date", ST_VAR, T_DATE, SPC_HEADER },
X{ "distribution", ST_VAR, arrayof(T_NEWSGROUP), SPC_HEADER },
X{ "rdistribution", ST_VAR, arrayof(T_NEWSGROUP), SPC_NEWSGROUPS },
X{ "expires", ST_VAR, T_DATE, SPC_HEADER },
X{ "followup_to", ST_VAR, arrayof(T_NEWSGROUP), SPC_HEADER },
X{ "rfollowup_to", ST_VAR, arrayof(T_NEWSGROUP), SPC_NEWSGROUPS },
X{ "from", ST_VAR, T_USERNAME, SPC_HEADER },
X{ "keywords", ST_VAR, arrayof(T_STRING), SPC_HEADER },
X{ "lines", ST_VAR, T_INTEGER, SPC_HEADER },
X{ "message_id", ST_VAR, T_STRING, SPC_HEADER },
X{ "newsgroups", ST_VAR, arrayof(T_NEWSGROUP), OSF_PREDEF|SPC_HEADER|OSF_REFERENCED },
X{ "organization", ST_VAR, T_STRING, SPC_HEADER },
X{ "path", ST_VAR, arrayof(T_STRING), SPC_HEADER },
X{ "posting_version", ST_VAR, T_STRING, SPC_HEADER },
X{ "references", ST_VAR, arrayof(T_STRING), SPC_HEADER },
X{ "reply_to", ST_VAR, T_USERNAME, SPC_HEADER },
X{ "rreply_to", ST_VAR, T_USERNAME, SPC_FROM },
X{ "sender", ST_VAR, T_USERNAME, SPC_HEADER },
X{ "rsender", ST_VAR, T_USERNAME, SPC_FROM },
X{ "subject", ST_VAR, T_STRING, SPC_HEADER },
X{ "summary", ST_VAR, T_STRING, SPC_HEADER },
X{ "xref", ST_VAR, arrayof(T_STRING), SPC_HEADER },
X/* useful variables */
X{ "followup", ST_VAR, T_INTEGER, SPC_REF },
X{ "score", ST_VAR, T_INTEGER, 0 },
X{ "article_filename", ST_VAR, T_STRING, 0 },
X{ "article_number", ST_VAR, T_INTEGER, 0 },
X{ "article_bytes", ST_VAR, T_INTEGER, OSF_CONST|SPC_STAT },
X{ "num_links", ST_VAR, T_INTEGER, SPC_STAT },
X{ "write_time", ST_VAR, T_DATE, SPC_STAT },
X/* size functions */
X{ "byte_count", ST_FUNC, T_INTEGER, OSF_PREDEF, &onetext },
X{ "line_count", ST_FUNC, T_INTEGER, OSF_PREDEF, &onetext },
X/* calculated variables */
X{ "distribution_level", ST_VAR, T_INTEGER, SPC_DIST},
X/* control variables */
X{ "set_include_prefix", ST_PROC, 0, 0, &onestring },
X{ "preserve_case", ST_VAR, T_INTEGER, 0 },
X{ "paragraph_scan", ST_VAR, T_INTEGER, 0 },
X{ "white_compress", ST_VAR, T_INTEGER, 0 },
X{ "set_signature_start",ST_PROC, 0, 0, &onestring },
X{ "subscribe", ST_PROC, 0, 0, &onestring },
X{ "time_now", ST_VAR, T_DATE, 0 },
X{ "my_domain", ST_VAR, T_STRING, 0 },
X{ "my_mail_address", ST_VAR, T_STRING, 0 },
X{ "options", ST_VAR, arrayof(T_STRING), 0 },
X{ "accept_all", ST_VAR, T_INTEGER, 0 },
X{ "reject_all", ST_VAR, T_INTEGER, 0 },
X{ "main_newsgroup", ST_VAR, T_NEWSGROUP, 0 },
X{ "dir_newsgroup", ST_VAR, T_NEWSGROUP, 0 },
X{ "proc_mode", ST_VAR, T_STRING, 0 },
X/* time and date constants */
X{ "day", ST_VAR, T_DATE, OSF_PREDEF|OSF_CONST },
X{ "week", ST_VAR, T_DATE, OSF_PREDEF|OSF_CONST },
X{ "month", ST_VAR, T_DATE, OSF_PREDEF|OSF_CONST },
X/* special text variables */
X{ "body", ST_VAR, T_TEXT, OSF_PREDEF|OSF_CONST },
X{ "text", ST_VAR, T_TEXT, OSF_PREDEF|OSF_CONST },
X{ "signature", ST_VAR, T_TEXT, OSF_PREDEF|OSF_CONST },
X{ "newtext", ST_VAR, T_TEXT, OSF_PREDEF|OSF_CONST },
X{ "included", ST_VAR, T_TEXT, OSF_PREDEF|OSF_CONST },
X/* null constants */
X{ "false", ST_VAR, T_INTEGER, OSF_PREDEF|OSF_CONST },
X{ "true", ST_VAR, T_INTEGER, OSF_PREDEF|OSF_CONST },
X{ "nilstring", ST_VAR, T_STRING, OSF_PREDEF|OSF_CONST },
X{ "niluserid", ST_VAR, T_USERNAME, OSF_PREDEF|OSF_CONST },
X{ "nildatabase", ST_VAR, T_DATABASE, OSF_PREDEF|OSF_CONST },
X{ "nilnewsgroup", ST_VAR, T_NEWSGROUP, OSF_PREDEF|OSF_CONST },
X{ "nilarray", ST_VAR, T_ARRAY, OSF_PREDEF|OSF_CONST },
X/* Functions, procedures and macros */
X{ "count", ST_FUNC, T_INTEGER, OSF_CONST|OSF_PREDEF,
X &onearray },
X{ "realname", ST_FUNC, T_STRING, OSF_CONST|OSF_PREDEF,
X &oneuname },
X{ "domain", ST_FUNC, T_STRING, 0, &onestring },
X{ "dlevel", ST_FUNC, T_INTEGER, OSF_PREDEF, &oneng },
X{ "chindex", ST_FUNC, T_INTEGER, OSF_CONST, &stringint },
X{ "read_database", ST_FUNC, T_DATABASE, OSF_PREDEF, &onestring},
X{ "exists", ST_FUNC, T_INTEGER, 0, &onestring },
X{ "write_database", ST_PROC, 0, OSF_PREDEF, &wrdb },
X{ "free_database", ST_PROC, 0, OSF_PREDEF, &onedb },
X{ "fresh_database", ST_FUNC, T_DATABASE, OSF_PREDEF, &oneint },
X{ "db_delete", ST_PROC, 0, OSF_PREDEF, &dbstring },
X{ "getenv", ST_FUNC, T_STRING, 0, &onestring },
X{ "dprintf", ST_PROC, 0, OSF_PREDEF, &strarb },
X{ "strlen", ST_FUNC, T_INTEGER, 0, &onestring },
X{ "left", ST_FUNC, T_STRING, 0, &stringint },
X{ "right", ST_FUNC, T_STRING, 0, &stringint },
X{ "concat", ST_FUNC, T_STRING, 0, &twostring },
X{ "drop_re", ST_FUNC, T_STRING, 0, &onestring },
X{ "permstring", ST_FUNC, T_STRING, 0, &onestring },
X{ "clipfront", ST_FUNC, T_STRING, 0, &stringint },
X{ "leftmost", ST_FUNC, T_STRING, 0, &stringint },
X{ "literal\_pattern", ST_FUNC, T_STRING, 0, &onestring },
X{ "lower", ST_FUNC, T_STRING, 0, &onestring },
X{ "named_group", ST_FUNC, T_INTEGER, 0, &oneng },
X{ "newsrc_group", ST_FUNC, T_INTEGER, 0, &oneng },
X{ 0, 0, 0, 0 }
X};
X
X/* some variables that get set based on what is used */
X
Xbool needs_stat = FALSE;
END_OF_FILE
if test 6938 -ne `wc -c <'comp/predef.c'`; then
echo shar: \"'comp/predef.c'\" unpacked with wrong size!
fi
# end of 'comp/predef.c'
fi
if test -f 'group.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'group.c'\"
else
echo shar: Extracting \"'group.c'\" \(6763 characters\)
sed "s/^X//" >'group.c' <<'END_OF_FILE'
X
X/*
X * Routine to handle the processing of newsgroups
X */
X
X /*
X * Newsclip(TM) Library Source Code.
X * Copyright 1989 Looking Glass Software Limited. All Rights Reserved.
X * Unless otherwise licenced, the only authorized use of this source
X * code is compilation into a binary of the newsclip library for the
X * use of licenced Newsclip customers. Minor source code modifications
X * are allowed.
X * Use of this code for a short term evaluation of the product, as defined
X * in the associated file, 'Licence', is permitted.
X */
X
X
X#include "nl.h"
X
Xdbptr ng_base; /* the database of known newsgroup names */
X
Xint group_count; /* count of newsgroups in database */
X
Xngrec **ngarray; /* newsgroup array */
Xngrec **ngarray_base; /* alloced address for newsgroup array */
Xngrec *extra_g_mem; /* memory for extra groups */
X
X/* Initialize the newsgroup database. This may just involve the use
X of the predefined newsgroup names in the user program, or we may read
X in a pile of groups from the .newsrc, .nglas and active files. */
X
Xinitngs(rcmode)
Xbool rcmode; /* true if reading newsrc */
X{
X extern int user_gcount; /* count of user referenced groups */
X ngrec *group; /* group record */
X extern char *user_groupnames[]; /* groups referenced in user code */
X int i;
X
X group_count = 1;
X
X ng_base = init_db( rcmode ? 400 : user_gcount, sizeof(ngrec) );
X
X /* now add the newsgroup names from the user's program */
X
X for( i = 0; user_groupnames[i]; i++ ) {
X group = (ngrec *)add_rec(ng_base, user_groupnames[i],
X AR_CREATE|AR_NOALLOC);
X if( group->ngnumber == 0 )
X group->ngnumber = group_count++;
X }
X
X /* read in data needed to process a .newsrc file */
X if( rcmode ) {
X read_las();
X read_newsrc();
X read_active();
X }
X /* read in and set distributions */
X handle_distrs();
X
X /* now build the newsgroup array */
X ngarray_base = (ngrec **)perm_alloc( (group_count+NG_EXTRAS) *
X sizeof(ngrec *) );
X ngarray = ngarray_base + NG_EXTRAS;
X /* mem for temporary newsgroups */
X extra_g_mem = (ngrec *)perm_alloc( NG_EXTRAS * sizeof(ngrec) );
X
X /* There are NG_EXTRAS negative slots for undefined groups */
X
X for( group = (ngrec *)first_rec(ng_base); group;
X group =next_rec(ng_base,group) )
X ngarray[group->ngnumber] = group;
X ngarray[0] = (ngrec *)0;
X}
X
X/* Read the active file for the latest info on our groups */
X
X/* Note that we don't read in groups in the active file that we
X haven't already seen in the program, .newsrc or .nglas files */
X
Xread_active()
X{
X FILE *afile;
X ngrec *group;
X char buf[MAX_LLEN]; /* line buffer */
X long highart, lowart; /* article limits of newsgroup */
X char *spp; /* space position */
X
X
X afile = dfopen( news_lib_dir, "active", "r" );
X if( !afile )
X error( "Missing active file" );
X
X
X while( fgets( buf, sizeof(buf), afile ) ) {
X spp = strchr( buf, ' ' );
X if( !spp )
X continue; /* report error in active? */
X *spp = 0;
X group = (ngrec *)get_rec( ng_base, buf );
X if( !group )
X continue; /* not a subscribed group */
X if( sscanf( spp+1, "%lu %lu", &highart, &lowart ) == 2 ) {
X group->highest = (int32)highart;
X group->lowest = (int32)lowart;
X group->gflag |= GF_ACTIVE; /* it exists */
X }
X }
X fclose( afile );
X}
X
X/* return the newsgroup number for a selected group
X * If we get a group that we haven't seen, we assign it a negative
X * number and put a temporary negative entry in the newsgroup table
X * so that we can still refer to the group name. Up to 20 unknown
X * groups can come in per article, this should be plenty. The table
X * is reset with every article */
X
Xint extra_groups; /* number of unknown groups, this article */
Xint ex_group_base; /* base for extra groups */
X
Xint
Xng_number( str )
Xchar *str; /* name of newsgroup */
X{
X ngrec *group;
X extern bool wants_dist;
X extern ngrec *extra_g_mem;
X
X group = (ngrec *)get_rec( ng_base, str );
X if( group )
X return group->ngnumber;
X else
X if( extra_groups < NG_EXTRAS ) {
X group = &extra_g_mem[extra_groups];
X ++extra_groups;
X zero( group, sizeof( ngrec ) );
X group->key = str; /* already temp alloced */
X group->ngnumber = -extra_groups;
X ngarray[-extra_groups] = group;
X if( wants_dist )
X set_distribution( group );
X return -extra_groups;
X }
X else
X return -1; /* 20 extra groups! return first */
X
X
X}
X
Xstatic char nfname[MAX_NGLEN];
X
X/* Change a newsgroup name into a subdirectory name in the news spools */
X
Xchar *
Xngdir( groupname )
Xchar *groupname; /* name of newsgroup, with dots */
X{
X char *p;
X
X strcpy( nfname, groupname );
X
X /* map dots to slashes */
X for( p = nfname; *p; p++ )
X if( *p == '.' )
X *p = '/';
X return nfname;
X}
X
X/* Read in list of distributions, and assign a distribution to each
X newsgroup */
X
X
Xhandle_distrs()
X{
X char ng[MAX_NGLEN]; /* newsgroup distribution name */
X FILE *distfile; /* file of distribution codes */
X char distline[MAX_LLEN];/* buffer line for distribution */
X ngrec *group;
X int dlevel; /* distribution level */
X extern char *news_lib_dir;
X extern bool wants_dist; /* are distributions even desired? */
X
X distfile = dfopen( dotdir, DISTLIST, "r" );
X if( !distfile )
X distfile = dfopen( news_lib_dir, DISTLIST, "r" );
X if( !distfile )
X distfile = dfopen( ".", DISTLIST, "r" );
X if( !distfile ) {
X warning( 1, "No distribution file %s\n", DISTLIST );
X wants_dist = FALSE;
X return;
X }
X
X while( fgets( distline, sizeof(distline), distfile ) ) {
X if( distline[0] == '#' )
X continue; /* comment */
X if( sscanf( distline, "%s %d", ng, &dlevel ) != 2 )
X continue;
X group = (ngrec *)add_rec(ng_base, ng, AR_CREATE);
X if( group->ngnumber == 0 )
X group->ngnumber = group_count++;
X group->distribution = dlevel;
X }
X fclose( distfile );
X
X for( group = (ngrec *)first_rec(ng_base); group;
X group =next_rec(ng_base,group) )
X set_distribution( group );
X}
X
X/* Default distribution if we can't figure it out */
X/* It's hard to say what this should be or what meaning it has. The
X user can extern it and set it, I guess */
X
Xint def_distribution = 10;
X
X/* figure out and set the distribution for a given group */
X
Xset_distribution( group )
Xngrec *group;
X{
X ngrec *drec; /* distribution record */
X char gname[MAX_NGLEN]; /* buffer for placing group name */
X char *p;
X
X if( group->distribution == 0 ) {
X strcpy( gname, group->key );
X p = gname + strlen(gname) - 1; /* point at end */
X /* loop through stripping off suffixes, and testing to see
X if there is a distribution number for them */
X while( p > gname ) {
X if( *p == '.' ) {
X *p = 0;
X if( (drec = (ngrec*)get_rec( ng_base, gname)) &&
X drec->distribution > 0) {
X group->distribution =drec->distribution;
X return;
X }
X }
X p--;
X }
X /* set default as we found nothing */
X group->distribution = def_distribution;
X }
X
X
X}
END_OF_FILE
if test 6763 -ne `wc -c <'group.c'`; then
echo shar: \"'group.c'\" unpacked with wrong size!
fi
# end of 'group.c'
fi
if test -f 'userlib.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'userlib.c'\"
else
echo shar: Extracting \"'userlib.c'\" \(8132 characters\)
sed "s/^X//" >'userlib.c' <<'END_OF_FILE'
X
X
X/*
X * Routines and externals for access by the user program
X */
X /*
X * Newsclip(TM) Library Source Code.
X * Copyright 1989 Looking Glass Software Limited. All Rights Reserved.
X * Unless otherwise licenced, the only authorized use of this source
X * code is compilation into a binary of the newsclip library for the
X * use of licenced Newsclip customers. Minor source code modifications
X * are allowed.
X * Use of this code for a short term evaluation of the product, as defined
X * in the associated file, 'Licence', is permitted.
X */
X
X
X#include "nl.h"
X#include <ctype.h>
X
X/* externals */
X
Xchar *article_filename; /* the filename of the article, if
X available */
X
Xint score; /* the score the article got */
X
Xint white_compress = FALSE; /* compress white space */
Xint paragraph_scan = FALSE; /* scan text as paragraphs */
Xint preserve_case = FALSE; /* don't lower case text */
X
Xchar *signature_start = "^-- *$"; /* start of signature */
X
Xchar *include_prefix = "^[ \t]*[:>#%]"; /* included text */
X
X
Xchar *
Xarr_string( thear, type, dex )
Xarray *thear;
Xdtype type; /* array type */
Xint dex; /* dex into array */
X{
X
X switch( type ) {
X case T_NEWSGROUP:
X return ngn(thear->vals[dex].uinteger);
X case T_USERNAME:
X return thear->vals[dex].uusername->emailname;
X case T_STRING:
X return thear->vals[dex].ustring;
X default:
X return "foo";
X }
X}
X
X/*
X * Now we have the various "in" routines which implement the in
X * operator. There is acutally a wide cross product of such routines,
X * based on the fact that you can search for a variety of types in
X * a variety of types. Scalars and arrays can be searched for in arrays
X * and databases, and the various semi-compatible string-like types
X * are mostly dealt with
X */
X
X
Xarr_in_db( arr, db )
Xarray *arr; /* array of string like objects */
Xdbptr db; /* database to look in */
X{
X register int i;
X char *str;
X
X if( !arr )
X return FALSE;
X
X for( i = 0; i < arr->arsize; i++ ) {
X if( str_in_db( arr_string(arr,arr->artype,i), db ) )
X return TRUE;
X }
X return FALSE;
X}
X
Xstr_in_db( str, db )
Xchar *str; /* string to check for */
Xdbptr db; /* database to look in */
X{
X register userdb *rec;
X extern long time_now;
X
X if( rec = (userdb*)get_rec( db, str ) ) {
X rec->access_date = time_now;
X return TRUE;
X }
X else
X return FALSE;
X}
X
Xarr_in_arr( ar1, ar2 )
Xarray *ar1; /* values to look for */
Xarray *ar2; /* array to look in */
X{
X /* we can search for ngs, usernames and strings in strings */
X int i1, i2; /* index vars */
X dtype ty1, ty2;
X
X if( !ar1 || !ar2 )
X return FALSE;
X
X ty1 = ar1->artype;
X ty2 = ar2->artype;
X
X if( ty1 == ty2 ) {
X for( i1 = 0; i1 < ar1->arsize; i1++ )
X for( i2 = 0; i2 < ar2->arsize; i2++ )
X switch( ty1 ) {
X case T_INTEGER:
X case T_NEWSGROUP:
X if( ar1->vals[i1].uinteger ==
X ar2->vals[i2].uinteger)
X return TRUE;
X break;
X case T_DATE:
X if( ar1->vals[i1].udate ==
X ar2->vals[i2].udate)
X return TRUE;
X break;
X case T_STRING:
X if(strcmp(ar1->vals[i1].ustring,
X ar2->vals[i2].ustring)
X == 0 )
X return TRUE;
X break;
X case T_USERNAME:
X if(strcmp(ar1->vals[i1].uusername->emailname,
X ar2->vals[i2].uusername->emailname)
X == 0 )
X return TRUE;
X break;
X }
X }
X else {
X for( i1 = 0; i1 < ar1->arsize; i1++ )
X for( i2 = 0; i2 < ar2->arsize; i2++ )
X if( strcmp(arr_string(ar1,ty1,i1),
X arr_string(ar2,ty2,i2)) == 0 )
X return TRUE;
X }
X return FALSE;
X}
X
Xint_in_arr( val, arr )
Xint val; /* value to search for */
Xarray *arr; /* array to search in */
X{
X int i;
X if( !arr )
X return FALSE;
X for( i = 0; i < arr->arsize; i++ )
X if( val == arr->vals[i].uinteger )
X return TRUE;
X return FALSE;
X}
X
X
Xdate_in_arr( val, arr )
Xdatehold val; /* value to search for */
Xarray *arr; /* array to search in */
X{
X int i;
X if( !arr )
X return FALSE;
X for( i = 0; i < arr->arsize; i++ )
X if( val == arr->vals[i].udate )
X return TRUE;
X return FALSE;
X}
X
Xng_in_arr( val, arr )
Xnewsgroup val; /* value to search for */
Xarray *arr; /* array to search in */
X{
X int i;
X dtype ty;
X if( !arr )
X return FALSE;
X
X ty = arr->artype;
X if( ty == T_NEWSGROUP ) {
X for( i = 0; i < arr->arsize; i++ )
X if( val == arr->vals[i].uinteger )
X return TRUE;
X }
X else {
X char *ngname;
X ngname = ngn(val);
X for( i = 0; i < arr->arsize; i++ )
X if( cleq( ngname, arr_string(arr,ty,i) ) )
X return TRUE;
X }
X return FALSE;
X}
X
Xstr_in_arr( val, arr )
Xchar * val; /* value to search for */
Xarray *arr; /* array to search in */
X{
X int i;
X dtype ty;
X if( !arr )
X return FALSE;
X
X ty = arr->artype;
X for( i = 0; i < arr->arsize; i++ )
X if( strcmp( val, arr_string(arr,ty,i) ) == 0 )
X return TRUE;
X return FALSE;
X}
X
Xname_in_arr( val, arr )
Xusername *val; /* value to search for */
Xarray *arr; /* array to search in */
X{
X int i;
X char *mailn; /* mail name */
X dtype ty;
X if( !arr )
X return FALSE;
X
X ty = arr->artype;
X
X mailn = val->emailname;
X for( i = 0; i < arr->arsize; i++ )
X if( cleq( mailn, arr_string(arr,ty,i)) )
X return TRUE;
X return FALSE;
X}
X
X/* Functions to parse strings with dots */
X
X/* Return the leftmost part of the string, bound by 'num' dots */
X
Xchar *
Xleft( str, num )
Xchar *str; /* string to parse */
Xint num; /* how many sections to return */
X{
X int i;
X char *p; /* scan through for dots */
X char *ret;
X
X p = str;
X
X for( i = 0; i < num; i++ ) {
X p = strchr( p, '.' );
X if( p )
X p++;
X else
X break;
X }
X if( p && p > str) {
X int len;
X len = (p - str) - 1;
X ret = temp_alloc( len + 1 );
X strncpy( ret, str, len );
X ret[len] = 0;
X return ret;
X }
X else
X return num > 0 ? str : "";
X}
X
X/* return the rightmost substring based on dots */
X
Xchar *
Xright( str, num )
Xchar *str;
Xint num;
X{
X int i;
X if( num < 0 )
X return "";
X
X for( i = strlen(str)-1; i >= 0; i-- )
X if( str[i] == '.' )
X if( --num <= 0 )
X return str + i + 1;
X return str;
X}
X
X/* return the domain from a mail address */
X
Xchar *
Xdomain( str )
Xchar *str;
X{
X char *at;
X if( at = strchr( str, '@' ) )
X return at+1;
X else
X return str;
X}
X
X/* distribution level for a newsgroup */
X
Xint
Xdlevel( ng )
Xnewsgroup ng;
X{
X return ngarray[ng]->distribution;
X}
X
X/* check for the presence of a newsgroup. This is generated by the
X * 'is' operator
X */
X
Xgquery( n )
Xregister newsgroup n;
X{
X extern array *newsgroups;
X register int i;
X int ncount;
X
X ncount = newsgroups->arsize;
X for( i = 0; i < ncount; i++ )
X if( newsgroups->vals[i].uinteger == n )
X return TRUE;
X return FALSE;
X}
X
X/* Concatenate two strings together and leave the result in new
X temporary memory */
X
Xchar *
Xconcat( s1, s2 )
Xchar *s1;
Xchar *s2;
X{
X unsigned int len, l1;
X char *ret;
X
X l1 = strlen(s1);
X len = l1 + strlen(s2);
X ret = temp_alloc( len+1 );
X strcpy( ret, s1 );
X strcpy( ret+l1, s2 );
X return ret;
X}
X
X/* Remove any level of "Re: " from the front of a string, most probably
X * a subject line
X */
X
X
Xchar *
Xdrop_re( str )
Xchar *str;
X{
X register char *p;
X
X for( p = str; *p; p++ ) {
X if( *p == ' ' )
X continue;
X else if( lowerlet(p[0]) == 'r' && lowerlet(p[1]) == 'e' &&
X p[2] == ':' )
X p +=2;
X else
X break;
X }
X return p;
X}
X
Xchar *
Xlower( str )
Xchar *str;
X{
X char *ret;
X ret = temp_string( str );
X lowercase( ret );
X return ret;
X}
X
Xint
Xnamed_group( n )
Xnewsgroup n;
X{
X extern int user_gcount;
X return n > 0 && n <= user_gcount;
X}
X
X/* is the group in the .newsrc */
Xint
Xnewsrc_group( n )
Xnewsgroup n;
X{
X return !!(ngarray[n]->gflag & GF_RCGROUP);
X}
X
X/* string compare */
X
Xstr_eq( a, b )
Xchar *a, *b; /* two strings to compare */
X{
X if( a == b )
X return TRUE;
X if( !a || !b )
X return FALSE; /* one is nil string */
X return strcmp( a, b ) == 0;
X}
X
X/* the string, missing N chars from the front */
X
Xchar *
Xclipfront( str, num )
Xchar *str;
Xint num;
X{
X int len;
X len = strlen(str);
X if( num < len )
X return str + num;
X else
X return "";
X}
X
X/* The leftmost N chars of a string */
Xchar *
Xleftmost( str, num )
Xchar *str;
Xint num;
X{
X int len;
X char *ret;
X
X len = strlen(str);
X if( num >= len )
X return str;
X else {
X ret = temp_alloc( num + 1 );
X strncpy( ret, str, num );
X ret[num] = 0;
X return ret;
X }
X}
END_OF_FILE
if test 8132 -ne `wc -c <'userlib.c'`; then
echo shar: \"'userlib.c'\" unpacked with wrong size!
fi
# end of 'userlib.c'
fi
if test -f 'whoami.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'whoami.c'\"
else
echo shar: Extracting \"'whoami.c'\" \(8532 characters\)
sed "s/^X//" >'whoami.c' <<'END_OF_FILE'
X
X/*
X * This file returns site-dependent and user-dependent information
X * It may be necessary to edit and ajust this file on different variants
X * of Unix, although we have tried to deal with many of them. I wish
X * they wouldn't keep adding more.
X */
X /*
X * Newsclip(TM) Library Source Code.
X * Copyright 1989 Looking Glass Software Limited. All Rights Reserved.
X * Unless otherwise licenced, the only authorized use of this source
X * code is compilation into a binary of the newsclip library for the
X * use of licenced Newsclip customers. Minor source code modifications
X * are allowed.
X * Use of this code for a short term evaluation of the product, as defined
X * in the associated file, 'Licence', is permitted.
X */
X
X
X#include "nl.h"
X
X#include <pwd.h>
X
Xchar *homedir; /* home directory */
Xchar *dotdir; /* dot directory */
Xchar *userid; /* the userid of the user */
Xchar *logname; /* login name */
Xchar *fullname; /* full name */
Xchar *sitename; /* short site name of my site */
Xchar *my_domain; /* domain name of my site */
Xchar *my_mail_address; /* my internet mail address */
Xchar *newsrcname = 0; /* name for .newsrc file */
Xchar *lasname = 0; /* last article seen file */
Xchar *temprc = 0; /* tempory newsrc to write out */
X
Xchar *news_lib_dir;
Xchar *news_spool_dir;
X
Xbool normal_newsrc = FALSE; /* are we using the standard newsc file? */
X
X/* There is no reliable method for getting the full mail domain name that
X is used in mail addresses. The only way is for the person who compiled
X the program to have set the proper defines. Some day this routine will
X do something. We *can* get the site name, but that's not all that
X useful to us for checking mail addresses, and it's a messy, multi-ifdef
X procedure that we don't need to have around unless it's necessary. */
X
Xchar *
Xget_domain(site)
Xchar *site;
X{
X#ifdef MAILDOMAIN
X return MAILDOMAIN;
X#else
X char *ret;
X ret = perm_alloc( strlen(site) + 5 + 1 );
X /* default domain of uucp is quite probably wrong */
X sprintf( ret, "%s.%s", site, DEFDOMAIN );
X return ret;
X#endif
X}
X
X#ifdef HAS_UNAME
X#include <sys/utsname.h>
X#endif
X
Xchar *
Xget_sitename()
X{
X char snbuf[50];
X FILE *sysid;
X#ifdef GETHOSTNAME
X gethostname(snbuf,sizeof(snbuf));
X return allocstring(snbuf);
X#else
X if( sysid = fopen( "/etc/systemid", "r" ) ) {
X int len;
X if( fgets( snbuf, sizeof(snbuf), sysid ) ) {
X fclose( sysid );
X len = strlen( snbuf );
X if( len && snbuf[len-1] == '\n' )
X snbuf[len-1] = 0;
X return allocstring( snbuf );
X }
X fclose( sysid );
X }
X# ifdef HAS_UNAME
X {
X struct utsname nam;
X uname( &nam );
X return allocstring( nam.nodename );
X }
X# else /*HAS_UNAME*/
X
X# ifndef sysname
X# define sysname "unknown"
X warning( 2, "System name is unknown.\n" );
X# endif
X return sysname; /* often defined in whoami.h */
X
X# endif /*HAS_UNAME*/
X
X#endif /*GETHOSTNAME*/
X
X}
X
X/* concatenate three strings together in a newly allocated buffer */
X/* used mostly to add a directory name, slash and filename together */
X
Xchar *
Xcatnames( s1, s2, s3 )
Xchar *s1, *s2, *s3;
X{
X unsigned int len, l1, l2;
X char *ret;
X
X l1 = strlen(s1);
X l2 = strlen(s2);
X len = l1 + l2 + strlen(s3);
X ret = perm_alloc( len+1 );
X strcpy( ret, s1 );
X strcpy( ret+l1, s2 );
X strcpy( ret+l1+l2, s3 );
X return ret;
X}
X
Xinit_whoami()
X{
X int uid;
X struct passwd *pwent, *getpwuid();
X extern char *getlogin();
X extern char *getenv AC((char *));
X char buf[MAX_LLEN];
X
X
X if( !( homedir = getenv( "HOME" ) ) )
X homedir = getenv( "LOGDIR" );
X
X fullname = getenv( "NAME" );
X
X uid = getuid();
X
X if( pwent = getpwuid( uid ) ) {
X userid = allocstring( pwent->pw_name );
X if( !fullname ) {
X char *p;
X /* theory is the comma should only be a delimiter
X on certain systems */
X p = strchr( pwent->pw_gecos, ',' );
X if( p )
X *p = 0;
X fullname = allocstring( pwent->pw_gecos );
X /* theory is that '&' should map to the userid but
X I can't imagine why in hell that should be */
X }
X if( !homedir )
X homedir = allocstring( pwent->pw_dir );
X }
X else /* give up and use a dummy name */
X userid = "fbaggins";
X
X if( !( logname = getenv("USER") ) )
X if( !( logname = getenv( "LOGNAME" ) ) )
X if( logname = getlogin() )
X logname = allocstring( logname );
X else
X logname = userid;
X
X /* Now get the site name */
X sitename = get_sitename();
X my_domain = get_domain( sitename );
X sprintf( buf, "%s@%s", userid, my_domain );
X my_mail_address = allocstring( buf );
X
X /* if we still don't have a full name, use the mail address */
X if( !fullname )
X fullname = my_mail_address;
X
X if( !dotdir )
X if( !( dotdir = getenv( "DOTDIR" ) ) )
X dotdir = homedir;
X if( !newsrcname ) {
X if( !( newsrcname = getenv( "NEWSRC" ) ) ) {
X newsrcname = catnames( dotdir, "/", ".newsrc" );
X normal_newsrc = TRUE;
X }
X }
X if( !lasname )
X lasname = catnames( newsrcname, "las", "" );
X temprc = catnames( newsrcname, "new", "" );
X
X /* set up news library and spool directories */
X if( !news_lib_dir )
X news_lib_dir = NEWSLIB;
X if( !news_spool_dir )
X news_spool_dir = NEWSSPOOL;
X}
X
X/* If your system has no getlogin, define this null one. It's not important,
X unless you can plug in some other username finding routine. This is
X the routine of last resort. If it returns null, as this dummy does,
X you get a dummy name. That's ok. Ther user simply can't use the
X "my_mail_address" variable in this case -- they have to enter it by
X hand. */
X
X#ifndef GETLOGIN
X
Xchar *
Xgetlogin()
X{
X return (char *)0;
X}
X#endif
X
Xdatehold time_now; /* the time we ran */
Xint zone_offset; /* offset from GMT in minutes */
X#include <time.h>
X
X/* Find the time, and the timezone offset from GMT in minutes. The way
X to find this out varies from OS variant to OS variant, but I believe
X I have a reasonably portable way below. */
X
Xinit_time()
X{
X struct tm *tbuf;
X long day1, time();
X
X time_now = time((long*)0);
X /* the most portable way I currently know to get the time zone
X adjustment is to get the time of day for Midnight on the second
X day of the epoch from the localtime function. Some systems
X require an init routine to be called to set up time zone stuff
X properly, and that can be inserted here. It's worth nothing
X that getting this value right isn't super crucial. It has
X only a minor effect on the parsing of dates, and usually dates
X aren't even bothered with by newsclip programs */
X
X day1 = 60*60*24; /* one day of seconds */
X
X tbuf = localtime( &day1 );
X /* In this case, it's minutes WEST of GMT, which is positive for
X us western guys */
X if( tbuf->tm_hour >= 12 )
X zone_offset = 60 * (24-tbuf->tm_hour) - tbuf->tm_min;
X else
X zone_offset = -60 * tbuf->tm_hour - tbuf->tm_min;
X}
X
X/* Some routines missing from BSD Unix */
X
X#ifdef NEED_SLIB
X
X
X/* strpbrk, like strchr, but searches for any one of a set of chars */
X
Xchar *
Xstrpbrk( str, lchars )
Xchar *str; /* string to search in */
Xchar *lchars;
X{
X register char *p;
X
X for( p = str; *p; p++ )
X if( strchr( lchars, *p ) )
X return p;
X return (char *)0;
X}
X
X/* strtok - string parsing routine */
X
Xstatic char *tokstring;
X
Xchar *
Xstrtok( string, delims )
Xchar *string; /* string to parse, or null to continue old string */
Xchar *delims; /* delimiters to parse on */
X{
X register char *p, *del; /* scanning pointer */
X char *start;
X
X p = string ? string : tokstring;
X
X /* skip over initial delimiters */
X while( *p ) {
X for( del = delims; *del; del++ )
X if( *del == *p )
X goto nextc;
X break; /* not a delim */
X nextc: p++;
X }
X
X if( !*p )
X return NULL;
X
X start = p;
X
X /* go to next delimiter */
X while( *p ) {
X for( del = delims; *del; del++ )
X if( *del == *p )
X goto tok_done;
X p++;
X }
X tok_done:
X /* store 0 on top of delimiter */
X if( *p )
X *p++ = 0;
X /* save in static for next call */
X tokstring = p;
X
X return start;
X}
X
X/*
X * The following is provided for those people who do not have strcspn() in
X * their C libraries. They should get off their butts and do something
X * about it; at least one public-domain implementation of those (highly
X * useful) string routines has been published on Usenet.
X */
X/*
X * strcspn - find length of initial segment of s1 consisting entirely
X * of characters not from s2 (Henry Spencer)
X */
X
Xstatic int
Xstrcspn(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X register char *scan1;
X register char *scan2;
X register int count;
X
X count = 0;
X for (scan1 = s1; *scan1 != '\0'; scan1++) {
X for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
X if (*scan1 == *scan2++)
X return(count);
X count++;
X }
X return(count);
X}
X#endif /*NEED_SLIB*/
END_OF_FILE
if test 8532 -ne `wc -c <'whoami.c'`; then
echo shar: \"'whoami.c'\" unpacked with wrong size!
fi
# end of 'whoami.c'
fi
echo shar: End of archive 4 \(of 15\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 15 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
More information about the Comp.sources.misc
mailing list