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

📄 art.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
	    IOError("logging site");	    syslog(L_ERROR, "%s cant write log_site %m", LogName);	    clearerr(Log);	}	sp->Sendit = TRUE;	sp->Seenit = TRUE;	if (sp->Master != NOSITE)	    Sites[sp->Master].Seenit = TRUE;    }    if (putc('\n', Log) == EOF     || (!BufferedLogs && fflush(Log))     || ferror(Log)) {	syslog(L_ERROR, "%s cant write log_end %m", LogName);	clearerr(Log);    }    /* Handle funnel sites. */    for (sp = Sites, i = nSites; --i >= 0; sp++)	if (sp->Sendit && sp->Funnel != NOSITE) {	    sp->Sendit = FALSE;	    funnel = &Sites[sp->Funnel];	    funnel->Sendit = TRUE;	    if (funnel->FNLwantsnames) {		bp = &funnel->FNLnames;		p = &bp->Data[bp->Used];		if (bp->Used) {		    *p++ = ' ';		    bp->Used++;		}		bp->Used += strlen(strcpy(p, sp->Name));	    }	}}/***  Build up the overview data.*/STATIC voidARTmakeoverview(Data)    ARTDATA			*Data;{    static char			SEP[] = "\t";    static char			COLONSPACE[] = ": ";    static BUFFER		Overview;    register ARTOVERFIELD	*fp;    register ARTHEADER		*hp;    register char		*p;    register int		i;    /* Setup. */    if (Overview.Data == NULL)	Overview.Data = NEW(char, 1);    Data->Overview = &Overview;    BUFFset(&Overview, Xref.Data + Xrefbase + 1, Xref.Used - (Xrefbase + 2));    for (i = Overview.Left, p = Overview.Data; --i >= 0; p++)	if (*p == '.' || *p == ':')	    *p = '/';    if (ARTfields == NULL) {	/* User error. */	return;    }    /* Write the data, a field at a time. */    for (fp = ARTfields; fp->Header; fp++) {	BUFFappend(&Overview, SEP, STRLEN(SEP));	hp = fp->Header;	if (!hp->Found)	    continue;	 if (fp->NeedHeader) {	      BUFFappend(&Overview, hp->Name, hp->Size);	      BUFFappend(&Overview, COLONSPACE, STRLEN(COLONSPACE));	 }	 i = Overview.Left;	 BUFFappend(&Overview, hp->Value, hp->Length);	 for (p = &Overview.Data[i]; i < Overview.Left; p++, i++)	     if (*p == '\t' || *p == '\n')		 *p = ' ';    }}/***  This routine is the heart of it all.  Take a full article, parse it,**  file or reject it, feed it to the other sites.  Return the NNTP**  message to send back.*/STRINGARTpost(cp, Replic, ihave)    CHANNEL		*cp;    BUFFER		*Replic;    char		*ihave;{    static char		errNOSPACE[] = NNTP_RESENDIT_NOSPACE;    static char		errNOHIST[] = NNTP_RESENDIT_NOHIST;    static BUFFER	Files;    static BUFFER	Header;    static char		buff[SPOOLNAMEBUFF];    register char	*p;    register int	i;    register int	j;    register NEWSGROUP	*ngp;    register NEWSGROUP	**ngptr;    register int	*isp;    register SITE	*sp;    ARTDATA		Data;    BOOL		Approved;    BOOL		Accepted;    BOOL		LikeNewgroup;    BOOL		CrossPosted;    BOOL		ToGroup;    BOOL		GroupMissing;    BUFFER		*article;    char		linkname[SPOOLNAMEBUFF];    char		**groups;    char		**hops;    int			hopcount;    char		**distributions;    STRING		error;    char		ControlWord[SMBUF];    int			ControlHeader;    /* Preliminary clean-ups. */    article = &cp->In;    Data.MessageID = ihave;    error = ARTclean(article, &Data);    /* Fill in other Data fields. */    Data.Poster = HDR(_sender);    if (*Data.Poster == '\0')	Data.Poster = HDR(_from);    Data.Replyto = HDR(_reply_to);    if (*Data.Replyto == '\0')	Data.Replyto = HDR(_from);    hops = ARTparsepath(HDR(_path), &hopcount);#if	defined(DO_IPADDR_LOG)    Data.Feedsite = RChostname(cp);    if (Data.Feedsite == NULL)	Data.Feedsite = CHANname(cp);#else    Data.Feedsite = hops && hops[0] ? hops[0] : CHANname(cp);#endif	/* defined(DO_IPADDRLOG) */    Data.FeedsiteLength = strlen(Data.Feedsite);    (void)sprintf(Data.TimeReceived, "%lu", Now.time);    Data.TimeReceivedLength = strlen(Data.TimeReceived);    /* A duplicate? */    if (error == NULL && HIShavearticle(Data.MessageID))	error = "Duplicate article";    /* Now see if we got an error in the article. */    if (error != NULL) {	(void)sprintf(buff, "%d %s", NNTP_REJECTIT_VAL, error);	ARTlog(&Data, ART_REJECT, buff);	ARTreject(buff, article);	return buff;    }    /* Stash a copy of the Newsgroups header. */    p = HDR(_newsgroups);    i = strlen(p);    if (Header.Data == NULL) {	Header.Size = i;	Header.Data = NEW(char, Header.Size + 1);    }    else if (Header.Size <= i) {	Header.Size = i + 16;	RENEW(Header.Data, char, Header.Size + 1);    }    (void)strcpy(Header.Data, p);    Data.Newsgroups = Header.Data;    Data.NewsgroupsLength = i;    /* If we limit what distributions we get, see if we want this one. */    p = HDR(_distribution);    distributions = *p ? CommaSplit(p) : NULL;    if (distributions) {	DISTparse(distributions, &Data);	if (ME.Distributions	 && !DISTwantany(ME.Distributions, distributions)) {	    (void)sprintf(buff, "%d Unwanted distribution \"%s\"",		    NNTP_REJECTIT_VAL,		    MaxLength(distributions[0], distributions[0]));	    ARTlog(&Data, ART_REJECT, buff);	    DISPOSE(distributions);	    ARTreject(buff, article);	    return buff;	}    }    else {	Data.Distribution = "?";	Data.DistributionLength = 1;    }    /* Clear all groups and sites -- assume nobody gets the article. */    for (i = nGroups, ngp = Groups; --i >= 0; ngp++)	ngp->PostCount = 0;    for (i = nSites, sp = Sites; --i >= 0; sp++) {	sp->Sendit = FALSE;	sp->Seenit = FALSE;	sp->FNLnames.Used = 0;	sp->ng = NULL;    }    /* Parse the Control or Also-Control header. */    groups = NGsplit(HDR(_newsgroups));    for (i = 0; groups[i] != NULL; i++)	continue;    Data.Groupcount = i;    if (HDR(_control)[0] != '\0')	ControlHeader = _control;    else if (HDR(_alsocontrol)[0] != '\0')	ControlHeader = _alsocontrol;    else {	ControlHeader = -1;	LikeNewgroup = FALSE;    }    if (ControlHeader >= 0) {	/* Nip off the first word into lowercase. */	(void)strncpy(ControlWord, HDR(ControlHeader), sizeof ControlWord);	ControlWord[sizeof ControlWord - 1] = '\0';	for (p = ControlWord; *p && !ISWHITE(*p); p++)	    if (CTYPE(isupper, *p))		*p = tolower(*p);	*p = '\0';	LikeNewgroup = EQ(ControlWord, "newgroup")		    || EQ(ControlWord, "rmgroup");	/* Control messages to "foo.ctl" are treated as if they were	 * posted to "foo".  I should probably apologize for all the	 * side-effects in the if. */	for (i = 0; (p = groups[i++]) != NULL; )	    if ((j = strlen(p) - 4) > 0	     && *(p += j) == '.'	     && p[1] == 'c' && p[2] == 't' && p[3] == 'l')		*p = '\0';    }    /* Loop over the newsgroups, see which ones we want, and get the     * total space needed for the Xref line.  At the end of this section     * of code, j will have the needed length, the appropriate site     * entries will have their Sendit and ng fields set, and GroupPointers     * will have pointers to the relevant newsgroups. */    ToGroup = FALSE;    p = HDR(_approved);    Approved = *p != '\0';    ngptr = GroupPointers;    j = 0;    for (GroupMissing = Accepted = FALSE; (p = *groups) != NULL; groups++) {	if (!RCcanpost(cp, p))	    continue;	if ((ngp = NGfind(p)) == NULL) {	    GroupMissing = TRUE;	    if (LikeNewgroup && Approved) {		/* Newgroup/rmgroup being sent to a group that doesn't		 * exist.  Assume it is being sent to the group being		 * created or removed, nd send the group to all sites that		 * would or would have had the group if it were created. */		ARTsendthegroup(*groups);		Accepted = TRUE;	    }#if	defined(DO_MERGE_TO_GROUPS)	    /* Try to collapse all "to" newsgroups. */	    if (*p != 't' || *++p != 'o' || *++p != '.' || *++p == '\0')		continue;	    ngp = NGfind("to");	    ToGroup = TRUE;	    if ((sp = SITEfind(p)) != NULL) {		SITEmark(sp, ngp);	    }#else	    continue;#endif	/* defined(DO_MERGE_TO_GROUPS) */	}	/* Ignore this group? */	if (ngp->Rest[0] == NF_FLAG_IGNORE)	    continue;	/* Basic validity check. */	if (ngp->Rest[0] == NF_FLAG_MODERATED && !Approved) {	    (void)sprintf(buff, "%d Unapproved for \"%s\"",		    NNTP_REJECTIT_VAL, ngp->Name);	    ARTlog(&Data, ART_REJECT, buff);	    if (distributions)		DISPOSE(distributions);	    ARTreject(buff, article);	    return buff;	}	/* Valid group, feed it to that group's sites. */	Accepted = TRUE;	for (isp = ngp->Sites, i = ngp->nSites; --i >= 0; isp++)	    if (*isp >= 0) {		sp = &Sites[*isp];		SITEmark(sp, ngp);	    }	/* If it's excluded, don't file it. */	if (ngp->Rest[0] == NF_FLAG_EXCLUDED)	    continue;	/* Expand aliases, mark the article as getting filed in the group. */	if (ngp->Alias != NULL)	    ngp = ngp->Alias;	*ngptr++ = ngp;	ngp->PostCount = 0;	j += ngp->NameLength + 1 + MAXARTFNAME + 1;    }    /* Control messages not filed in "to" get filed only in controlname     * or control. */    if (ControlHeader >= 0 && Accepted && !ToGroup) {	FileGlue(buff, "control", '.', ControlWord);	if ((ngp = NGfind(buff)) == NULL)	    ngp = NGfind(ARTctl);	ngp->PostCount = 0;	ngptr = GroupPointers;	*ngptr++ = ngp;	j = ngp->NameLength + 1 + MAXARTFNAME;	for (isp = ngp->Sites, i = ngp->nSites; --i >= 0; isp++)	    if (*isp >= 0) {		sp = &Sites[*isp];		SITEmark(sp, ngp);	    }    }    /* If !Accepted, then none of the article's newgroups exist in our     * active file.  Proper action is to drop the article on the floor.     * If ngp == GroupPointers, then all the new articles newsgroups are     * "j" entries in the active file.  In that case, we have to file it     * under junk so that downstream feeds can get it. */    if (!Accepted || ngptr == GroupPointers) {	if (!Accepted) {	    (void)sprintf(buff, "%d Unwanted newsgroup \"%s\"",		NNTP_REJECTIT_VAL,		MaxLength(HDR(_newsgroups), HDR(_newsgroups)));	    ARTlog(&Data, ART_REJECT, buff);#if	defined(DONT_WANT_TRASH)#if	defined(DO_REMEMBER_TRASH)	    if (Mode == OMrunning && !HISwrite(&Data, ""))		syslog(L_ERROR, "%s cant write history %s %m",		    LogName, Data.MessageID);#endif	/* defined(DO_REMEMBER_TRASH) */	    if (distributions)		DISPOSE(distributions);	    ARTreject(buff, article);	    return buff;#else	    /* if !GroupMissing, then all the groups the article was posted	     * to have a flag of "x" in our active file, and therefore	     * we should throw the article away:  if you have define	     * DO_WANT_TRASH, then you want all trash except that which	     * you explicitly excluded in your active file. */	    if (!GroupMissing) {		if (distributions)		    DISPOSE(distributions);		ARTreject(buff, article);		return buff;	    }#endif	/* defined(DONT_WANT_TRASH) */	}	ngp = NGfind(ARTjnk);	*ngptr++ = ngp;	ngp->PostCount = 0;	j = STRLEN(ARTjnk) + 1 + MAXARTFNAME;	/* Junk can be fed to other sites. */	for (isp = ngp->Sites, i = ngp->nSites; --i >= 0; isp++)	    if (*isp >= 0) {		sp = &Sites[*isp];		SITEmark(sp, ngp);	    }    }    *ngptr = NULL;    CrossPosted = ngptr > &GroupPointers[1] || AlwaysCrosspost;    j++;    if (Replic)	j = Replic->Used + 1;    /* Make sure the Xref buffer has room. */    Xref.Used = Xrefbase;    if (Xref.Size <= j + Xrefbase + 2) {	Xref.Size = j + Xrefbase + 2;	RENEW(Xref.Data, char, Xref.Size + 1);    }    /* Make sure the filename buffer has room. */    if (Files.Data == NULL) {	Files.Size = j;	Files.Data = NEW(char, Files.Size + 1);    }    else if (Files.Size <= j) {	Files.Size = j;	RENEW(Files.Data, char, Files.Size + 1);    }    /* Assign article numbers, fill in Xref buffer. */    if (Replic == NULL)	ARTassignnumbers();    else	ARTreplic(Replic, &CrossPosted);    /* Optimize how we place the article on the disk. */    ARTsortfordisk();    /* Now we can file it. */    if (++ICDactivedirty >= ICD_SYNC_COUNT) {	ICDwriteactive();	ICDactivedirty = 0;    }    Data.Name[0] = '\0';    p = Files.Data;    *p = '\0';    for (i = 0; (ngp = GroupPointers[i]) != NULL; i++) {	if (!ngp->PostCount)	    continue;	ngp->PostCount = 0;	if (Data.Name[0] == '\0') {	    /* Write the article the first time. */	    (void)sprintf(Data.Name, "%s/%lu", ngp->Dir, ngp->Filenum);	    if (ARTwrite(Data.Name, article, &Data, CrossPosted) < 0	     && (!MakeSpoolDirectory(ngp->Dir)	      || ARTwrite(Data.Name, article, &Data, CrossPosted) < 0)) {		syslog(L_ERROR, "%s cant write %s %m", LogName, Data.Name);		ARTlog(&Data, ART_REJECT, errNOSPACE);		if (distributions)		    DISPOSE(distributions);		ARTreject(buff, article);		return errNOSPACE;	    }	    p += strlen(strcpy(p, Data.Name));	    Data.NameLength = strlen(Data.Name);	}	else {	    /* Link to the main article. */	    (void)sprintf(linkname, "%s/%lu", ngp->Dir, ngp->Filenum);	    if (link(Data.Name, linkname) < 0	     && (!MakeSpoolDirectory(ngp->Dir)	      || link(Data.Name, linkname) < 0)) {#if	defined(DONT_HAVE_SYMLINK)		IOError("linking article");		syslog(L_ERROR, "%s cant link %s and %s %m",		    LogName, Data.Name, linkname);		continue;#else		/* Try to make a symbolic link to the full pathname. */		FileGlue(buff, SPOOL, '/', Data.Name);		if (symlink(buff, linkname) < 0		 && (!MakeSpoolDirectory(ngp->Dir)		  || symlink(buff, linkname) < 0)) {		    IOError("symlinking article");		    syslog(L_ERROR, "%s cant symlink %s and %s %m",			LogName, buff, linkname);		    continue;		}#endif	/* defined(DONT_HAVE_SYMLINK) */	    }	    *p++ = ' ';	    p += strlen(strcpy(p, linkname));	}    }    /* Update history if we didn't get too many I/O errors above. */    if (Mode != OMrunning || !HISwrite(&Data, Files.Data)) {	syslog(L_ERROR, "%s cant write history %s %m", LogName, Data.MessageID);	ARTlog(&Data, ART_REJECT, errNOHIST);	if (distributions)	    DISPOSE(distributions);	ARTreject(buff, article);	return errNOHIST;    }    /* If we just flushed the active (above), now flush history. */    if (ICDactivedirty == 0)	HISsync();    /* We wrote the history, so modify it and save it for output. */    for (Data.Replic = Files.Data, p = (char *)Data.Replic; *p; p++)	if (*p == ' ')	    *p = ',';    Data.ReplicLength = p - Data.Replic;    /* Start logging, then propagate the article. */    ARTlog(&Data, Accepted ? ART_ACCEPT : ART_JUNK, (char *)NULL);#if	defined(DO_NNTPLINK_LOG)    if (fprintf(Log, " (%s)", Data.Name) == EOF || ferror(Log)) {	IOError("logging nntplink");	syslog(L_ERROR, "%s cant write log_nntplink %m", LogName);	clearerr(Log);    }#endif	/* defined(DO_NNTPLINK_LOG) */    ARTpropagate(&Data, hops, hopcount, distributions);    if (distributions)	DISPOSE(distributions);    /* Now that it's been written, process the control message.  This has     * a small window, if we get a new article before the newgroup message     * has been processed.  We could pause ourselves here, but it doesn't     * seem to be worth it. */    if (Accepted) {	if (ControlHeader >= 0)	    ARTcontrol(&Data, HDR(ControlHeader));	p = HDR(_supersedes);	if (*p)	    ARTcancel(&Data, p, FALSE);    }    /* If we need the overview data, write it. */    if (NeedOverview)	ARTmakeoverview(&Data);    /* And finally, send to everyone who should get it */    for (sp = Sites, i = nSites; --i >= 0; sp++)	if (sp->Sendit)	    SITEsend(sp, &Data);    return NNTP_TOOKIT;}

⌨️ 快捷键说明

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