?? art.c
字號:
/* $Revision: 1.52 $**** Article-processing.*/#include "innd.h"#include "dbz.h"#include <sys/uio.h>typedef struct iovec IOVEC;/*** A way to index into the header table.*/#define HDR(_x) (ARTheaders[(_x)].Value)#if defined(S_IXUSR)#define EXECUTE_BITS (S_IXUSR | S_IXGRP | S_IXOTH)#else#define EXECUTE_BITS 0111#endif /* defined(S_IXUSR) *//*** Mark that the site gets this article.*/#define SITEmark(sp_, ngp_) \ do { \ SITE *funnel; \ \ sp_->Sendit = TRUE; \ if (sp_->ng == NULL) \ sp_->ng = ngp_; \ if (sp_->Funnel != NOSITE) { \ funnel = &Sites[sp_->Funnel]; \ if (funnel->ng == NULL) \ funnel->ng = ngp_; \ } \ } while (JUSTONCE)/*** Header types.*/typedef enum _ARTHEADERTYPE { HTreq, /* Drop article if this is missing */ HTobs, /* Delete this header if found */ HTstd /* Standard optional header */} ARTHEADERTYPE;/*** Entry in the header table.*/typedef struct _ARTHEADER { STRING Name; ARTHEADERTYPE Type; int Size; /* Length of Name */ char *Value; int Length; /* Length of Value */ int Found; BOOL Allocated;} ARTHEADER;/*** For speed we build a binary tree of the headers, sorted by their** name. We also store the header's Name fields in the tree to avoid** doing an extra indirection.*/typedef struct _TREE { STRING Name; ARTHEADER *Header; struct _TREE *Before; struct _TREE *After;} TREE;STATIC TREE *ARTheadertree;/*** For doing the overview database, we keep a list of the headers and** a flag saying if they're written in brief or full format.*/typedef struct _ARTOVERFIELD { ARTHEADER *Header; BOOL NeedHeader;} ARTOVERFIELD;STATIC ARTOVERFIELD *ARTfields;/*** General newsgroup we care about, and what we put in the Path line.*/STATIC char ARTctl[] = "control";STATIC char ARTjnk[] = "junk";STATIC char *ARTpathme;/*** Flag array, indexed by character. Character classes for Message-ID's.*/STATIC char ARTcclass[256];#define CC_MSGID_ATOM 01#define CC_MSGID_NORM 02#define CC_HOSTNAME 04#define ARTnormchar(c) ((ARTcclass[(c)] & CC_MSGID_NORM) != 0)#define ARTatomchar(c) ((ARTcclass[(c)] & CC_MSGID_ATOM) != 0)#define ARThostchar(c) ((ARTcclass[(c)] & CC_HOSTNAME) != 0)/*** The header table. Not necessarily sorted, but the first character** must be uppercase.*/STATIC ARTHEADER ARTheaders[] = { /* Name Type ... */ { "Approved", HTstd },#define _approved 0 { "Control", HTstd },#define _control 1 { "Date", HTreq },#define _date 2 { "Distribution", HTstd },#define _distribution 3 { "Expires", HTstd },#define _expires 4 { "From", HTreq },#define _from 5 { "Lines", HTstd },#define _lines 6 { "Message-ID", HTreq },#define _message_id 7 { "Newsgroups", HTreq },#define _newsgroups 8 { "Path", HTreq },#define _path 9 { "Reply-To", HTstd },#define _reply_to 10 { "Sender", HTstd },#define _sender 11 { "Subject", HTreq },#define _subject 12 { "Supersedes", HTstd },#define _supersedes 13 { "Bytes", HTstd },#define _bytes 14 { "Also-Control", HTstd },#define _alsocontrol 15 { "References", HTstd },#define _references 16 { "Xref", HTobs },#define _xref 17 { "Date-Received", HTobs }, { "Posted", HTobs }, { "Posting-Version", HTobs }, { "Received", HTobs }, { "Relay-Version", HTobs },};/****/BOOLARTreadschema(){ static char SCHEMA[] = _PATH_SCHEMA; register FILE *F; register int i; register char *p; register ARTOVERFIELD *fp; register ARTHEADER *hp; BOOL ok; char buff[SMBUF]; if (ARTfields != NULL) { DISPOSE(ARTfields); ARTfields = NULL; } /* Open file, count lines. */ if ((F = fopen(SCHEMA, "r")) == NULL) return FALSE; for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++) continue; (void)fseek(F, (OFFSET_T)0, SEEK_SET); ARTfields = NEW(ARTOVERFIELD, i + 1); /* Parse each field. */ for (ok = TRUE, fp = ARTfields; fgets(buff, sizeof buff, F) != NULL; ) { /* Ignore blank and comment lines. */ if ((p = strchr(buff, '\n')) != NULL) *p = '\0'; if ((p = strchr(buff, COMMENT_CHAR)) != NULL) *p = '\0'; if (buff[0] == '\0') continue; if ((p = strchr(buff, ':')) != NULL) { *p++ = '\0'; fp->NeedHeader = EQ(p, "full"); } else fp->NeedHeader = FALSE; for (hp = ARTheaders; hp < ENDOF(ARTheaders); hp++) if (EQ(buff, hp->Name)) { fp->Header = hp; break; } if (hp == ENDOF(ARTheaders)) { syslog(L_ERROR, "%s bad_schema unknown header \"%s\"", buff); ok = FALSE; continue; } fp++; } fp->Header = NULL; (void)fclose(F); return ok;}/*** Build a balanced tree for the headers in subscript range [lo..hi).** This only gets called once, and the tree only has about 20 entries,** so we don't bother to unroll the recursion.*/static TREE *ARTbuildtree(Table, lo, hi) ARTHEADER **Table; int lo; int hi;{ int mid; TREE *tp; mid = lo + (hi - lo) / 2; tp = NEW(TREE, 1); tp->Header = Table[mid]; tp->Name = tp->Header->Name; if (mid == lo) tp->Before = NULL; else tp->Before = ARTbuildtree(Table, lo, mid); if (mid == hi - 1) tp->After = NULL; else tp->After = ARTbuildtree(Table, mid + 1, hi); return tp;}/*** Sorting predicate for qsort call in ARTsetup.*/STATIC intARTcompare(p1, p2) POINTER p1; POINTER p2;{ ARTHEADER **h1; ARTHEADER **h2; h1 = CAST(ARTHEADER**, p1); h2 = CAST(ARTHEADER**, p2); return strcasecmp(h1[0]->Name, h2[0]->Name);}/*** Setup the article processing.*/voidARTsetup(){ register STRING p; register ARTHEADER *hp; ARTHEADER **table; register int i; /* Set up the character class tables. These are written a * little strangely to work around a GCC2.0 bug. */ (void)memset((POINTER)ARTcclass, 0, sizeof ARTcclass); p = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; while ((i = *p++) != 0) { ARTcclass[i] = CC_HOSTNAME | CC_MSGID_ATOM | CC_MSGID_NORM; } p = "!#$%&'*+-/=?^_`{|}~"; while ((i = *p++) != 0) { ARTcclass[i] = CC_MSGID_ATOM | CC_MSGID_NORM; } p = "\"(),.:;<@[\\]"; while ((i = *p++) != 0) { ARTcclass[i] = CC_MSGID_NORM; } /* The RFC's don't require it, but we add underscore to the list of valid * hostname characters. */ ARTcclass['.'] |= CC_HOSTNAME; ARTcclass['-'] |= CC_HOSTNAME; ARTcclass['_'] |= CC_HOSTNAME; /* Allocate space in the header table. */ for (hp = ARTheaders; hp < ENDOF(ARTheaders); hp++) { hp->Size = strlen(hp->Name); hp->Allocated = hp->Value == NULL && hp->Type != HTobs && hp != &ARTheaders[_bytes]; if (hp->Allocated) hp->Value = NEW(char, MAXHEADERSIZE + 1); } /* Build the header tree. */ table = NEW(ARTHEADER*, SIZEOF(ARTheaders)); for (i = 0; i < SIZEOF(ARTheaders); i++) table[i] = &ARTheaders[i]; qsort((POINTER)table, SIZEOF(ARTheaders), sizeof *table, ARTcompare); ARTheadertree = ARTbuildtree(table, 0, SIZEOF(ARTheaders)); DISPOSE(table); /* Get our Path name, kill trailing !. */ ARTpathme = COPY(Path.Data); ARTpathme[Path.Used - 1] = '\0'; /* Set up database; ignore errors. */ (void)ARTreadschema();}STATIC voidARTfreetree(tp) TREE *tp;{ TREE *next; for ( ; tp != NULL; tp = next) { if (tp->Before) ARTfreetree(tp->Before); next = tp->After; DISPOSE(tp); }}voidARTclose(){ register ARTHEADER *hp; /* Free space in the header table. */ for (hp = ARTheaders; hp < ENDOF(ARTheaders); hp++) if (hp->Allocated) DISPOSE(hp->Value); if (ARTfields != NULL) { DISPOSE(ARTfields); ARTfields = NULL; } ARTfreetree(ARTheadertree);}/*** Read in a file, return a pointer to static space that is reused.*/STATIC char *ARTreadfile(name) char *name;{ static BUFFER File; struct stat Sb; int fd; int oerrno; /* Open the file, get its size. */ if ((fd = open(name, O_RDONLY)) < 0) return NULL; if (fstat(fd, &Sb) < 0) { oerrno = errno; (void)close(fd); errno = oerrno; return NULL; } /* Make sure we have enough space. */ if (File.Size == 0) { File.Size = Sb.st_size; File.Data = NEW(char, File.Size + 1); } else if (File.Size <= Sb.st_size) { File.Size = Sb.st_size + 16; RENEW(File.Data, char, File.Size + 1); } /* Read in the file. */ if (xread(fd, File.Data, Sb.st_size) < 0) { oerrno = errno; (void)close(fd); errno = oerrno; return NULL; } /* Clean up and return the data. */ File.Data[Sb.st_size] = '\0'; (void)close(fd); return File.Data;}/*** Open the article file and return a copy of it. The files parameter is** actually a whitespace-separated list of names.*/char *ARTreadarticle(files) register char *files;{ register char *p; register BOOL more; char *art; if (files == NULL) return NULL; /* Loop over all filenames until we can open one. */ for ( ; *files; files = p + 1) { /* Snip off next name, turn dots to slashes. */ for (p = files; ISWHITE(*p); p++) continue; for (files = p; *p && *p != ' '; p++) if (*p == '.') *p = '/'; more = *p == ' '; if (more) *p = '\0'; art = ARTreadfile(files); if (more) *p = ' '; if (art != NULL) return art; if (!more) break; } return NULL;}/*** Open the article file and return a copy of the headers.*/char *ARTreadheader(files) char *files;{ register char *p; register char *head; if ((head = ARTreadarticle(files)) == NULL) return NULL; /* Find \n\n which means the end of the header. */ for (p = head; (p = strchr(p, '\n')) != NULL; p++) if (p[1] == '\n') { p[1] = '\0'; return head; } syslog(L_NOTICE, "%s bad_article %s is all headers", LogName, files); DISPOSE(head); return NULL;}/*** Parse a Path line, splitting it up into NULL-terminated array of strings.** The argument is modified!*/STATIC char **ARTparsepath(p, countp) register char *p; int *countp;{ static char *NULLPATH[1] = { NULL }; static int oldlength; static char **hosts; register int i; register char **hp; /* We can be called with a non-existant or empty path. */ if (p == NULL || *p == '\0') { *countp = 0; return NULLPATH; } /* Get an array of character pointers. */ i = strlen(p); if (hosts == NULL) { oldlength = i; hosts = NEW(char*, oldlength + 1); } else if (oldlength <= i) { oldlength = i; RENEW(hosts, char*, oldlength + 1); } /* Loop over text. */ for (hp = hosts; *p; *p++ = '\0') { /* Skip leading separators. */ for (; *p && !ARThostchar(*p); p++) continue; if (*p == '\0') break; /* Mark the start of the host, move to the end of it. */ for (*hp++ = p; *p && ARThostchar(*p); p++) continue; if (*p == '\0') break; } *hp = NULL; *countp = hp - hosts; return hosts;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -