⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 expire.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  $Revision: 1.17 $****  Expire news articles.*/#include "configdata.h"#include <stdio.h>#include <ctype.h>#include <sys/types.h>#include <sys/stat.h>#if	defined(DO_NEED_TIME)#include <time.h>#endif	/* defined(DO_NEED_TIME) */#include <sys/time.h>#include <errno.h>#include "paths.h"#include "libinn.h"#include "clibrary.h"#include "inndcomm.h"#include "dbz.h"#include "qio.h"#include "macros.h"/***  Stuff that more or less duplicates stuff in innd.*/#define NGH_HASH(Name, p, j)    \	for (p = Name, j = 0; *p; ) j = (j << 5) + j + *p++#define NGH_SIZE	128#define NGH_BUCKET(j)	&NGHtable[j & (NGH_SIZE - 1)]typedef struct _BUFFER {    int		Size;    int		Used;    int		Left;    char	*Data;} BUFFER;typedef struct _NEWSGROUP {    char		*Name;    char		*Rest;    long		Last;	/* These fields are new. */    time_t		Keep;    time_t		Default;    time_t		Purge;} NEWSGROUP;typedef struct _NGHASH {    int		Size;    int		Used;    NEWSGROUP	**Groups;} NGHASH;/***  Expire-specific stuff.*/#define MAGIC_TIME	49710.typedef struct _BADGROUP {    struct _BADGROUP	*Next;    char		*Name;    BOOL		HasDirectory;} BADGROUP;STATIC BADGROUP		*EXPbadgroups;STATIC BOOL		EXPlinks;STATIC BOOL		EXPquiet;STATIC BOOL		EXPsizing;STATIC BOOL		EXPtracing;STATIC BOOL		EXPusepost;STATIC char		EXPnewslib[] = _PATH_NEWSLIB;STATIC char		ACTIVE[] = _PATH_ACTIVE;STATIC char		SPOOL[] = _PATH_SPOOL;STATIC int		nGroups;STATIC FILE		*EXPunlinkfile;STATIC long		EXPsaved;STATIC NEWSGROUP	*Groups;STATIC NEWSGROUP	EXPdefault;STATIC NGHASH		NGHtable[NGH_SIZE];STATIC STRING		EXPreason;STATIC time_t		EXPremember;STATIC time_t		Now;/* Statistics; for -v flag. */STATIC char		*EXPgraph;STATIC int		EXPverbose;STATIC long		EXPprocessed;STATIC long		EXPunlinked;STATIC long		EXPhistdrop;STATIC long		EXPhistremember;STATIC long		EXPallgone;STATIC long		EXPstillhere;STATIC int		EXPsplit();extern double		atof();/***  Hash a newsgroup and see if we get it.*/STATIC NEWSGROUP *NGfind(Name)    char		*Name;{    register char	*p;    register int	i;    unsigned int	j;    register NEWSGROUP	**ngp;    char		c;    NGHASH		*htp;    /* SUPPRESS 6 *//* Over/underflow from plus expression */    NGH_HASH(Name, p, j);    htp = NGH_BUCKET(j);    for (c = *Name, ngp = htp->Groups, i = htp->Used; --i >= 0; ngp++)	if (c == ngp[0]->Name[0] && EQ(Name, ngp[0]->Name))	    return ngp[0];    return NULL;}/***  Sorting predicate to put newsgroups in rough order of their activity.*/STATIC intNGcompare(p1, p2)    POINTER	p1;    POINTER	p2;{    NEWSGROUP	**ng1;    NEWSGROUP	**ng2;    ng1 = CAST(NEWSGROUP**, p1);    ng2 = CAST(NEWSGROUP**, p2);    return ng1[0]->Last - ng2[0]->Last;}/***  Build the newsgroup structures from the active file.*/STATIC voidBuildGroups(active)    char		*active;{    register NGHASH	*htp;    register NEWSGROUP	*ngp;    register char	*p;    register char	*q;    register int	i;    register unsigned	j;    register int	lines;    int			NGHbuckets;    char		*fields[5];    /* Count the number of groups. */    for (p = active, i = 0; (p = strchr(p, '\n')) != NULL; p++, i++)	continue;    nGroups = i;    Groups = NEW(NEWSGROUP, i);    /* Set up the default hash buckets. */    NGHbuckets = i / NGH_SIZE;    if (NGHbuckets == 0)	NGHbuckets = 1;    for (i = NGH_SIZE, htp = NGHtable; --i >= 0; htp++) {	htp->Size = NGHbuckets;	htp->Groups = NEW(NEWSGROUP*, htp->Size);	htp->Used = 0;    }    /* Fill in the array. */    lines = 0;    for (p = active, ngp = Groups, i = nGroups; --i >= 0; ngp++, p = q + 1) {	lines++;	if ((q = strchr(p, '\n')) == NULL) {	    (void)fprintf(stderr, "%s: line %d missing newline\n",		    ACTIVE, lines);	    exit(1);	}	*q = '\0';	if (EXPsplit(p, ' ', fields, SIZEOF(fields)) != 4) {	    (void)fprintf(stderr, "%s: line %d wrong number of fields\n",		    ACTIVE, lines);	    exit(1);	}	ngp->Name = fields[0];	ngp->Last = atol(fields[1]);	ngp->Rest = fields[3];	/* Find the right bucket for the group, make sure there is room. */	/* SUPPRESS 6 *//* Over/underflow from plus expression */	NGH_HASH(ngp->Name, p, j);	htp = NGH_BUCKET(j);	if (htp->Used >= htp->Size) {	    htp->Size += NGHbuckets;	    RENEW(htp->Groups, NEWSGROUP*, htp->Size);	}	htp->Groups[htp->Used++] = ngp;    }    /* Sort each hash bucket. */    for (i = NGH_SIZE, htp = NGHtable; --i >= 0; htp++)    if (htp->Used > 1)	qsort((POINTER)htp->Groups, (SIZE_T)htp->Used, sizeof htp->Groups[0],		NGcompare);}/***  Open a file or give up.*/STATIC FILE *EXPfopen(Remove, Name, Mode)    BOOL	Remove;    STRING	Name;    char	*Mode;{    FILE	*F;    if (Remove && unlink(Name) < 0 && errno != ENOENT)	(void)fprintf(stderr, "Warning, can't remove %s, %s\n",		Name, strerror(errno));    if ((F = fopen(Name, Mode)) == NULL) {	(void)fprintf(stderr, "Can't open %s in %s mode, %s\n",		Name, Mode, strerror(errno));	exit(1);    }    return F;}/***  Split a line at a specified field separator into a vector and return**  the number of fields found, or -1 on error.*/STATIC intEXPsplit(p, sep, argv, count)    register char	*p;    register char	sep;    register char	**argv;    register int	count;{    register int	i;    for (i = 1, *argv++ = p; *p; )	if (*p++ == sep) {	    if (++i == count)		/* Overflow. */		return -1;	    p[-1] = '\0';	    for (*argv++ = p; *p == sep; p++)		continue;	}    return i;}/***  Parse a number field converting it into a "when did this start?".**  This makes the "keep it" tests fast, but inverts the logic of**  just about everything you expect.  Print a message and return FALSE**  on error.*/STATIC BOOLEXPgetnum(line, word, v, name)    int			line;    char		*word;    time_t		*v;    char		*name;{    register char	*p;    register BOOL	SawDot;    double		d;    if (caseEQ(word, "never")) {	*v = (time_t)0;	return TRUE;    }    /* Check the number.  We don't have strtod yet. */    for (p = word; ISWHITE(*p); p++)	continue;    if (*p == '+' || *p == '-')	p++;    for (SawDot = FALSE; *p; p++)	if (*p == '.') {	    if (SawDot)		break;	    SawDot = TRUE;	}	else if (!CTYPE(isdigit, *p))	    break;    if (*p) {	(void)fprintf(stderr, "Line %d, bad `%c' character in %s field\n",		line, *p, name);	return FALSE;    }    d = atof(word);    if (d > MAGIC_TIME)	*v = (time_t)0;    else	*v = Now - (time_t)(d * 86400.);    return TRUE;}/***  Set the expiration fields for all groups that match this pattern.*/STATIC voidEXPmatch(p, v, mod)    register char	*p;    register NEWSGROUP	*v;    register char	mod;{    register NEWSGROUP	*ngp;    register int	i;    register BOOL	negate;    negate = *p == '!';    if (negate)	p++;    for (ngp = Groups, i = nGroups; --i >= 0; ngp++)	if (negate ? !wildmat(ngp->Name, p) : wildmat(ngp->Name, p))	    if (mod == 'a'	     || (mod == 'm' && ngp->Rest[0] == NF_FLAG_MODERATED)	     || (mod == 'u' && ngp->Rest[0] != NF_FLAG_MODERATED)) {		ngp->Keep      = v->Keep;		ngp->Default   = v->Default;		ngp->Purge     = v->Purge;		if (EXPverbose > 4) {		    (void)printf("%s", ngp->Name);		    (void)printf(" %13.13s", ctime(&v->Keep) + 3);		    (void)printf(" %13.13s", ctime(&v->Default) + 3);		    (void)printf(" %13.13s", ctime(&v->Purge) + 3);		    (void)printf(" (%s)\n", p);		}	    }}/***  Parse the expiration control file.  Return TRUE if okay.*/STATIC BOOLEXPreadfile(F)    register FILE	*F;{    register char	*p;    register int	i;    register int	j;    register int	k;    register char	mod;    NEWSGROUP		v;    BOOL		SawDefault;    char		buff[BUFSIZ];    char		*fields[6];    char		**patterns;    /* Scan all lines. */    EXPremember = -1;    SawDefault = FALSE;    patterns = NEW(char*, nGroups);    for (i = 1; fgets(buff, sizeof buff, F) != NULL; i++) {	if ((p = strchr(buff, '\n')) == NULL) {	    (void)fprintf(stderr, "Line %d too long\n", i);	    return FALSE;	}	*p = '\0';	if (buff[0] == '\0' || buff[0] == '#')	    continue;	if ((j = EXPsplit(buff, ':', fields, SIZEOF(fields))) == -1) {	    (void)fprintf(stderr, "Line %d too many fields\n", i);	    return FALSE;	}	/* Expired-article remember line? */	if (EQ(fields[0], "/remember/")) {	    if (j != 2) {		(void)fprintf(stderr, "Line %d bad format\n", i);		return FALSE;	    }	    if (EXPremember != -1) {		(void)fprintf(stderr, "Line %d duplicate /remember/\n", i);		return FALSE;	    }	    if (!EXPgetnum(i, fields[1], &EXPremember, "remember"))		return FALSE;	    continue;	}	/* Regular expiration line -- right number of fields? */	if (j != 5) {	    (void)fprintf(stderr, "Line %d bad format\n", i);	    return FALSE;	}	/* Parse the fields. */	if (strchr(fields[1], 'M') != NULL)	    mod = 'm';	else if (strchr(fields[1], 'U') != NULL)	    mod = 'u';	else if (strchr(fields[1], 'A') != NULL)	    mod = 'a';	else {	    (void)fprintf(stderr, "Line %d bad modflag\n", i);	    return FALSE;	}	if (!EXPgetnum(i, fields[2], &v.Keep,    "keep")	 || !EXPgetnum(i, fields[3], &v.Default, "default")	 || !EXPgetnum(i, fields[4], &v.Purge,   "purge"))	    return FALSE;	/* These were turned into offsets, so the test is the opposie	 * of what you think it should be.  If Purge isn't forever,	 * make sure it's greater then the other two fields. */	if (v.Purge) {	    /* Some value not forever; make sure other values are in range. */	    if (v.Keep && v.Keep < v.Purge) {		(void)fprintf(stderr, "Line %d keep>purge\n", i);		return FALSE;	    }	    if (v.Default && v.Default < v.Purge) {		(void)fprintf(stderr, "Line %d default>purge\n", i);		return FALSE;	    }	}	/* Is this the default line? */	if (fields[0][0] == '*' && fields[0][1] == '\0' && mod == 'a') {	    if (SawDefault) {		(void)fprintf(stderr, "Line %d duplicate default\n", i);		break;	    }	    EXPdefault.Keep    = v.Keep;	    EXPdefault.Default = v.Default;	    EXPdefault.Purge   = v.Purge;	    SawDefault = TRUE;	}	/* Assign to all groups that match the pattern and flags. */	if ((j = EXPsplit(fields[0], ',', patterns, nGroups)) == -1) {	    (void)fprintf(stderr, "Line %d too many patterns\n", i);	    return FALSE;	}	for (k = 0; k < j; k++)	    EXPmatch(patterns[k], &v, mod);    }    DISPOSE(patterns);    return TRUE;}/***  Handle a newsgroup that isn't in the active file.*/STATIC NEWSGROUP *EXPnotfound(Entry)    char		*Entry;{    static NEWSGROUP	Removeit;    register BADGROUP	*bg;    register char	*p;    struct stat		Sb;    char		buff[SPOOLNAMEBUFF];    /* See if we already know about this group. */    for (bg = EXPbadgroups; bg; bg = bg->Next)	if (EQ(Entry, bg->Name))	    break;    if (bg == NULL) {	bg = NEW(BADGROUP, 1);	bg->Name = COPY(Entry);	(void)strcpy(buff, bg->Name);	for (p = buff; *p; p++)	    if (*p == '.')		*p = '/';	bg->HasDirectory = stat(buff, &Sb) >= 0 && S_ISDIR(Sb.st_mode);	bg->Next = EXPbadgroups;	EXPbadgroups = bg;	if (!EXPquiet) {	    (void)fflush(stdout);	    (void)fprintf(stderr, "Group not matched (removed?) %s -- %s\n",		Entry,		bg->HasDirectory ? "Using default expiration"				 : "Purging all articles");	}    }    /* Directory still there; use default expiration. */    if (bg->HasDirectory)	return &EXPdefault;    /* No directory -- remove it all now. */    if (Removeit.Keep == 0) {	Removeit.Keep = Now;	Removeit.Default = Now;	Removeit.Purge = Now;    }    return &Removeit;}/***  Should we keep the specified article?*/STATIC BOOLEXPkeepit(Entry, when, Expires)    char		*Entry;    time_t		when;    time_t		Expires;{    register char	*p;    register NEWSGROUP	*ngp;    if ((p = strchr(Entry, '/')) == NULL) {	(void)fflush(stdout);	(void)fprintf(stderr, "Bad entry, \"%s\"\n", Entry);	return TRUE;    }    *p = '\0';    if ((ngp = NGfind(Entry)) == NULL)	ngp = EXPnotfound(Entry);    *p = '/';    if (EXPverbose > 2) {	if (EXPverbose > 3)	    (void)printf("%s age = %0.2f\n",		    Entry, (Now - when) / 86400.);	if (Expires == 0) {	    if (when < ngp->Default)		(void)printf("%s too old (no exp)\n", Entry);	}	else {	    if (when < ngp->Purge)		(void)printf("%s later than purge\n", Entry);	    if (when > ngp->Keep)		(void)printf("%s earlier than min\n", Entry);	    if (Now > Expires)		(void)printf("%s later than header\n", Entry);	}    }    /* If no expiration, make sure it wasn't posted before the default. */    if (Expires == 0)	return when >= ngp->Default;    /* Make sure it's not posted before the purge cut-off and     * that it's not due to expire. */    return when >= ngp->Purge && (Expires >= Now || when >= ngp->Keep);}/***  An article can be removed.  Either print a note, or actually remove it.**  Also fill in the article size.*/STATIC voidEXPremove(p, size)    char		*p;    long		*size;{    register char	*q;    struct stat		Sb;    /* Turn into a filename and get the size if we need it. */    for (q = p; *q; q++)	if (*q == '.')	    *q = '/';    if (EXPsizing && *size < 0 && stat(p, &Sb) >= 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -