?? art.c
字號:
}}/*** We are going to reject an article, record the reason and** and the article. For now, this is just a placeholder.*//* ARGSUSED0 */STATIC voidARTreject(buff, article) char *buff; BUFFER *article;{}#if defined(DO_VERIFY_CANCELS)/*** Verify if a cancel message is valid. If the user posting the cancel** matches the user who posted the article, return the list of filenames** otherwise return NULL.*/STATIC char *ARTcancelverify(Data, MessageID) ARTDATA *Data; char *MessageID;{ register char *files; register char *p; register char *local; char *head; char buff[SMBUF]; files = HISfilesfor(MessageID); if ((head = ARTreadheader(files)) == NULL) return NULL; /* Get the author header. */ if ((local = HeaderFind(head, "Sender", 6)) == NULL && (local = HeaderFind(head, "From", 4)) == NULL) { syslog(L_ERROR, "%s bad_article %s checking cancel", LogName, MessageID); return NULL; } HeaderCleanFrom(local); /* Compare canonical forms. */ p = COPY(Data->Poster); HeaderCleanFrom(p); if (!EQ(local, p)) { files = NULL; (void)sprintf(buff, "\"%.50s\" wants to cancel %s by \"%.50s\"", p, MaxLength(MessageID, MessageID), local); ARTlog(Data, ART_REJECT, buff); } DISPOSE(p); return files;}#endif /* defined(DO_VERIFY_CANCELS) *//*** Process a cancel message.*//* ARGSUSED2 */voidARTcancel(Data, MessageID, Trusted) ARTDATA *Data; char *MessageID; BOOL Trusted;{ register char *files; register char *p; register BOOL more; STRING save; char buff[SMBUF]; if (!HIShavearticle(MessageID)) { /* Article hasn't arrived here, so write a fake entry using * most of the information from the cancel message. */#if defined(DO_VERIFY_CANCELS) if (!Trusted) return;#endif /* defined(DO_VERIFY_CANCELS) */ save = Data->MessageID; Data->MessageID = MessageID; (void)HISwrite(Data, (char *)NULL); Data->MessageID = save; (void)sprintf(buff, "Cancelling %s", MessageID); ARTlog(Data, ART_CANC, buff); return; }#if defined(DO_VERIFY_CANCELS) files = Trusted ? HISfilesfor(MessageID) : ARTcancelverify(Data, MessageID);#else files = HISfilesfor(MessageID);#endif /* !defined(DO_VERIFY_CANCELS) */ if (files == NULL) return; /* Get the files where the message is stored and and zap them. */ 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'; /* Remove this file, go back for the next one if there's more. */ if (unlink(files) < 0 && errno != ENOENT) syslog(L_ERROR, "%s cant unlink %s %m", LogName, files); if (!more) break; }}/*** Process a control message. Cancels are handled here, but any others** are passed out to an external program in a specific directory that** has the same name as the first word of the control message.*/STATIC voidARTcontrol(Data, Control) ARTDATA *Data; char *Control;{ static char CTLBIN[] = _PATH_CONTROLPROGS; register char *p; char buff[SMBUF]; char *av[6]; struct stat Sb; register char c; /* See if it's a cancel message. */ c = *Control; if (c == 'c' && EQn(Control, "cancel", 6)) { for (p = &Control[6]; ISWHITE(*p); p++) continue; if (*p) ARTcancel(Data, p, FALSE); return; } /* Nip off the first word into lowercase. */ for (p = Control; *p && !ISWHITE(*p); p++) if (CTYPE(isupper, *p)) *p = tolower(*p); if (*p) *p++ = '\0'; /* Treat the control message as a place to send the article, if * the name is "safe" -- no slashes in the pathname. */ if (p - Control + STRLEN( _PATH_BADCONTROLPROG) >= SMBUF-4 || strchr(Control, '/') != NULL) FileGlue(buff, CTLBIN, '/', _PATH_BADCONTROLPROG); else { FileGlue(buff, CTLBIN, '/', Control); if (stat(buff, &Sb) < 0 || (Sb.st_mode & EXECUTE_BITS) == 0) FileGlue(buff, CTLBIN, '/', _PATH_BADCONTROLPROG); } /* If it's an ihave or sendme, check the site named in the message. */ if ((c == 'i' && EQ(Control, "ihave")) || (c == 's' && EQ(Control, "sendme"))) { while (ISWHITE(*p)) p++; if (*p == '\0') { syslog(L_NOTICE, "%s malformed %s no site %s", LogName, Control, Data->Name); return; } if (EQ(p, ARTpathme)) { /* Do nothing -- must have come from a replicant. */ syslog(L_NOTICE, "%s %s_from_me %s", Data->Feedsite, Control, Data->Name); return; } if (!SITEfind(p)) { if (c == 'i') syslog(L_ERROR, "%s bad_ihave in %s", Data->Feedsite, Data->Newsgroups); else syslog(L_ERROR, "%s bad_sendme dont feed %s", Data->Feedsite, Control, Data->Name); return; } } /* Build the command vector and execute it. */ av[0] = buff; av[1] = COPY(Data->Poster); av[2] = COPY(Data->Replyto); av[3] = Data->Name; av[4] = (char *)Data->Feedsite; av[5] = NULL; HeaderCleanFrom(av[1]); HeaderCleanFrom(av[2]); if (Spawn(STDIN, (int)fileno(Errlog), (int)fileno(Errlog), av) < 0) /* We know the strrchr below can't fail. */ syslog(L_ERROR, "%s cant spawn %s for %s %m", LogName, MaxLength(av[0], strrchr(av[0], '/')), Data->Name); DISPOSE(av[1]); DISPOSE(av[2]);}/*** Split a Distribution header, making a copy and skipping leading and** trailing whitespace (which the RFC allows).*/STATIC voidDISTparse(list, Data) register char **list; ARTDATA *Data;{ static BUFFER Dist; register char *p; register char *q; register int i; register int j; /* Get space to store the copy. */ for (i = 0, j = 0; (p = list[i]) != NULL; i++) j += 1 + strlen(p); if (Dist.Data == NULL) { Dist.Size = j; Dist.Data = NEW(char, Dist.Size + 1); } else if (Dist.Size <= j) { Dist.Size = j + 16; RENEW(Dist.Data, char, Dist.Size + 1); } /* Loop over each element, skip and trim whitespace. */ for (q = Dist.Data, i = 0, j = 0; (p = list[i]) != NULL; i++) { while (ISWHITE(*p)) p++; if (*p) { if (j) *q++ = ','; for (list[j++] = p; *p && !ISWHITE(*p); ) *q++ = *p++; *p = '\0'; } } list[j] = NULL; *q = '\0'; Data->Distribution = Dist.Data; Data->DistributionLength = q - Dist.Data;}/*** A somewhat similar routine, except that this handles negated entries** in the list and is used to check the distribution sub-field.*/STATIC BOOLDISTwanted(list, p) register char **list; register char *p;{ register char *q; register char c; register BOOL sawbang; for (sawbang = FALSE, c = *p; (q = *list) != NULL; list++) if (*q == '!') { sawbang = TRUE; if (c == *++q && EQ(p, q)) return FALSE; } else if (c == *q && EQ(p, q)) return TRUE; /* If we saw any !foo's and didn't match, then assume they are all * negated distributions and return TRUE, else return false. */ return sawbang;}/*** See if any of the distributions in the article are wanted by the site.*/STATIC BOOLDISTwantany(site, article) char **site; register char **article;{ for ( ; *article; article++) if (DISTwanted(site, *article)) return TRUE; return FALSE;}/*** Sort an array of newsgroups for optimal disk access. This may be** of marginal benefit.*/STATIC voidARTsortfordisk(){ static NEWSGROUP *save; register NEWSGROUP **ngptr; if (save && GroupPointers[1] != NULL) { /* If one of the groups we want to access is the group we last * wrote to, move it to the front of the list. */ for (ngptr = GroupPointers; *++ngptr; ) if (*ngptr == save) { *ngptr = GroupPointers[0]; GroupPointers[0] = save; return; } } save = GroupPointers[0];}/*** Send the current article to all sites that would get it if the** group were created.*/STATIC voidARTsendthegroup(name) register char *name;{ register SITE *sp; register int i; NEWSGROUP *ngp; for (ngp = NGfind(ARTctl), sp = Sites, i = nSites; --i >= 0; sp++) if (sp->Name != NULL && SITEwantsgroup(sp, name)) { SITEmark(sp, ngp); }}/*** Assign article numbers to the article and create the Xref line.** If we end up not being able to write the article, we'll get "holes"** in the directory and active file.*/STATIC voidARTassignnumbers(){ register char *p; register int i; register NEWSGROUP *ngp; p = &Xref.Data[Xref.Used]; for (i = 0; (ngp = GroupPointers[i]) != NULL; i++) { /* If already went to this group (i.e., multiple groups are aliased * into it), then skip it. */ if (ngp->PostCount > 0) continue; /* Bump the number. */ ngp->PostCount++; ngp->Last++; if (!FormatLong(ngp->LastString, (long)ngp->Last, ngp->Lastwidth)) { syslog(L_ERROR, "%s cant update_active %s", LogName, ngp->Name); continue; } ngp->Filenum = ngp->Last; (void)sprintf(p, " %s:%lu", ngp->Name, ngp->Filenum); p += strlen(p); } Xref.Used = p - Xref.Data; Xref.Data[Xref.Used++] = '\n';}/*** Parse the data from the xreplic command and assign the numbers.** This involves replacing the GroupPointers entries.*/STATIC voidARTreplic(Replic, CrossPostedp) BUFFER *Replic; BOOL *CrossPostedp;{ register char *p; register char *q; register char *name; register char *next; register NEWSGROUP *ngp; register int i; p = &Xref.Data[Xref.Used]; for (i = 0, name = Replic->Data; *name; name = next) { /* Mark end of this entry and where next one starts. */ if ((next = strchr(name, ',')) != NULL) *next++ = '\0'; else next = ""; /* Split into news.group/# */ if ((q = strchr(name, '/')) == NULL) { syslog(L_ERROR, "%s bad_format %s", LogName, name); continue; } *q = '\0'; if ((ngp = NGfind(name)) == NULL) { syslog(L_ERROR, "%s bad_newsgroup %s", LogName, name); continue; } ngp->Filenum = atol(q + 1); /* Update active file if we got a new high-water mark. */ if (ngp->Last < ngp->Filenum) { ngp->Last = ngp->Filenum; if (!FormatLong(ngp->LastString, (long)ngp->Last, ngp->Lastwidth)) { syslog(L_ERROR, "%s cant update_active %s", LogName, ngp->Name); continue; } } /* Mark that this group gets the article. */ ngp->PostCount++; GroupPointers[i++] = ngp; /* Turn news.group/# into news.group:#, append to Xref. */ *q = ':'; *p++ = ' '; p += strlen(strcpy(p, name)); } *CrossPostedp = i > 1 || AlwaysCrosspost; Xref.Used = p - Xref.Data; Xref.Data[Xref.Used++] = '\n';}/*** Return TRUE if a list of strings has a specific one. This is a** generic routine, but is used for seeing if a host is in the Path line.*/STATIC BOOLListHas(list, p) register char **list; register char *p;{ register char *q; register char c; for (c = *p; (q = *list) != NULL; list++) if (c == *q && caseEQ(p, q)) return TRUE; return FALSE;}/*** Propagate an article to the sites have "expressed an interest."*/STATIC voidARTpropagate(Data, hops, hopcount, list) ARTDATA *Data; char **hops; int hopcount; char **list;{ register SITE *sp; register int i; register int j; register int Groupcount; register char *p; register SITE *funnel; register BUFFER *bp; /* Work out which sites should really get it. */ Groupcount = Data->Groupcount; for (sp = Sites, i = nSites; --i >= 0; sp++) { if (sp->Seenit || !sp->Sendit) continue; sp->Sendit = FALSE; if (sp->Master != NOSITE && Sites[sp->Master].Seenit) continue; if (sp->MaxSize && sp->MaxSize < Data->SizeValue) /* Too big for the site. */ continue; if ((!sp->IgnorePath && ListHas(hops, sp->Name)) || (sp->Hops && hopcount > sp->Hops) || (sp->Groupcount && Groupcount > sp->Groupcount)) /* Site already saw the article; path too long; or too much * cross-posting. */ continue; if (list && sp->Distributions && !DISTwantany(sp->Distributions, list)) /* Not in the site's desired list of distributions. */ continue; if (sp->DistRequired && list == NULL) /* Site requires Distribution header and there isn't one. */ continue; if (sp->Exclusions) { for (j = 0; (p = sp->Exclusions[j]) != NULL; j++) if (ListHas(hops, p)) break; if (p != NULL) /* A host in the site's exclusion list was in the Path. */ continue; } /* Write that the site is getting it, and flag to send it. */ if (fprintf(Log, " %s", sp->Name) == EOF || ferror(Log)) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -