/* * distributions.c Copyright 1999 Christopher M Sedore. All Rights Reserved. * Please see the "COPYING" file for license details. * * This code selects articles for feeds, stores, and filtering */ #include "main.h" typedef unsigned int DWORD; extern DWORD MaxCrossposts; struct distinclude { char *name; MATCHHEAD *dist; BOOL matched,poisoned; TAILQ_ENTRY(distinclude) list; }; TAILQ_HEAD(mdist,distinclude) dIncHead; BOOL FreeMatchData(struct article *art) { if (art->ad) { if (art->ad->newsgroups) free(art->ad->newsgroups); if (art->ad->pathline) free(art->ad->pathline); free(art->ad); art->ad=NULL; } return TRUE; } BOOL PrepareForMatch(struct article *art) { char *s,*s1; DWORD l,b; BOOL cont; ARTICLEDATA *ad; art->ad=malloc(sizeof(ARTICLEDATA)); bzero(art->ad,sizeof(ARTICLEDATA)); ad=art->ad; ad->followupCount=0; if (GetHeaderRange(art,"Newsgroups:",&b,&l,&cont)) { s=s1=malloc(l+10); ad->numgroups=0; while (sbuf[b+(s-s1)]<33) { b++; l--; continue; } *s=art->buf[b+(s-s1)]; // putchar(*s); if (*s==',') { *s=0; ad->numgroups++; } s++; } *s=0; s++; *s=0; ad->newsgroups=s1; // putchar('\n'); } else { syslog(LOG_NEWS|LOG_INFO,"no newsgroups in %s\n",art->mid); return FALSE; } if (GetHeaderRange(art,"Path:",&b,&l,&cont)) { s=s1=malloc(l+10); ad->hopcount=0; while (sbuf[b+(s-s1)]<33) { b++; l--; continue; } *s=art->buf[b+(s-s1)]; if (*s=='!') { *s=0; ad->hopcount++; } s++; } *s=0; s++; *s=0; ad->pathline=s1; } else { syslog(LOG_NEWS|LOG_INFO,"no path in %s\n",art->mid); return FALSE; } if (GetHeaderRange(art,"Followup-To:",&b,&l,&cont)) { ad->followupCount++; s=s1=art->buf; while (sfollowupCount++; } s++; } } if (GetHeaderRange(art,"Control:",&b,&l,&cont)) { art->isControl=TRUE; } if (GetHeaderRange(art,"Approved:",&b,&l,&cont)) { art->isApproved=TRUE; } CheckIncludeMatch(art); return TRUE; } BOOL MatchHeader(char *pattern,char *string) { char *s; s=string; while (*s!=0) { if (StringMatch(pattern,s)) return TRUE; while (*s!=0) s++; s++; } return FALSE; } BOOL MatchHeaderSpec(char *pattern,char *headername,struct article *art) { char *s,*s1; DWORD b,l; BOOL cont; s=malloc(8192); if (!GetHeaderFromBuf(art->buf,headername,s,8192,art->len)) { return FALSE; } if (StringMatch(pattern,s)) { free(s); return TRUE; } free(s); return FALSE; } BOOL MatchArticle(struct article *art,MATCHNODE *mnode,BOOL *poison) { BOOL match=FALSE,nDone=FALSE; MATCHNODE *mn; void *hold; DWORD op; char *ng; if (*poison) return FALSE; ng=art->ad->newsgroups; while ((*ng!=0) && (!*poison)) { mn=mnode; nDone=FALSE; while ((mn!=NULL) && (!nDone)) { match=FALSE; op=(mn->operation & 0x0F000000); switch (op) { case OP_HEADERMATCH: { switch (mn->operation & 0xFF) { case OP_GROUP: { match=StringMatch(ng,mn->cpat); // printf("%x mtch %s %s=%i?\n",mn->operation,ng,mn->cpat,match); if (match && (mn->operation & OP_POISON)) { *poison=TRUE; nDone=TRUE; continue; } if (match && (mn->operation & OP_NOT)) { match=FALSE; nDone=TRUE; continue; } if (match && !(mn->operation & OP_NOT)) { match=TRUE; nDone=TRUE; continue; } mn=mn->next; continue; } break; case OP_PATH: { match=MatchHeader(mn->cpat,art->ad->pathline); // printf("%x pmtch %s %s=%i?\n",mn->operation,art->ad->pathline,mn->cpat,match); if (match & (mn->operation & OP_NOT)) { match=TRUE; nDone=TRUE; } else { if (match) { *poison=TRUE; nDone=TRUE; } } mn=mn->next; continue; } break; } } break; case OP_REFDIST: { struct distinclude *d; d=(struct distinclude *)mn->left; // printf("check include %s m=%u p=%u========", // d->name,d->matched,d->poisoned); if (d->poisoned) { // printf("poisoned\n"); *poison=TRUE; nDone=TRUE; continue; } match=d->matched; if (mn->operation & (OP_NOT|OP_POISON)) { if (match) { // printf("poisoned\n"); *poison=TRUE; nDone=TRUE; continue; } } if (!match) { // printf("not matched\n"); mn=mn->next; continue; } // printf("matched\n"); nDone=TRUE; continue; } break; case OP_LOGICALOR: { if ((MatchArticle(art,mn->left,poison)) || (MatchArticle(art,mn->right,poison))) match=TRUE; *poison=FALSE; } break; case OP_LOGICALAND: { if ((MatchArticle(art,mn->left,poison)) && (MatchArticle(art,mn->right,poison))) match=TRUE; *poison=FALSE; } break; case OP_GREATER: { switch (mn->operation & 0xFF) { case OP_HOPCOUNT: { if (art->ad->hopcount>mn->count) match=TRUE; }break; case OP_GROUPCOUNT: { if (art->ad->numgroups>mn->count) match=TRUE; }break; case OP_SIZE: { if (art->len>(DWORD)mn->count) match=TRUE; } break; case OP_TIME: { if (art->artTime>mn->count) match=TRUE; } break; } } break; case OP_LESS: { switch (mn->operation & 0xFF) { case OP_HOPCOUNT: { if (art->ad->hopcountcount) match=TRUE; }break; case OP_GROUPCOUNT: { if (art->ad->numgroupscount) match=TRUE; }break; case OP_SIZE: { if (art->len<(DWORD)mn->count) match=TRUE; // printf("%x sz %u<%u=%i?\n",mn->operation,art->len,mn->count,match); }break; case OP_TIME: { if (art->artTimecount) match=TRUE; } break; } } break; case OP_ISCONTROL: { match=art->isControl; } break; case OP_ISAPPROVED: { match=art->isApproved; } break; case OP_HSPEC: { match=MatchHeaderSpec(mn->cpat,mn->hname,art); } break; } if (mn->operation & OP_NOT) { match=!match; } if (mn->operation & OP_POISON) { if (match) { *poison=TRUE; break; } } mn=mn->next; if (!match) { *poison=TRUE; break; } match=FALSE; } if (match) break; while (*ng!=0) ng++; ng++; } return (match && (!*poison)); } BOOL CheckMatch(struct article *art, MATCHHEAD *mp) { BOOL poison=FALSE; int r=FALSE; if (mp->poisonhead) { r=MatchArticle(art,mp->poisonhead,&poison); } if (!poison) r=MatchArticle(art,mp->head,&poison); // printf(">>>>>>>>>>match=%u<<<<<<<<<<<<<<\n",r); return r; } struct distinclude * FindInclude(char *name) { struct distinclude *d; for (d=TAILQ_FIRST(&dIncHead);d;d=TAILQ_NEXT(d,list)) { if (!strcasecmp(d->name,name)) { return d; } } return NULL; } BOOL AddInclude(char *name,char *diststr) { struct distinclude *d; d=malloc(sizeof(struct distinclude)); bzero(d,sizeof(struct distinclude)); d->name=strdup(name); if (diststr) d->dist=CompileMatchString(diststr); TAILQ_INSERT_TAIL(&dIncHead,d,list); return 1; } BOOL CheckIncludeMatch(struct article *art) { BOOL poison=FALSE; int r; struct distinclude *d; MATCHHEAD *mp; for (d=TAILQ_FIRST(&dIncHead);d;d=TAILQ_NEXT(d,list)) { d->poisoned=d->matched=poison=FALSE; mp=d->dist; if (mp->poisonhead) { r=MatchArticle(art,mp->poisonhead,&poison); if (poison) { // printf("inclpoisoned\n"); d->poisoned=TRUE; continue; } } r=MatchArticle(art,mp->head,&poison); if (r) { d->matched=TRUE; } } /* for (d=TAILQ_FIRST(&dIncHead);d;d=TAILQ_NEXT(d,list)) { printf("%s m=%u p=%u\n",d->name,d->matched,d->poisoned); } */ } MATCHNODE * ParseNodeString(char *s) { MATCHNODE *m; char *s1; BOOL intValue=FALSE; m=malloc(sizeof(MATCHNODE)); ZeroMemory(m,sizeof(MATCHNODE)); switch (*s) { case '!' : { m->operation|=OP_NOT; s++; } break; case '~' : { m->operation|=OP_POISON; s++; } break; } switch (*s) { case '|': { m->operation|=OP_LOGICALOR; s1=strtok(NULL,","); if (!s1) { free(m); return NULL; } m->left=ParseNodeString(s1); s1=strtok(NULL,","); if (!s1) { free(m); return NULL; } m->right=ParseNodeString(s1); s++; return m; } break; case '&' : { m->operation|=OP_LOGICALAND; s1=strtok(NULL,","); if (!s1) { free(m); return NULL; } m->left=ParseNodeString(s1); s1=strtok(NULL,","); if (!s1) { free(m); return NULL; } m->right=ParseNodeString(s1); s++; return m; } break; case '+' : { s++; if (m->left=(MATCHNODE *) FindInclude(s)) { m->operation|=OP_REFDIST; return m; } else { printf("included distribution %s not found!\n",s); free(m); return NULL; } } break; } if (*s=='$') { s++; switch (*s) { case 'I': { m->operation|=OP_HOPCOUNT; intValue=TRUE; } break; case 'G': { m->operation|=OP_GROUPCOUNT; intValue=TRUE; } break; case 'S': { m->operation|=OP_SIZE; intValue=TRUE; } break; case 'A': { m->operation|=OP_TIME; intValue=TRUE; } break; case 'P': { m->operation=OP_PATH|OP_HEADERMATCH; } break; /* case 'F': { m->operation|=OP_FOLLOWUPCOUNT; intValue=TRUE; } break; */ case 'V': { s++; m->operation|=OP_ISAPPROVED; return m; } break; case 'H': { char *h; s++; if (*s!='[') { free(m); return NULL; } s++; if (*s!='"') { free(m); return NULL; } s++; h=m->hname=malloc(strlen(s)); while (*s!='"') { *h=*s; s++; h++; } *h=0; s++; if (*s!=']') { free(m); return NULL; } m->operation|=OP_HSPEC; } break; case 'C' : { s++; m->operation|=OP_ISCONTROL; return m; } break; } s++; } else { m->operation|=OP_HEADERMATCH|OP_GROUP; m->cpat=strdup(s); return m; } switch (*s) { case '>' : { m->operation|=OP_GREATER; intValue=TRUE; } break; case '<' : { m->operation|=OP_LESS; intValue=TRUE; } break; case '=' : { if (!(m->operation & OP_HEADERMATCH)) { } } break; default : { if (!(m->operation & OP_HEADERMATCH)) { free(m); return NULL; } } break; } s++; if (intValue) { m->count=atoi(s); } else { m->cpat=strdup(s); } return m; } MATCHHEAD * CompileMatchString(char *feedinfo) { char *s1; MATCHHEAD *a=malloc(sizeof(MATCHHEAD)); MATCHNODE *p,*n=NULL,*np=NULL; char *hold; ZeroMemory(a,sizeof(MATCHHEAD)); hold=strdup(feedinfo); p=a->head=malloc(sizeof(MATCHNODE)); ZeroMemory(p,sizeof(MATCHNODE)); s1=strtok(hold,",\r\n\t"); while (s1!=NULL) { p=ParseNodeString(s1); // printf(">>>>>>>>s1==%s\n",s1); assert(p); s1=strtok(NULL," ,\n"); if ((p) && (p->operation & OP_POISON)) { if (!np) { np=p; a->poisonhead=p; } else { np->next=p; np=p; } } else if (p) { if (!n) { n=p; a->head=p; } else { n->next=p; n=p; } } } p->next=NULL; free(hold); return a; } BOOL DistributionInit() { TAILQ_INIT(&dIncHead); return TRUE; }