brad@looking.ON.CA (Brad Templeton) (12/20/89)
Posting-number: Volume 9, Issue 73 Submitted-by: brad@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@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