/* Copyright (c) 1996-97, Ruslan R. Laishev (@RRL) */ #include "nntp.h" int nntp_feed_group ( WorkerContext *, FeedRec *, char *, int, char *, int ); int feed_bymail ( WorkerContext *, int, char * ); char IHAVE[] = "IHAVE %.*s\r\n"; char POST[] = "POST\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_feed ( WorkerContext *Wctxp, char *GrpList, char *IP, int PostingType, char *ExcList ) { GrpKey gkey; FeedRec frec; int flag = 0; int rc; unsigned long lmsg; char lGrpList [ 1024 ]; char lExcList [ 1024 ]; int sz; char MODE_READER[] = "MODE READER\r\n"; char QUIT[] = "QUIT\r\n"; strcpy (lGrpList,GrpList); strcpy (lExcList,ExcList); if ( 0 >= nntp_cmd_get (Wctxp->chan,Wctxp->bufp,BUFPSZ) ) return -1; /* * For type of posting 'POST' send MODE READER */ if ( PostingType ) { if ( 0 > send(Wctxp->chan,MODE_READER,sizeof (MODE_READER)-1,0) ) return -1; if ( 0 >= nntp_cmd_get (Wctxp->chan,Wctxp->bufp,BUFPSZ) ) return -1; } /* * Get first group with Posting allowed and matched in list */ while ( GrpDBget_seq (&Wctxp->Grprab,&gkey,flag++) ) { /* NNTP_LOGT(Wctxp,LOGD,"Check group '%.*s'.", GrpName$_len,gkey.GrpName); */ gkey.GrpName[GrpName$_len] = 0; if ( ('n' == gkey.PostFlag) || (!strmatch (lGrpList,gkey.GrpName)) || (gkey.Last == 0) ) { /* NNTP_LOGT(Wctxp,LOGD,"Skip group '%.*s'.", GrpName$_len,gkey.GrpName); */ continue; } /* * Get info in Feed database about last feeded message */ lmsg = gkey.First; NNTP_LOGT(Wctxp,LOGW,"'%.*s' first ARTICLE #%u.", GrpName$_len,gkey.GrpName,lmsg); sprintf(frec.Host_Grp,"%s,%.*s",IP,GrpName$_len,gkey.GrpName); if ( FeedDBget(&Wctxp->Feedrab,&frec) ) { NNTP_LOGT(Wctxp,LOGW,"'%.*s' last feeded ARTICLE #%u.", GrpName$_len,gkey.GrpName,frec.Last); if ( gkey.Last == frec.Last ) continue; lmsg = max (lmsg,frec.Last); lmsg = min (lmsg,gkey.Last); } /* * Start FeedUp for one group */ if ( !nntp_feed_group ( Wctxp,&frec,gkey.GrpName,lmsg,lExcList,PostingType) ) continue; /* * Update Feed record in FeedDB */ NNTP_LOGT(Wctxp,LOGW,"Update FeedDB for %.*s,last ARTICLE #%u", Feed$_len,frec.Host_Grp,frec.Last); if ( !FeedDBput(&Wctxp->Feedrab,&frec) ) NNTP_LOGT(Wctxp,LOGE,"Update FeedDB."); } send(Wctxp->chan,QUIT,sizeof (QUIT)-1,0); NNTP_LOGT(Wctxp,LOGW,"All Group is Feeded."); return 0; } /* *-------------------------------------------------------------------------------- */ int nntp_feed_group ( WorkerContext *Wctxp, FeedRec *frec, char *fGrp, int lmsg, char *ExcList, int PostingType ) { int nntp_feed_exclude (char *,char *,int); unsigned long rc,rc0,cmsg; int sz,szA,szM; char *cp0,*cp1; char lfGrp [ GrpName$_len + 1 ]; MsgKey *mkeyp = (MsgKey*) Wctxp->MsgBuff; char FieldPath [ ] = {"Path:"}; int Posted,Rejected,Skiped; int feed_bymail_f = 0; Posted = Rejected = Skiped = 0; strncpy (lfGrp,fGrp,GrpName$_len); NNTP_LOGT(Wctxp,LOGW,"Start upload '%.*s' at ARTICLE #%u.", GrpName$_len,lfGrp,lmsg+1); if ( *nntp_conf.GrpMod && strmatch (nntp_conf.GrpMod,lfGrp) ) feed_bymail_f = 1; while (1) { frec->Last = lmsg; lmsg++; /* * Get ARTICLE # in the buffer */ if ( !(szM = MsgDBget_byNum(&Wctxp->Msgrab,lfGrp, lmsg,Wctxp->MsgBuff,MSGBUFFSZ)) ) { NNTP_LOGT(Wctxp,LOGW,"'%s' ARTICLE #%u-Not Retrived.", lfGrp,lmsg); break; } Wctxp->MsgBuff[sizeof(MsgKey)+szM] = 0; NNTP_LOGT(Wctxp,LOGD,"ARTICLE #%u %.*s (%d bytes)-Retrived.", lmsg,MsgId$_len,mkeyp->MsgId,szM); /* * Extract 'Path:'-field for exclude list */ if ( NULL == (cp0 = strstr(&Wctxp->MsgBuff[sizeof(MsgKey)],FieldPath)) ) break; cp0 += (sizeof(FieldPath)-1); cp1 = strpbrk(cp0,"\r\t"); strncpy(Wctxp->bufp,cp0,cp1-cp0); Wctxp->bufp[cp1-cp0] = 0; strlwr (Wctxp->bufp); /* * Check for presence in exclude list */ if ( nntp_feed_exclude (Wctxp->bufp,ExcList,strlen(ExcList)) ) { NNTP_LOGT(Wctxp,LOGD,"ARTICLE #%u %.*s-Skipped.", lmsg,MsgId$_len,mkeyp->MsgId); Skiped++; continue; } /* * */ if ( feed_bymail_f ) { if ( !(rc0 = feed_bymail(Wctxp,sz,lfGrp)) ) {Posted++;continue;} if ( rc0 < 0 ) {Rejected++;continue;} } /* * */ if ( PostingType ) {sz = sprintf(Wctxp->bufp,POST);} else {sz = sprintf(Wctxp->bufp,IHAVE,MsgId$_len,mkeyp->MsgId);} NNTP_LOGT(Wctxp,LOGD,"Send '%.*s'.",sz,Wctxp->bufp); if ( 0 > send (Wctxp->chan,Wctxp->bufp,sz,0) ) break; /* * Get response from feeder */ if ( 0 >= (sz = nntp_cmd_get(Wctxp->chan,Wctxp->bufp,BUFPSZ)) ) break; if ( PostingType ) NNTP_LOGT(Wctxp,LOGW,"Response to 'POST' from Feeder '%.*s'.", sz,Wctxp->bufp); else NNTP_LOGT(Wctxp,LOGW,"Response to 'IHAVE' from Feeder '%.*s'.", sz,Wctxp->bufp); /* * Get status code & dispatch */ if (1 != sscanf(Wctxp->bufp,"%u",&rc) ) break; if ( (rc == 435) || (rc == 441) ) { Rejected++; continue; } if ( rc >= 400 ) break; /* * 335 or 340 - 'Ok' Send article to feeder host */ NNTP_LOGT(Wctxp,LOGD,"Send ARTICLE #%u %.*s.", lmsg,MsgId$_len,mkeyp->MsgId); if ( 0 >= send(Wctxp->chan,&Wctxp->MsgBuff[sizeof(MsgKey)],szM,0) ) { NNTP_LOGT(Wctxp,LOGE,"Send ARTICLE #%u %.*s.", lmsg,MsgId$_len,mkeyp->MsgId); break; } if ( 0 >= (sz = nntp_cmd_get(Wctxp->chan,Wctxp->bufp,BUFPSZ)) ) break; NNTP_LOGT(Wctxp,LOGW,"Status after sending ARTICLE to Feed '%.*s'.", sz,Wctxp->bufp); /* * Get status code & check it */ if (1 != sscanf(Wctxp->bufp,"%u",&rc) ) break; if ( (rc == 235) || (rc == 240) ) { NNTP_LOGT(Wctxp,LOGW,"Send ARTICLE #%u %.*s.", lmsg,MsgId$_len,mkeyp->MsgId); Posted++; continue; } NNTP_LOGT(Wctxp,LOGE,"Send ARTICLE #%u %.*s.", lmsg,MsgId$_len,mkeyp->MsgId); } NNTP_LOGT(Wctxp,LOGW,"'%.*s' statistic:Posted %u,Rejected %u,Skiped %u.", GrpName$_len,lfGrp,Posted,Rejected,Skiped); return ( Posted + Rejected + Skiped); } /* *-------------------------------------------------------------------------------- */ int nntp_feed_exclude ( char *sList, char *eList, int eListsz ) { char buf [ 128 ]; int i; for (i = 0;strelem(buf,eList,eListsz,",",i); i++) { if ( strstr(sList,buf) ) return 1; } return 0; } /* *-------------------------------------------------------------------------------- * * * Wctxp->MsgBuff = ARTICLE for inserting to message database * * * return: 0 - Ok, message is posted by E-mail to moderator * 1 - Ok, "Approved:" field is present, * message can by insert to DB * -1 - Error, message is not valide - must be ignored */ int feed_bymail (WorkerContext *Wctxp,int sz,char *Grp) { char FieldPath [ ] = {"Path:"}; char FieldAppr [ ] = {"Approved:"}; char FieldReplyTo [ ] = {"Reply-To:"}; char FieldFrom [ ] = {"From:"}; char FieldSubj [ ] = {"Subject:"}; char *msgp = &Wctxp->MsgBuff[sizeof(MsgKey)]; char *bufp = &Wctxp->bufp; char bufpg [ GrpName$_len + 1 ]; char bufp0 [ 1024 ]; char *cp0,*cp1; char *from, *to, *subj, *body = msgp; int fromsz, tosz, subjsz, bodysz = sz; int i,l,len; long status; strncpy (bufpg,Grp,GrpName$_len); bufpg[GrpName$_len] = 0; /* * Search HEADER/BODY separator of # ARTICLE */ if ( !(cp0 = strstr(msgp,"\r\n\r\n")) ) { NNTP_LOGT(Wctxp,LOGE,"Article %.*s-Can't find HEADER/BODY.", MsgId$_len,Wctxp->MsgBuff); return -1; } /* * Check "Approved:" by moderator or "GateWay" */ if ( cp1 = strstr(msgp,FieldAppr) ) { cp0 = strpbrk(cp1,"\r\t"); NNTP_LOGT(Wctxp,LOGW,"Article-Haved '%.*s'.",cp0-cp1,cp1); if ( (cp0 - sizeof(FieldAppr)) > cp1 ) return 1; } /* * Extract "Subject:" field */ subj = strstr(msgp,FieldSubj)+sizeof(FieldSubj); subjsz = strpbrk(subj,"\r\t") - subj; l = strlen(nntp_conf.Moderator); for (i=0; len=strelem(bufp,nntp_conf.Moderator,l,"|",i); i++) { if ( !strelem (bufp0,bufp,len,":",0) ) continue; if ( strmatch (bufp0,bufpg) ) { strelem (bufp0,bufp,len,":",1); cp0 = bufpg; while ( *(cp0++) ) if ( *(cp0) == '.' ) *cp0 = '-'; tosz = sprintf(bufp,bufp0,bufpg); tosz = sprintf(bufp0,"%s%\"%s\"",nntp_conf.LocalSMTP,bufp); if ( from = strstr(msgp,FieldReplyTo) ) { from +=sizeof(FieldReplyTo); fromsz = strpbrk(from,"\r\t") - from; } else { from = strstr(msgp,FieldFrom)+sizeof(FieldFrom); fromsz = strpbrk(from,"\r\t") - from; if ( cp0 = strchr (from,'<' ) ) { from = cp0+1; cp0 = strchr(from,'>'); fromsz = cp0 - from; } } NNTP_LOGT(Wctxp,LOGI,"feed_bymail:(From:%.*s,To:%.*s,Subj:%.*s,%d bytes).", fromsz,from,tosz,bufp0,subjsz,subj,bodysz); if ( send_mail (bufp0,tosz,subj,subjsz,body,bodysz,from,fromsz) ) return -1; NNTP_LOGT(Wctxp,LOGI,"feed_bymail:(From:%.*s,To:%.*s,Subj:%.*s,%d bytes).", fromsz,from,tosz,bufp0,subjsz,subj,bodysz); return 0; } } NNTP_LOGT(Wctxp,LOGE,"feed_bymail:Problem with '%s'.",bufpg); return -1; }