/* Copyright (c) 1996, Ruslan R. Laishev (@RRL) */ #include #include "nntp.h" int post_bymail ( WorkerContext *, int, char * ); static NNTP_cmd_t NNTP_cmd[] = { {"help", nntp_help,"Help"}, {"quit", nntp_quit,"Quit"}, {"arti", nntp_arti,"Article [MessageID | Number]"}, {"head", nntp_head,"Head [MessageID | Number]"}, {"body", nntp_body,"Body [MessageID | Number]"}, {"stat", nntp_stat,"Stat [MessageID | Number]"}, {"post", nntp_post,"Post"}, {"ihav", nntp_ihav,"Ihave MessageID"}, {"list", nntp_list,"List"}, {"grou", nntp_grou,"Group newsgroupname"}, {"newg", nntp_newg,"NewGroups date time [GMT] []"}, {"slav", nntp_slav,"Slave"}, {"xove", nntp_xove,"Xover [First - Last]"}, {"last", nntp_last,"Last"}, {"next", nntp_next,"Next"}, {"newn", nntp_newn,"NewNews date time [GMT] []"}, /* "auth", nntp_auth,"Authinfo user pass" */ {NULL, NULL, "UnRecognized"} }; /* *-------------------------------------------------------------------------------- */ void *nntp_cmd_parse (WorkerContext *Wctxp) { NNTP_cmd_t *cmdp; cmdp = &NNTP_cmd[0]; do { if ( !strincmp(cmdp->cmd,Wctxp->bufp,4) ) break; cmdp++; } while (cmdp->cmd != NULL); NNTP_LOGT(Wctxp,LOGD,"NNTP cmd '%s'",Wctxp->bufp); return (void *) cmdp->nntp_fun; } /* *-------------------------------------------------------------------------------- */ char LIST_OF_CMD[] = "100 list of legal commands follows\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_help (WorkerContext *Wctxp) { NNTP_cmd_t *t = &NNTP_cmd[0]; char *cp= &Wctxp->MsgBuff[0]; long status; int sz; send(Wctxp->chan,LIST_OF_CMD,sizeof(LIST_OF_CMD)-1,0); while(t->cmd) { sz = sprintf(cp,"->%s\r\n",t->hlp); cp += sz; t++; } send(Wctxp->chan,Wctxp->MsgBuff,cp-(&Wctxp->MsgBuff[0]),0); return (send(Wctxp->chan,NNTP_EOT,sizeof(NNTP_EOT)-1,0)); } /* *-------------------------------------------------------------------------------- */ char GOODBYE[] = "205 closing connection - goodbye !\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_quit (WorkerContext *Wctxp) { send(Wctxp->chan,GOODBYE,sizeof(GOODBYE)-1,0); return -1; } /* *-------------------------------------------------------------------------------- */ char SLAVE_RESP[] = "202 slave status noted\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_slav (WorkerContext *Wctxp) { return send(Wctxp->chan,SLAVE_RESP,sizeof(SLAVE_RESP)-1,0); } /* *-------------------------------------------------------------------------------- */ char NO_GRP_SEL[] = "412 no newsgroup has been selected\r\n"; char ARTI_FOLLOW[] = "220 %.*s Article text follows\r\n"; char ARTI_N_FOLW[] = "220 %u %.*s article retrived-head follows\r\n"; char HEAD_FOLLOW[] = "221 %.*s Article text follows\r\n"; char HEAD_N_FOLW[] = "221 %u %.*s article retrived-head follows\r\n"; char BODY_FOLLOW[] = "222 %.*s Article text follows\r\n"; char BODY_N_FOLW[] = "222 %u %.*s article retrived-head follows\r\n"; char STAT_FOLLOW[] = "223 %.*s Article retrived-id follows\r\n%.*s\r\n"; char STAT_N_FOLW[] = "223 %u %.*s article retrived-id follows\r\n%.*s\r\n"; char NO_ART_SEL[] = "420 no current article has been slected\r\n"; char NO_SUCH_ARTS[] = "421 no such next article in this group\r\n"; char NO_SUCH_ARTP[] = "422 no such previous article in this group\r\n"; char NO_SUCH_ARTN[] = "423 no such article number in this group\r\n"; char NO_SUCH_ART[] = "430 no such article found\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_arti (WorkerContext *Wctxp) { char *cp0,*cp1; int sz,n,sz0; MsgKey *mkeyp = (MsgKey *) &Wctxp->MsgBuff[0]; if( cp0 = strchr(Wctxp->bufp,'<') ) { /*Get by Message ID */ if ( cp1 = strchr(Wctxp->bufp,'>') ) if ( (cp1 - cp0) > MsgId$_len ) return 0; *(++cp1) = 0; Wctxp->MsgNumf = 0; if ( sz = MsgDBget_byId(&Wctxp->Msgrab,cp0,Wctxp->MsgBuff,MSGBUFFSZ) ) { sz0= sprintf(Wctxp->bufp,ARTI_FOLLOW,MsgId$_len,mkeyp->MsgId); send(Wctxp->chan,Wctxp->bufp,sz0,0); return (send(Wctxp->chan,&Wctxp->MsgBuff[sizeof(MsgKey)],sz,0)); } return (send(Wctxp->chan,NO_SUCH_ART,sizeof(NO_SUCH_ART)-1,0)); } /*Get by Message number */ if ( !Wctxp->Grp[0] ) return send(Wctxp->chan,NO_GRP_SEL,sizeof(NO_GRP_SEL)-1,0); n = Wctxp->MsgNum; if( cp0 = strchr(Wctxp->bufp,' ') ) if ( atoi(cp0) ) n = atoi(cp0); if ( sz = MsgDBget_byNum(&Wctxp->Msgrab,Wctxp->Grp,n,Wctxp->MsgBuff,MSGBUFFSZ) ) { sz0 = sprintf(Wctxp->bufp,ARTI_N_FOLW,n,MsgId$_len,mkeyp->MsgId); Wctxp->MsgNum = n; Wctxp->MsgNumf= 1; send(Wctxp->chan,Wctxp->bufp,sz0,0); return (send(Wctxp->chan,&Wctxp->MsgBuff[sizeof(MsgKey)],sz,0)); } return (send(Wctxp->chan,NO_SUCH_ARTN,sizeof(NO_SUCH_ARTN)-1,0)); } /* *-------------------------------------------------------------------------------- */ int nntp_head (WorkerContext *Wctxp) { char *cp0,*cp1; int sz,n,sz0; MsgKey *mkeyp = (MsgKey *) &Wctxp->MsgBuff[0]; if( cp0 = strchr(Wctxp->bufp,'<') ) { /*Get by Message ID */ if ( cp1 = strchr(Wctxp->bufp,'>') ) if ( (cp1 - cp0) > MsgId$_len ) return 0; *(++cp1) = 0; Wctxp->MsgNumf= 0; if ( sz = MsgDBget_byId(&Wctxp->Msgrab,cp0,Wctxp->MsgBuff,MSGBUFFSZ) ) { sz0 = sprintf(Wctxp->bufp,HEAD_FOLLOW,MsgId$_len,mkeyp->MsgId); send(Wctxp->chan,Wctxp->bufp,sz0,0); cp0 = &Wctxp->MsgBuff[sizeof(MsgKey)]; sz = strstr(cp0,"\r\n\r\n") - cp0; sz += 2; send(Wctxp->chan,cp0,sz,0); return (send(Wctxp->chan,NNTP_EOT,sizeof(NNTP_EOT)-1,0)); } return (send(Wctxp->chan,NO_SUCH_ART,sizeof(NO_SUCH_ART)-1,0)); } /*Get by Message number */ if ( !Wctxp->Grp[0] ) return (send(Wctxp->chan,NO_GRP_SEL,sizeof(NO_GRP_SEL)-1,0)); n = Wctxp->MsgNum; if( cp0 = strchr(Wctxp->bufp,' ') ) if ( atoi(cp0) ) n = atoi(cp0); if ( sz = MsgDBget_byNum(&Wctxp->Msgrab,Wctxp->Grp,n,Wctxp->MsgBuff,MSGBUFFSZ) ) { sz0 = sprintf(Wctxp->bufp,HEAD_N_FOLW,n,MsgId$_len,mkeyp->MsgId); send(Wctxp->chan,Wctxp->bufp,sz0,0); cp0 = &Wctxp->MsgBuff[sizeof(MsgKey)]; sz = strstr(cp0,"\r\n\r\n") - cp0; sz += 2; send(Wctxp->chan,cp0,sz,0); Wctxp->MsgNum = n; Wctxp->MsgNumf= 1; return (send(Wctxp->chan,NNTP_EOT,sizeof(NNTP_EOT)-1,0)); } return (send(Wctxp->chan,NO_SUCH_ARTN,sizeof(NO_SUCH_ARTN)-1,0)); } /* *-------------------------------------------------------------------------------- */ int nntp_body (WorkerContext *Wctxp) { char *cp0,*cp1; int sz,n,sz0; MsgKey *mkeyp = (MsgKey *) &Wctxp->MsgBuff[0]; if( cp0 = strchr(Wctxp->bufp,'<') ) { /*Get by Message ID */ if ( cp1 = strchr(Wctxp->bufp,'>') ) if ( (cp1 - cp0) > MsgId$_len ) return 0; *(++cp1) = 0; Wctxp->MsgNumf= 0; if ( sz = MsgDBget_byId(&Wctxp->Msgrab,cp0,Wctxp->MsgBuff,MSGBUFFSZ) ) { sz0 = sprintf(Wctxp->bufp,BODY_FOLLOW,MsgId$_len,mkeyp->MsgId); send(Wctxp->chan,Wctxp->bufp,sz0,0); cp0 = &Wctxp->MsgBuff[sizeof(MsgKey)]; cp0 = 4+strstr(cp0,"\r\n\r\n"); sz -= (cp0-&Wctxp->MsgBuff[sizeof(MsgKey)]); return (send(Wctxp->chan,cp0,sz,0)); } return (send(Wctxp->chan,NO_SUCH_ART,sizeof(NO_SUCH_ART)-1,0)); } /*Get by Message number */ if ( !Wctxp->Grp[0] ) return (send(Wctxp->chan,NO_GRP_SEL,sizeof(NO_GRP_SEL)-1,0)); n = Wctxp->MsgNum; if( cp0 = strchr(Wctxp->bufp,' ') ) if ( atoi(cp0) ) n = atoi(cp0); if ( sz = MsgDBget_byNum(&Wctxp->Msgrab,Wctxp->Grp,n,Wctxp->MsgBuff,MSGBUFFSZ) ) { sz0 = sprintf(Wctxp->bufp,BODY_N_FOLW,n,MsgId$_len,mkeyp->MsgId); send(Wctxp->chan,Wctxp->bufp,sz0,0); cp0 = &Wctxp->MsgBuff[sizeof(MsgKey)]; cp0 = 4+strstr(cp0,"\r\n\r\n"); sz -= (cp0-&Wctxp->MsgBuff[sizeof(MsgKey)]); Wctxp->MsgNumf= 1; Wctxp->MsgNum = n; return (send(Wctxp->chan,cp0,sz,0)); } return (send(Wctxp->chan,NO_SUCH_ARTN,sizeof(NO_SUCH_ARTN)-1,0)); } /* *-------------------------------------------------------------------------------- */ int nntp_stat (WorkerContext *Wctxp) { char *cp0,*cp1; int sz,n; MsgKey *mkeyp = (MsgKey *) &Wctxp->MsgBuff[0]; if( cp0 = strchr(Wctxp->bufp,'<') ) { /*Get by Message ID */ if ( cp1 = strchr(Wctxp->bufp,'>') ) if ( (cp1 - cp0) > MsgId$_len ) return 0; *(++cp1) = 0; Wctxp->MsgNumf= 0; if ( MsgDBget_byId(&Wctxp->Msgrab,cp0,Wctxp->MsgBuff,MSGBUFFSZ) ) { sz = sprintf(Wctxp->bufp,STAT_FOLLOW, MsgId$_len,mkeyp->MsgId, MsgId$_len,mkeyp->MsgId); return send(Wctxp->chan,Wctxp->bufp,sz,0); } return (send(Wctxp->chan,NO_SUCH_ART,sizeof(NO_SUCH_ART)-1,0)); } /*Get by Message number */ if ( !Wctxp->Grp[0] ) return (send(Wctxp->chan,NO_GRP_SEL,sizeof(NO_GRP_SEL)-1,0)); n = Wctxp->MsgNum; if( cp0 = strchr(Wctxp->bufp,' ') ) if ( atoi(cp0) ) n = atoi(cp0); if ( MsgDBget_byNum(&Wctxp->Msgrab,Wctxp->Grp,n,Wctxp->MsgBuff,MSGBUFFSZ) ) { sz = sprintf(Wctxp->bufp,STAT_N_FOLW, n, MsgId$_len,mkeyp->MsgId, MsgId$_len,mkeyp->MsgId); Wctxp->MsgNumf= 1; Wctxp->MsgNum = n; return (send(Wctxp->chan,Wctxp->bufp,sz,0)); } return (send(Wctxp->chan,NO_SUCH_ARTN,sizeof(NO_SUCH_ARTN)-1,0)); } /* *-------------------------------------------------------------------------------- */ char SEND_TO_POST[] = "340 send article to be posted.End-.\r\n"; char NO_VALD_SIZE[] = "441 length article not valid\r\n"; char POST_FAIL[] = "442 posting failed\r\n"; char POST_OK[] = "240 article posting ok\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_post (WorkerContext *Wctxp) { int sz; send(Wctxp->chan,SEND_TO_POST,sizeof(SEND_TO_POST)-1,0); sz = nntp_txt_get (Wctxp->chan,&Wctxp->MsgBuff[sizeof(MsgKey)],MSGBUFFSZ); if (sz <= 0) return (send(Wctxp->chan,NO_VALD_SIZE,sizeof(NO_VALD_SIZE)-1,0)); if ( !msg_to_db (Wctxp,sz) ) return (send(Wctxp->chan,POST_OK,sizeof(POST_OK)-1,0)); return (send(Wctxp->chan,POST_FAIL,sizeof(POST_FAIL)-1,0)); } /* *-------------------------------------------------------------------------------- */ char FieldFrom [ ] = {"From:"}; char FieldDate [ ] = {"Date:"}; char FieldNewsg [ ] = {"Newsgroups:"}; char FieldSubj [ ] = {"Subject:"}; char FieldMID [ ] = {"Message-ID:"}; char FieldPath [ ] = {"Path:"}; char FieldAppr [ ] = {"Approved:"}; /* *-------------------------------------------------------------------------------- * * * Wctxp->MsgBuff = ARTICLE for inserting to message database * */ int msg_to_db (WorkerContext *Wctxp,int sz) { int msg_hdr_valid (WorkerContext *,int); MsgKey *mkeyp = (MsgKey *) &Wctxp->MsgBuff[0]; char *msgp = (char *) &Wctxp->MsgBuff[sizeof(MsgKey)]; char *cp0,*cp1; char *buf [ GrpName$_len + 1 ]; int len,n,rc; time_t t,told; NNTP_LOGT(Wctxp,LOGD,"msg_to_db:Article size %d.",sz); /* * Check mandatory fields in message and add "Path: " */ if ( 0 > (sz = msg_hdr_valid (Wctxp,sz)) ) { NNTP_LOGT(Wctxp,LOGE,"msg_to_db:Article header is not valid.\n"); return -1; } NNTP_LOGT(Wctxp,LOGD,"msg_to_db:Article size after validation %d.",sz); /* * Check for too old messages */ if ( NULL == (cp0 = strstr(msgp,FieldDate)) ) return -1; cp0 += sizeof(FieldDate); cp1 = strpbrk(cp0,"\r\t"); memcpy(Wctxp->bufp,cp0,cp1-cp0); Wctxp->bufp[cp1-cp0] = 0; t = cvt_rfc_to_vms (Wctxp->bufp); time(&told); told = told - (24*60*60*nntp_conf.MsgOld); if ( t < told) { NNTP_LOGT(Wctxp,LOGW,"msg_to_db:Article is too old (%s).", Wctxp->bufp); return -1; } /* * Extract Message-ID field */ memset(mkeyp,0,sizeof(MsgKey)); if ( NULL == (cp0 = strstr(msgp,FieldMID)) ) return -1; cp0 += sizeof(FieldMID); cp1 = strpbrk(cp0,"\r\t"); if ( (cp1-cp0) > MsgId$_len ) { NNTP_LOGT(Wctxp,LOGE,"msg_to_db:Message-ID (%.*s)=%d > %d.\n", cp1-cp0,cp0,cp1-cp0,MsgId$_len); return -1; } strncpy(mkeyp->MsgId,cp0,cp1-cp0); /* * Date of message (in local database) - data of arriving */ time(&mkeyp->Date); /* * Extract "NewsGroups:" field */ if ( NULL == (cp0 = strstr(msgp,FieldNewsg)) ) return -1; cp0 += sizeof(FieldNewsg); cp1 = strpbrk(cp0,"\r\t"); if ( (cp1-cp0) > BUFPSZ ) { NNTP_LOGT(Wctxp,LOGE,"Length of newsgroups (%.*s) is too big (%d > %d).\n", cp1-cp0,cp0,cp1-cp0,BUFPSZ); return -1; } strncpy(Wctxp->bufp,cp0,cp1-cp0); Wctxp->bufp[cp1-cp0] = 0; /* Field MsgKey.Date,MsgKey.Id is filled */ Wctxp->MsgNumf = 0; /* cp0 point to newsgroups list ("vmsnet.test , vmsnet.admin") */ for (n = 0; len = strelem (buf,Wctxp->bufp,cp1-cp0," ,",n); n++) { if ( len > GrpName$_len ) continue; if ( *nntp_conf.GrpMod ) { if ( strmatch (nntp_conf.GrpMod,buf) ) { if ( 0 > (rc = post_bymail (Wctxp,sz,buf)) ) return -1; if ( !rc ) continue; } } if ( !strmatch (nntp_conf.GrpME,buf) ) continue; if ( DBins (&Wctxp->Grprab,&Wctxp->Msgrab,buf,mkeyp->Date, Wctxp->MsgBuff,sz) ) { NNTP_LOGT(Wctxp,LOGE,"Insert to DB:%.*s,'%.*s'", MsgId$_len,mkeyp->MsgId,len,buf); } else { NNTP_LOGT(Wctxp,LOGW,"Inserted to DB:%.*s,'%.*s'", MsgId$_len,mkeyp->MsgId,len,buf); } } return 0; } /* *-------------------------------------------------------------------------------- */ int msg_hdr_valid (WorkerContext *Wctxp,int sz) { char *msgp = (char *) &Wctxp->MsgBuff[sizeof(MsgKey)]; char *cp0,*cp1; char buf [ 256 ]; time_t t; int sz0; if ( NULL == strstr (msgp,FieldFrom) ) return -1; if ( NULL == strstr (msgp,FieldSubj) ) return -1; if ( NULL == strstr (msgp,FieldMID) ) return -1; if ( NULL == strstr (msgp,FieldNewsg) ) return -1; /* Check and validate Date field */ if ( NULL == (cp0 = strstr(msgp,FieldDate)) ) { time(&t); sz0 = sprintf(buf,"Date: %s\r\n",cvt_vms_to_rfc(t,&buf[128], nntp_conf.LocalTZ)); if ( (sz0+sz) > MSGMAXSZ ) return -1; memmove(msgp+sz0,msgp,sz); memcpy (msgp,buf,sz0); sz += sz0; } /* Check and validate Path field */ if ( NULL == (cp0 = strstr(msgp,FieldPath)) ) { sz0 = sprintf(buf,"X-NNTP-Srv: %s\r\nPath: %s\r\n", ID$IDsrv,nntp_conf.LocalPath); if ( (sz0+sz) > MSGMAXSZ ) return -1; memmove(msgp+sz0,msgp,sz); memcpy (msgp,buf,sz0); return (sz+sz0); } cp0 += sizeof(FieldPath); sz0 = sprintf(buf,"%s!",nntp_conf.LocalPath); /*@RRL */ if ( (sz0+sz) > MSGMAXSZ ) return -1; memmove(cp0+sz0,cp0,sz-(cp0-msgp)); memcpy (cp0,buf,sz0); return (sz+sz0); } /* *-------------------------------------------------------------------------------- */ char LIST_GRP[] = "215 list of newsgroups follows\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_list (WorkerContext *Wctxp) { char *cp = &Wctxp->MsgBuff[0]; int flag = 0; int sz0 = 0,sz1 = 0; GrpKey *gk = (GrpKey *) &Wctxp->bufp[0]; if ( 1 != sscanf(Wctxp->bufp,"%s %s",cp,cp) ) { sz0 = sprintf(Wctxp->bufp,"500 UnRecognized command\r\n"); return (send(Wctxp->chan,Wctxp->bufp,sz0,0)); } send(Wctxp->chan,LIST_GRP,sizeof(LIST_GRP)-1,0); while( GrpDBget_seq(&Wctxp->Grprab,(char *) gk,flag++) ) { sz0 = sprintf(cp,"%.*s %d %d %c\r\n", GrpName$_len, gk->GrpName, gk->Last, gk->First, gk->PostFlag); cp += sz0; sz1 += sz0; if ( sz1 > (MSGBUFFSZ - 256) ) { send(Wctxp->chan,Wctxp->MsgBuff,sz1,0); cp = &Wctxp->MsgBuff[0]; sz0 = sz1 = 0; } } send(Wctxp->chan,Wctxp->MsgBuff,sz1,0); return (send(Wctxp->chan,NNTP_EOT,sizeof(NNTP_EOT)-1,0)); } /* *-------------------------------------------------------------------------------- */ char ALRDY_SEEN[] = "435 Already seen that one,where you been\r\n"; char NEWS_TO_ME[] = "335 News to me!End-..\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_ihav (WorkerContext *Wctxp) { int sz; char *cp0,*cp1; if ( NULL == (cp0 = strchr(Wctxp->bufp,'<')) ) return 0; if ( NULL == (cp1 = strchr(cp0,'>')) ) return 0; if ( (cp1 - cp0) > MsgId$_len ) return 0; *(++cp1) = 0; Wctxp->MsgNumf= 0; if (!MsgDBfind_byId(&Wctxp->Msgrab,cp0,cp1-cp0) ) return (send(Wctxp->chan,ALRDY_SEEN,sizeof(ALRDY_SEEN)-1,0)); send(Wctxp->chan,NEWS_TO_ME,sizeof(NEWS_TO_ME)-1,0); if ( 0 > (sz = nntp_txt_get (Wctxp->chan,&Wctxp->MsgBuff[sizeof(MsgKey)],MSGMAXSZ)) ) return (send(Wctxp->chan,NO_VALD_SIZE,sizeof(NO_VALD_SIZE)-1,0)); if ( !msg_to_db (Wctxp,sz) ) return (send(Wctxp->chan,POST_OK,sizeof(POST_OK)-1,0)); return (send(Wctxp->chan,POST_FAIL,sizeof(POST_FAIL)-1,0)); } /* *-------------------------------------------------------------------------------- */ char NO_SUCH_GRP[] = "411 no such news group\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_grou (WorkerContext *Wctxp) { char *cp = &Wctxp->bufp[0]; int sz = 0; GrpKey *gk = (GrpKey *) &Wctxp->MsgBuff[0]; if ( 2 == (sscanf (cp,"%s %s",cp,cp)) ) { NNTP_LOGT(Wctxp,LOGD,"Get group info:%.*s", GrpName$_len,cp); if ( GrpDBget (&Wctxp->Grprab,cp, (char *) gk,0) ) { sz = sprintf(cp,"211 0%d 0%d 0%d %.*s group selected\r\n", (gk->Last-gk->First)+1, gk->First, gk->Last, GrpName$_len, gk->GrpName); strncpy(Wctxp->Grp,gk->GrpName,GrpName$_len); Wctxp->MsgNum = gk->First; Wctxp->MsgNumf= 0; } else { NNTP_LOGT(Wctxp,LOGE,"Get group info:%.*s", GrpName$_len,cp); sz = sprintf(cp,NO_SUCH_GRP); } } else sz = sprintf(cp,NO_SUCH_GRP); return (send(Wctxp->chan,cp,sz,0)); } /* *-------------------------------------------------------------------------------- */ char NEW_GRP[] = "231 list of newsgroups since %s follows\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_newg (WorkerContext *Wctxp) { char *cp = &Wctxp->bufp[0]; char *cp0= &Wctxp->MsgBuff[0]; int sz0,sz1,flag = 0; time_t t; GrpKey *gkeyp = (GrpKey *) &Wctxp->bufp[0]; if ( cp = strchr (cp,' ') ) { if ( t = cvt_nntp_to_vms(cp) ) { sz0 = sprintf(cp0,NEW_GRP,cp); send(Wctxp->chan,cp0,sz0,0); cp = &Wctxp->MsgBuff[0]; sz0 = sz1 = 0; while(GrpDBget_seq(&Wctxp->Grprab,(char *) gkeyp,flag++) ) { if (t > gkeyp->DateCr) continue; sz0 = sprintf(cp,"%.*s %d %d %c\r\n", GrpName$_len, gkeyp->GrpName, gkeyp->Last, gkeyp->First, gkeyp->PostFlag); cp += sz0; sz1 += sz0; if ( sz1 > (MSGBUFFSZ - 256) ) { send(Wctxp->chan,Wctxp->MsgBuff,sz1,0); cp = &Wctxp->MsgBuff[0]; sz0 = sz1 = 0; } } }; } send(Wctxp->chan,Wctxp->MsgBuff,sz1,0); return (send(Wctxp->chan,NNTP_EOT,sizeof(NNTP_EOT)-1,0)); } /* *-------------------------------------------------------------------------------- */ char DATA_FOLLOWS[] = "224 data follows\r\n"; char XOVER_DATA[] = "%s\t%.*s\t%.*s\t%s\t%.*\r\n"; /* *-------------------------------------------------------------------------------- */ /* Extract the headers, remove tab and nl's, the headers we want are: artid|subject|From|Date|Message-Id */ /* *-------------------------------------------------------------------------------- */ int nntp_xove (WorkerContext *Wctxp) { char *cp0,*cp1,*cp2; unsigned sz,from = 0,to = 0,i; MsgKey *mkeyp = (MsgKey *) &Wctxp->MsgBuff[0]; GrpKey *gkeyp = (GrpKey *) &Wctxp->MsgBuff[0]; char lkey [MsgGrp$_len]; char buf [ 128 ]; NNTP_LOGT(Wctxp,LOGD,"Get group info:'%.*s",GrpName$_len,Wctxp->Grp); if ( 0 > GrpDBget(&Wctxp->Grprab,Wctxp->Grp,(char *) gkeyp,0) ) { NNTP_LOGT(Wctxp,LOGD,"Get group info:%.*s",GrpName$_len,Wctxp->Grp); return (send(Wctxp->chan,NO_GRP_SEL,sizeof(NO_GRP_SEL)-1,0)); } from = to = gkeyp->First; if ( cp0 = strchr(&Wctxp->bufp[0],' ') ) { cp0++; from = atoi(cp0); if ( cp0 = strchr(cp0,'-') ) { cp0++; to = atoi(cp0); } } from = max (from,gkeyp->First); to = min (to ,gkeyp->Last); send(Wctxp->chan,DATA_FOLLOWS,sizeof(DATA_FOLLOWS)-1,0); lkey[0] = 0; NNTP_LOGT(Wctxp,LOGD,"From:%d, To:%d",Wctxp->indx,Wctxp->chan,from,to); for (i = from; i <= to; i++) { if (0 > (sz = MsgDBget_byNum(&Wctxp->Msgrab,Wctxp->Grp,i, Wctxp->MsgBuff, MSGBUFFSZ)) ) break; if ( !sz ) continue; Wctxp->MsgBuff[sz+sizeof(MsgKey)] = 0; /*Article Number */ sz = sprintf(Wctxp->bufp,"%lu\t",i); /*Article 'Subj' Field */ cp2 = strtok_val (&Wctxp->MsgBuff[sizeof(MsgKey)],buf,FieldSubj,"\r\t",64); sz += sprintf(&Wctxp->bufp[sz],"%s\t",cp2?cp2:" "); /*Article 'From' Field */ cp2 = strtok_val (&Wctxp->MsgBuff[sizeof(MsgKey)],buf,FieldFrom,"\r\t",64); sz += sprintf(&Wctxp->bufp[sz],"%s\t",cp2?cp2:" "); /*Article 'Date' Field */ cp2 = strtok_val (&Wctxp->MsgBuff[sizeof(MsgKey)],buf,FieldDate,"\r\t",64); sz += sprintf(&Wctxp->bufp[sz],"%s\t",cp2?cp2:" "); /*Article 'Msg-ID' Field */ sz += sprintf(&Wctxp->bufp[sz],"%.*s\t\t\t\t\r\n",MsgId$_len,mkeyp->MsgId); send(Wctxp->chan,Wctxp->bufp,sz,0); } return (send(Wctxp->chan,NNTP_EOT,sizeof(NNTP_EOT)-1,0)); } /* *-------------------------------------------------------------------------------- */ int nntp_last (WorkerContext *Wctxp) { int n,sz; MsgKey *mkeyp = (MsgKey *) &Wctxp->MsgBuff[0]; if ( !Wctxp->Grp[0] ) return (send(Wctxp->chan,NO_GRP_SEL,sizeof(NO_GRP_SEL)-1,0)); if ( !Wctxp->MsgNum ) return (send(Wctxp->chan,NO_ART_SEL,sizeof(NO_ART_SEL)-1,0)); n = Wctxp->MsgNum; n--; Wctxp->MsgNumf= 0; if ( MsgDBget_byNum(&Wctxp->Msgrab,Wctxp->Grp,n,Wctxp->MsgBuff,MSGBUFFSZ) ) { Wctxp->MsgNum = n; sz = sprintf(Wctxp->bufp,STAT_N_FOLW, n, MsgId$_len,mkeyp->MsgId, MsgId$_len,mkeyp->MsgId); return (send(Wctxp->chan,Wctxp->bufp,sz,0)); } return (send(Wctxp->chan,NO_SUCH_ARTP,sizeof(NO_SUCH_ARTP)-1,0)); } /* *-------------------------------------------------------------------------------- */ int nntp_next (WorkerContext *Wctxp) { int n,sz; MsgKey *mkeyp = (MsgKey *) &Wctxp->MsgBuff[0]; if ( !Wctxp->Grp[0] ) return (send(Wctxp->chan,NO_GRP_SEL,sizeof(NO_GRP_SEL)-1,0)); if ( !Wctxp->MsgNum ) return (send(Wctxp->chan,NO_ART_SEL,sizeof(NO_ART_SEL)-1,0)); n = Wctxp->MsgNum; n++; Wctxp->MsgNumf= 0; if ( MsgDBget_byNum(&Wctxp->Msgrab,Wctxp->Grp,n,Wctxp->MsgBuff,MSGBUFFSZ) ) { Wctxp->MsgNum = n; sz = sprintf(Wctxp->bufp,STAT_N_FOLW, n, MsgId$_len,mkeyp->MsgId, MsgId$_len,mkeyp->MsgId); return (send(Wctxp->chan,Wctxp->bufp,sz,0)); } return (send(Wctxp->chan,NO_SUCH_ARTS,sizeof(NO_SUCH_ARTS)-1,0)); } /* *-------------------------------------------------------------------------------- */ char NEW_NEWS[] = "230 list of news since %s follows\r\n"; /* *-------------------------------------------------------------------------------- */ int nntp_newn (WorkerContext *Wctxp) { int n,sz; MsgKey *mkeyp = (MsgKey *) &Wctxp->MsgBuff[0]; GrpKey gk; char *lp = &Wctxp->bufp[0],*cp; time_t t; int flag_g; char MsgId [ MsgId$_len + 3 ]; char lkey [MsgGrp$_len]; int lkeysz; if ( NULL == (lp = strchr (lp,' ')) ) return 0; n = strspn (lp," "); lp += n; if ( NULL == (cp = strchr (lp,' ')) ) return 0; *cp = 0; cp++; if ( !(t = cvt_nntp_to_vms(cp)) ) return 0; sz = sprintf((char *) mkeyp,NEW_NEWS,cp); send(Wctxp->chan,(char *) mkeyp ,sz,0); flag_g = 0; while( GrpDBget_seq(&Wctxp->Grprab,(char *) &gk,flag_g++) ) { if ( strmatch (lp,gk.GrpName) ) { lkey [0] = 0; lkeysz = 0; while( 0 < MsgDBget_byRange(&Wctxp->Msgrab, gk.GrpName, gk.First, gk.Last, (char *) mkeyp, sizeof(MsgKey)+1, lkey,&lkeysz) ) { if ( t <= mkeyp->Date ) { sz = sprintf(MsgId,"%.*s\r\n", MsgId$_len,mkeyp->MsgId); send(Wctxp->chan,MsgId,sz,0); } } } } return (send(Wctxp->chan,NNTP_EOT,sizeof(NNTP_EOT)-1,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 by reject */ int post_bymail (WorkerContext *Wctxp,int sz,char *Grp) { 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); NNTP_LOGT(Wctxp,LOGW,"post_bymail:(To:%.*s,Subj:%.*s,%d bytes).", tosz,bufp0,subjsz,subj,bodysz); if ( send_mail (bufp0,tosz,subj,subjsz,body,bodysz) ) return -1; NNTP_LOGT(Wctxp,LOGW,"post_bymail:(To:%.*s,Subj:%.*s,%d bytes)-Posted.", tosz,bufp0,subjsz,subj,bodysz); return 0; } } NNTP_LOGT(Wctxp,LOGE,"post_bymail:Problem with '%s'.",bufpg); return -1; }