?? art.c
字號:
/*** Write an article using writev. The article is split into pieces,** shown below separated by pipe signs. The items in square brackets are** "inserted" by this routine.** |headers...** Path: |[Path.Data]|rest of path...** headers...** |[Lines header, if needed]|** |[Xref header]|**** Article body.** Also, the Data->Size field is filled in.*/STATIC intARTwrite(name, Article, Data, CrossPosted) char *name; BUFFER *Article; ARTDATA *Data; BOOL CrossPosted;{ static char WHEN[] = "article"; static char NL[] = "\n"; static BUFFER Headers; register int fd; register IOVEC *vp; register long size; register char *p; IOVEC iov[7]; IOVEC *end; char bytesbuff[SMBUF]; int i; if ((p = HeaderFind(Article->Data, "Path", 4)) == NULL || p == Article->Data) { /* This should not happen. */ syslog(L_ERROR, "%s internal %s no Path header", Data->MessageID, LogName); return -1; } /* Open the file. */ if ((fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, ARTFILE_MODE)) < 0) { if (errno != ENOENT) IOError(WHEN); return -1; } /* Set up the scatter/gather vectors. */ vp = iov; size = 0; vp->iov_base = Article->Data; vp->iov_len = p - Article->Data; size += (vp++)->iov_len; vp->iov_base = Path.Data; vp->iov_len = Path.Used; size += (vp++)->iov_len; vp->iov_base = p; vp->iov_len = Data->Body - p; size += (vp++)->iov_len; if (ARTheaders[_lines].Found == 0) { (void)sprintf(Data->Lines, "Lines: %d\n", Data->LinesValue); i = strlen(Data->Lines); vp->iov_base = Data->Lines; (vp++)->iov_len = i; size += i; /* Install in header table; STRLEN("Lines: ") == 7. */ (void)strcpy(ARTheaders[_lines].Value, Data->Lines + 7); ARTheaders[_lines].Length = i - 7; ARTheaders[_lines].Found = 1; } if (CrossPosted) { /* Install in header table; STRLEN("Xref: ") == 6. */ HDR(_xref) = Xref.Data + 6; ARTheaders[_xref].Length = Xref.Used - 6; ARTheaders[_xref].Found = 1; vp->iov_base = Xref.Data; vp->iov_len = Xref.Used; size += (vp++)->iov_len; } end = vp; vp->iov_base = NL; vp->iov_len = 1; size += (vp++)->iov_len; vp->iov_base = Data->Body; vp->iov_len = &Article->Data[Article->Used] - Data->Body; size += (vp++)->iov_len; Data->SizeValue = size; (void)sprintf(Data->Size, "%ld", Data->SizeValue); Data->SizeLength = strlen(Data->Size); HDR(_bytes) = Data->Size; ARTheaders[_bytes].Length = Data->SizeLength; ARTheaders[_bytes].Found = 1; /* Now do the write. */ if (xwritev(fd, iov, vp - iov) < 0) { IOError(WHEN); syslog(L_ERROR, "%s cant write %s %m", LogName, name); (void)close(fd); if (unlink(name) < 0 && errno != ENOENT) { IOError(WHEN); syslog(L_ERROR, "%s cant unlink %s %m", LogName, name); } return -1; } if (close(fd) < 0) { IOError(WHEN); syslog(L_ERROR, "%s cant close %s %m", LogName, name); if (unlink(name) < 0 && errno != ENOENT) { IOError(WHEN); syslog(L_ERROR, "%s cant unlink %s %m", LogName, name); } return -1; } /* Set the owner. */ if (AmRoot) xchown(name); /* Need the header data? */ if (!NeedHeaders) return 0; /* Figure out how much space we'll need and get it. */ (void)sprintf(bytesbuff, "Bytes: %ld\n", size); for (i = strlen(bytesbuff), vp = iov; vp < end; vp++) i += vp->iov_len; if (!CrossPosted) i += Xref.Used; if (Headers.Data == NULL) { Headers.Size = i; Headers.Data = NEW(char, Headers.Size + 1); } else if (Headers.Size <= i) { Headers.Size = i; RENEW(Headers.Data, char, Headers.Size + 1); } /* Add the data. */ BUFFset(&Headers, bytesbuff, strlen(bytesbuff)); if (!CrossPosted) BUFFappend(&Headers, Xref.Data, Xref.Used); for (vp = iov; vp < end; vp++) BUFFappend(&Headers, vp->iov_base, vp->iov_len); Data->Headers = &Headers; return 0;}/*** Parse a header that starts at in, copying it to out. Return pointer to** the start of the next header and fill in *deltap with what should** get added to the output pointer. (This nicely lets us clobber obsolete** headers by setting it to zero.)*/STATIC char *ARTparseheader(in, out, deltap, errorp) register char *in; register char *out; int *deltap; STRING *errorp;{ static char buff[SMBUF]; static char COLONSPACE[] = "No colon-space in \"%s\" header"; register char *start; register TREE *tp; register ARTHEADER *hp; register char c; register char *p; register char *dest; register int i; register char *colon; /* Find a non-continuation line. */ for (colon = NULL, start = out; ; ) { switch (*in) { case '\0': *errorp = "EOF in headers"; return NULL; case ':': if (colon == NULL) colon = out; break; } if ((*out++ = *in++) == '\n' && !ISWHITE(*in)) break; } *deltap = out - start; if (colon == NULL || !ISWHITE(colon[1])) { if ((p = strchr(start, '\n')) != NULL) *p = '\0'; (void)sprintf(buff, COLONSPACE, MaxLength(start, start)); *errorp = buff; return NULL; } /* See if this is a system header. A fairly tightly-coded * binary search. */ c = CTYPE(islower, *start) ? toupper(*start) : *start; for (*colon = '\0', tp = ARTheadertree; tp; ) { if ((i = c - tp->Name[0]) == 0 && (i = strcasecmp(start, tp->Name)) == 0) break; if (i < 0) tp = tp->Before; else tp = tp->After; } *colon = ':'; if (tp == NULL) { /* Not a system header, make sure we have <word><colon><space>. */ for (p = colon; --p != start; ) if (ISWHITE(*p)) { (void)sprintf(buff, "Space before colon in \"%s\" header", MaxLength(start, start)); *errorp = buff; return NULL; } return in; } /* Found a known header; is it obsolete? */ hp = tp->Header; if (hp->Type == HTobs) { *deltap = 0; return in; } /* If body of header is all blanks, drop the header. */ for (p = colon + 1; ISWHITE(*p); p++) continue; if (*p == '\0' || *p == '\n') { *deltap = 0; return in; } hp->Found++; /* Zap in the canonical form of the header, undoing the \0 that * strcpy put out (strncpy() spec isn't trustable, unfortunately). */ (void)strcpy(start, hp->Name); start[hp->Size] = ':'; /* Copy the header if not too big. */ i = (out - 1) - p; if (i >= MAXHEADERSIZE) { (void)sprintf(buff, "\"%s\" header too long", hp->Name); *errorp = buff; return NULL; } hp->Length = i; if (i > MEMCPY_THRESHOLD) { (void)memcpy((POINTER)hp->Value, (POINTER)p, (SIZE_T)i); hp->Value[i] = '\0'; } else { for (dest = hp->Value, i++; --i > 0; ) *dest++ = *p++; *dest = '\0'; } return in;}/*** Check Message-ID format based on RFC 822 grammar, except that (as per** RFC 1036) whitespace, non-printing, and '>' characters are excluded.** Based on code by Paul Eggert posted to news.software.b on 22-Nov-90** in <#*tyo2'~n@twinsun.com>, with additional email discussion.** Thanks, Paul.*/BOOLARTidok(save) char *save;{ register int c; register char *p; /* Scan local-part: "< atom|quoted [ . atom|quoted]" */ p = save; if (*p++ != '<') return FALSE; for (; ; p++) { if (ARTatomchar(*p)) while (ARTatomchar(*++p)) continue; else { if (*p++ != '"') return FALSE; for ( ; ; ) { switch (c = *p++) { case '\\': c = *p++; /* FALLTHROUGH */ default: if (ARTnormchar(c)) continue; return FALSE; case '"': break; } break; } } if (*p != '.') break; } /* Scan domain part: "@ atom|domain [ . atom|domain] > \0" */ if (*p++ != '@') return FALSE; for ( ; ; p++) { if (ARTatomchar(*p)) while (ARTatomchar(*++p)) continue; else { if (*p++ != '[') return FALSE; for ( ; ; ) { switch (c = *p++) { case '\\': c = *p++; /* FALLTHROUGH */ default: if (ARTnormchar(c)) continue; /* FALLTHROUGH */ case '[': return FALSE; case ']': break; } break; } } if (*p != '.') break; } return *p == '>' && *++p == '\0' && p - save <= DBZMAXKEY;}/*** Clean up an article. This is mainly copying in-place, stripping bad** headers. Also fill in the article data block with what we can find.** Return NULL if the article is okay, or a string describing the error.*/STATIC STRINGARTclean(Article, Data) BUFFER *Article; ARTDATA *Data;{ static char buff[SMBUF]; ARTHEADER *hp; register char *in; register char *out; register int i; register char *p; STRING error; int delta; /* Read through the headers one at a time. */ Data->Feedsite = "?"; Data->Size[0] = '0'; Data->Size[1] = '\0'; for (hp = ARTheaders; hp < ENDOF(ARTheaders); hp++) { if (hp->Value && hp->Type != HTobs) *hp->Value = '\0'; hp->Found = 0; } for (error = NULL, in = out = Article->Data; ; out += delta, in = p) { if (*in == '\0') { error = "No body"; break; } if (*in == '\n' && out > Article->Data && out[-1] == '\n') /* Found a \n after another \n; break out. */ break; /* Check the validity of this header. */ if ((p = ARTparseheader(in, out, &delta, &error)) == NULL) break; } Data->Body = out; in++; /* Try to set this now, so we can report it in errors. */ p = HDR(_message_id); if (*p) { Data->MessageID = p; Data->MessageIDLength = strlen(p); if (error == NULL) { if (Data->MessageIDLength > DBZMAXKEY) error = "\"Message-ID\" header too long"; else if (!ARTidok(p)) error = "Bad \"Message-ID\" header"; } } if (error) return error; /* Make sure all the headers we need are there, and no duplicates. */ for (hp = ARTheaders; hp < ENDOF(ARTheaders); hp++) if (hp->Type == HTreq) { if (*hp->Value == '\0') { (void)sprintf(buff, "Missing \"%s\" header", hp->Name); return buff; } if (hp->Found > 1) { (void)sprintf(buff, "Duplicate \"%s\" header", hp->Name); return buff; } } /* Scan the body, counting lines. */ for (i = 0; *in; ) { if (*in == '\n') i++; *out++ = *in++; } *out = '\0'; Article->Used = out - Article->Data; Data->LinesValue = i;#if defined(DO_CHECK_LINECOUNT) p = HDR(_lines); if (*p && (delta = i - atoi(p)) != 0 && abs(delta) > LINECOUNT_FUZZ) { if ((in = strchr(p, '\n')) != NULL) *in = '\0'; (void)sprintf(buff, "Linecount %s != %d +- %d", MaxLength(p, p), i, LINECOUNT_FUZZ); return buff; }#endif /* defined(DO_CHECK_LINECOUNT) */ /* Is article too old? */ p = HDR(_date); if ((Data->Posted = parsedate(p, &Now)) == -1) { (void)sprintf(buff, "Bad \"Date\" header -- \"%s\"", MaxLength(p, p)); return buff; } if (Cutoff && Data->Posted < Now.time - Cutoff) { (void)sprintf(buff, "Too old -- \"%s\"", MaxLength(p, p)); return buff; } if (Data->Posted > Now.time + DATE_FUZZ) { (void)sprintf(buff, "Article posted in the future -- \"%s\"", MaxLength(p, p)); return buff; } Data->Arrived = Now.time; p = HDR(_expires); Data->Expires = 0; if (*p != '\0' && (Data->Expires = parsedate(p, &Now)) == -1) {#if 0 (void)sprintf(buff, "Bad \"Expires\" header -- \"%s\"", MaxLength(p, p)); return buff;#endif } /* Whitespace in the Newsgroups header? */ for (p = HDR(_newsgroups); *p; p++) if (ISWHITE(*p)) { (void)sprintf(buff, "Whitespace in \"Newsgroups\" header -- \"%s\"", MaxLength(HDR(_newsgroups), p)); return buff; } /* If there is no control header, see if the article starts with * "cmsg ". */ in = HDR(_control); if (*in == '\0') { p = HDR(_subject); if (*p == 'c' && EQn(p, "cmsg ", 5)) { for (p += 5; *p && ISWHITE(*p); ) p++; if (*p) (void)strcpy(in, p); } } return NULL;}/*** Start a log message about an article.*/STATIC voidARTlog(Data, code, text) ARTDATA *Data; char code; char *text;{ int i; BOOL Done; /* We could be a bit faster by not dividing Now.usec by 1000, * but who really wants to log at the Microsec level? */ Done = code == ART_ACCEPT || code == ART_JUNK; if (text) i = fprintf(Log, "%.15s.%03.3d %c %s %s %s%s", ctime(&Now.time) + 4, (int)(Now.usec / 1000), code, Data->Feedsite, Data->MessageID, text, Done ? "" : "\n"); else i = fprintf(Log, "%.15s.%03.3d %c %s %s%s", ctime(&Now.time) + 4, (int)(Now.usec / 1000), code, Data->Feedsite, Data->MessageID, Done ? "" : "\n"); if (i == EOF || (Done && !BufferedLogs && fflush(Log)) || ferror(Log)) { IOError("logging article"); syslog(L_ERROR, "%s cant write log_start %m", LogName); clearerr(Log);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -