diff options
author | in2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2002-03-07 23:13:44 +0800 |
---|---|---|
committer | in2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2002-03-07 23:13:44 +0800 |
commit | ae31e19f92e717919ac8e3db9039eb38d2b89aae (patch) | |
tree | c70164d6a1852344f44b04a653ae2815043512af /innbbsd/bbsnnrp.c | |
download | pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.gz pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.bz2 pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.lz pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.xz pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.zst pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.zip |
Initial revision
git-svn-id: http://opensvn.csie.org/pttbbs/pttbbs/trunk/pttbbs@1 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'innbbsd/bbsnnrp.c')
-rw-r--r-- | innbbsd/bbsnnrp.c | 1187 |
1 files changed, 1187 insertions, 0 deletions
diff --git a/innbbsd/bbsnnrp.c b/innbbsd/bbsnnrp.c new file mode 100644 index 00000000..11993629 --- /dev/null +++ b/innbbsd/bbsnnrp.c @@ -0,0 +1,1187 @@ +/* + Usage: bbsnnrp [options] nntpserver activefile + -h|? (help) + -v (verbose protocol transactions) + -c (reset active files only; don't receive articles) + -r remotehost(send articles to remotehost, default=local) + -p port|(send articles to remotehost at port, default=7777) + path(send articles to local at path, default=~bbs/innd/.innbbsd) + -n (don't ask innbbsd server and stat articles) + -w seconds (wait for seconds and run infinitely, default=once) + -a max_art (maximum number of articles received for a group each time) + -s max_stat(maximum number of articles stated for a group each time) + -t stdin|nntp (default=nntp) +*/ + +#include "innbbsconf.h" +#include <sys/mman.h> +#ifndef AIX +# include <sys/fcntl.h> +#endif +#include "bbslib.h" +#include "daemon.h" +#include "nntp.h" + +#ifndef MAX_ARTS +# define MAX_ARTS 100 +#endif +#ifndef MAX_STATS +# define MAX_STATS 1000 +#endif + +#if defined(__linux) +#define NO_USE_MMAP +#else +#define USE_MMAP +#endif + +int Max_Arts= MAX_ARTS; +int Max_Stats = MAX_STATS; + +typedef struct NEWSRC_T { + char *nameptr, *lowptr, *highptr, *modeptr; + int namelen, lowlen, highlen; + ULONG low, high; + int mode, subscribe; +} newsrc_t; + +typedef struct NNRP_T { + int nnrpfd; + int innbbsfd; + FILE *nnrpin, *nnrpout; + FILE *innbbsin, *innbbsout; + char activefile[MAXPATHLEN]; + char rcfile[MAXPATHLEN]; + newsrc_t *newsrc; + char *actpointer, *actend; + int actsize, actfd, actdirty; +} nnrp_t; + +typedef struct XHDR_T { + char *header; + ULONG artno; +} xhdr_t; + +xhdr_t XHDR[MAX_ARTS]; +char LockFile[1024]; + +#define NNRPGroupOK NNTP_GROUPOK_VAL +#define NNRPXhdrOK NNTP_HEAD_FOLLOWS_VAL +#define NNRParticleOK NNTP_ARTICLE_FOLLOWS_VAL +#define INNBBSstatOK NNTP_NOTHING_FOLLOWS_VAL +#define INNBBSihaveOK NNTP_SENDIT_VAL +#define NNRPconnectOK NNTP_POSTOK_VAL +#define NNRPstatOK NNTP_NOTHING_FOLLOWS_VAL +#define INNBBSconnectOK NNTP_POSTOK_VAL + +nnrp_t BBSNNRP; + +void doterm(s) +int s; +{ + printf("bbsnnrp terminated. Signal %d\n", s); + writerc(&BBSNNRP); + if (isfile(LockFile)) + unlink(LockFile); + exit(1); +} + +extern char *optarg; +extern int opterr, optind; + +#ifndef MIN_WAIT +# define MIN_WAIT 60 +#endif + +int ResetActive = 0; +int StatHistory = 1; +int AskLocal = 1; +int RunOnce = 1; + +int DefaultWait = MIN_WAIT; + +char *DefaultPort = DefaultINNBBSPort; +char *DefaultPath = LOCALDAEMON; +char *DefaultRemoteHost; + +#ifndef MAXBUFLEN +#define MAXBUFLEN 256 +#endif +char DefaultNewsgroups[MAXBUFLEN]; +char DefaultOrganization[MAXBUFLEN]; +char DefaultModerator[MAXBUFLEN]; +char DefaultTrustfrom[MAXBUFLEN]; +char DefaultTrustFrom[MAXBUFLEN]; + +usage(arg) +char *arg; +{ +fprintf(stderr,"Usage: %s [options] nntpserver activefile\n", arg); +fprintf(stderr," -h|? (help) \n"); +fprintf(stderr," -v (verbose protocol transactions)\n"); +fprintf(stderr," -c (reset active files only; don't receive articles)\n"); +fprintf(stderr," -r [proto:]remotehost\n"); +fprintf(stderr," (send articles to remotehost, default=ihave:local)\n"); +fprintf(stderr," -p port|(send articles to remotehost at port, default=%s)\n",DefaultINNBBSPort); +fprintf(stderr," path(send articles to local at path, default=~bbs/innd/.innbbsd)\n"); +fprintf(stderr," -w seconds ( > 1 wait for seconds and run infinitely, default=once)\n"); +fprintf(stderr," -n (don't ask innbbsd server and stat articles)\n"); +fprintf(stderr," -a max_art(maximum number of articles received for a group each time)\n"); +fprintf(stderr," default=%d\n", MAX_ARTS); +fprintf(stderr," -s max_stat(maximum number of articles stated for a group each time)\n"); +fprintf(stderr," default=%d\n", MAX_STATS); +fprintf(stderr," -t stdin|nntp (default=nntp)\n"); +fprintf(stderr," -g newsgroups\n"); +fprintf(stderr," -m moderator\n"); +fprintf(stderr," -o organization\n"); +fprintf(stderr," -f trust_user (From: trust_user)\n"); +fprintf(stderr," -F trust_user (From trust_user)\n"); +fprintf(stderr," Please E-mail bug to skhuang@csie.nctu.edu.tw or\n"); +fprintf(stderr," post to tw.bbs.admin.installbbs\n"); +} + +static char *StdinInputType="stdin"; +static char *NntpInputType="nntp"; +static char *NntpIhaveProtocol="ihave"; +static char *NntpPostProtocol="post"; +static char *DefaultNntpProtocol ; +main(argc, argv) +int argc; +char **argv; +{ + char *ptr, *server, *active; + int c, errflag=0; + int lockfd; + char *inputtype; + + DefaultNntpProtocol = NntpIhaveProtocol; + *DefaultNewsgroups = '\0'; + *DefaultModerator = '\0'; + *DefaultOrganization = '\0'; + *DefaultTrustFrom = '\0'; + *DefaultTrustfrom = '\0'; + inputtype = NntpInputType; + while ((c = getopt(argc,argv,"f:F:m:o:g:w:r:p:a:s:t:h?ncv"))!= -1) + switch (c) { + case 'v': + verboseon("bbsnnrp.log"); + break; + case 'c': + ResetActive = 1; + break; + case 'g': + strncpy(DefaultNewsgroups, optarg, sizeof DefaultNewsgroups); + break; + case 'm': + strncpy(DefaultModerator, optarg, sizeof DefaultModerator); + break; + case 'o': + strncpy(DefaultOrganization, optarg, sizeof DefaultOrganization); + break; + case 'f': + strncpy(DefaultTrustfrom, optarg, sizeof DefaultTrustfrom); + break; + case 'F': + strncpy(DefaultTrustFrom, optarg, sizeof DefaultTrustFrom); + break; + case 'r': { + char *hostptr; + AskLocal = 0; + DefaultRemoteHost = optarg; + if ((hostptr = strchr(optarg,':')) != NULL) { + *hostptr = '\0'; + DefaultRemoteHost = hostptr+1; + if (strcasecmp( optarg, "post" ) == 0) + DefaultNntpProtocol = NntpPostProtocol; + *hostptr = ':'; + } + break; + } + case 'w': + RunOnce = 0; + DefaultWait = atoi(optarg); + if (DefaultWait < MIN_WAIT) + DefaultWait = MIN_WAIT; + break; + case 'p': + if (AskLocal == 0) { + DefaultPort = optarg; + } else { + DefaultPath = optarg; + } + break; + case 'n': + StatHistory = 0; + break; + case 'a': + Max_Arts = atol(optarg); + if (Max_Arts < 0) Max_Arts = 0; + break; + case 's': + Max_Stats = atol(optarg); + if (Max_Stats < 0) Max_Stats = 0; + break; + case 't': + if ( strcasecmp(optarg,StdinInputType) == 0) { + inputtype = StdinInputType; + } + break; + case 'h': + case '?': + default: + errflag ++; + } + if (errflag > 0) { + usage(argv[0]); + return(1); + } + if (inputtype == NntpInputType && argc - optind < 2) { + usage(argv[0]); + exit(1); + } + if (inputtype == NntpInputType) { + server = argv[optind]; + active = argv[optind+1]; + if ( isfile(active) ) { + strncpy(BBSNNRP.activefile, active, sizeof BBSNNRP.activefile); + } else if ( strchr(active,'/') == NULL) { + sprintf(BBSNNRP.activefile, "%s/innd/%.*s",BBSHOME, sizeof BBSNNRP.activefile - 7 - strlen(BBSHOME), active); + } else { + strncpy(BBSNNRP.activefile, active, sizeof BBSNNRP.activefile); + } + + strncpy(LockFile , (char*)fileglue("%s.lock",active), sizeof LockFile); + if ((lockfd = open(LockFile, O_RDONLY)) >= 0) { + char buf[10]; + int pid; + + if (read(lockfd, buf, sizeof buf) > 0 && (pid = atoi(buf))>0 && kill(pid,0)==0) { + fprintf(stderr, "another process [%d] running\n", pid); + exit(1); + } else { + fprintf(stderr, "no process [%d] running, but lock file existed, unlinked\n", pid); + unlink(LockFile); + } + close(lockfd); + } + if ((lockfd = open(LockFile, O_RDWR|O_CREAT|O_EXCL,0644)) < 0) { + fprintf( stderr, "maybe another %s process running\n",argv[0]); + exit(1); + } else { + char buf[10]; + int pid; + sprintf(buf,"%-.8d\n",getpid()); + write(lockfd, buf, strlen(buf)); + close(lockfd); + } + for (;;) { + if (!initial_bbs(NULL)) { + fprintf(stderr, "Initial BBS failed\n"); + exit(1); + } + initsockets(server, &BBSNNRP, inputtype); + ptr = (char*)strrchr(active,'/'); + if (ptr != NULL) + ptr++; + else + ptr = active; + sprintf(BBSNNRP.rcfile,"%s/.newsrc.%s.%s",INNDHOME, server, ptr); + initrcfiles(&BBSNNRP); + + signal(SIGTERM, doterm); + signal(SIGKILL, doterm); + signal(SIGHUP, doterm); + signal(SIGPIPE, doterm); + + readnews(&BBSNNRP); + writerc(&BBSNNRP); + closesockets(); + + if (RunOnce) break; + sleep(DefaultWait); + } + unlink(LockFile); + } /* NntpInputType */ + else { + if (!initial_bbs(NULL)) { + fprintf(stderr, "Initial BBS failed\n"); + exit(1); + } + initsockets(server, &BBSNNRP, inputtype); + signal(SIGTERM, doterm); + signal(SIGKILL, doterm); + signal(SIGHUP, doterm); + signal(SIGPIPE, doterm); + + stdinreadnews(&BBSNNRP); + closesockets(); + } /* stdin input type */ + return 0; +} + +headbegin(buffer) +char *buffer; +{ + if (strncmp(buffer,"Path: ",6)==0 ) { + if (strchr(buffer+6,'!') != NULL) + return 1; + } + if (strncmp(buffer,"From ",5)== 0 ) { + if (strchr(buffer+5,':') != NULL) + return 1; + } + return 0; +} + +stdinreadnews(bbsnnrp) +nnrp_t *bbsnnrp; +{ + int i; + char buffer[4096]; + ULONG low, high; + char tmpfilename[MAXPATHLEN]; + FILE *tmpfp = NULL; + char mid[1024]; + int pathagain; + int ngmet, submet, midmet, pathmet, orgmet, approvedmet; + int discard; + char sending_path[MAXPATHLEN]; + int sending_path_len=0; + + strncpy(tmpfilename,(char*)fileglue("/tmp/bbsnnrp-stdin-%d-%d",getuid(),getpid()),sizeof tmpfilename); + fgets(buffer, sizeof buffer, bbsnnrp->innbbsin); + verboselog("innbbsGet: %s", buffer); + if (atoi(buffer) != INNBBSconnectOK) { + fprintf(stderr, "INNBBS server not OK\n"); + return; + } + + if ( DefaultNntpProtocol == NntpPostProtocol ) { + fputs("MODE READER\r\n", bbsnnrp->innbbsout); + fflush(bbsnnrp->innbbsout); + verboselog("innbbsPut: MODE READER\n"); + fgets(buffer, sizeof buffer, bbsnnrp->innbbsin); + verboselog("innbbsGet: %s",buffer); + } + + if (StatHistory == 0) { + fputs("MIDCHECK OFF\r\n", bbsnnrp->innbbsout); + fflush(bbsnnrp->innbbsout); + verboselog("innbbsPut: MIDCHECK OFF\n"); + fgets(buffer, sizeof buffer, bbsnnrp->innbbsin); + verboselog("innbbsGet: %s",buffer); + } + tmpfp = fopen(tmpfilename,"w"); + if (tmpfp == NULL) return; + *mid = '\0'; + for (;;) { + fprintf(stderr,"Try to read from stdin ...\n"); + ngmet = 0, submet = 0, midmet = 0, pathmet = 0, orgmet = 0, approvedmet=0; + discard = 0; + while (fgets(buffer, sizeof buffer, stdin) != NULL) { + char *tmpptr; + tmpptr = strchr(buffer,'\n'); + if (tmpptr != NULL) *tmpptr = '\0'; + if (strncasecmp(buffer,"Message-ID: ",12)==0) { + strncpy(mid, buffer+12,sizeof mid); + midmet = 1; + } else if (strncmp(buffer,"Subject: ",9)==0) { + submet = 1; + } else if (strncmp(buffer,"Path: ",6)==0) { + pathmet = 1; + } else if (strncmp(buffer,"Organization: ",14)==0) { + orgmet = 1; + } else if (strncmp(buffer,"Approved: ",10) == 0) { + approvedmet = 1; + } else if (strncmp(buffer,"From: ",6)==0 && *DefaultTrustfrom ) { + if (strstr(buffer+6, DefaultTrustfrom)==NULL) { + discard = 1; + verboselog("Discard: %s for %s",buffer, DefaultTrustfrom); + } + } else if (strncmp(buffer,"From ",5)==0 && *DefaultTrustFrom ) { + if (strstr(buffer+5, DefaultTrustFrom)==NULL) { + discard = 1; + verboselog("Discard: %s for %s",buffer, DefaultTrustFrom); + } + } else if (strncmp(buffer,"Received: ",10)==0) { + char *rptr=buffer+10, *rrptr; + int savech, len; + if (strncmp(buffer+10,"from ",5)==0) { + rptr +=5; + rrptr = strchr(rptr,'('); + if (rrptr != NULL) rptr = rrptr + 1; + rrptr = strchr(rptr,' '); + savech = *rrptr; + if (rrptr != NULL) *rrptr = '\0'; + } else if (strncmp(buffer+10,"(from ",6)==0) { + rptr +=6; + rrptr = strchr(rptr,')'); + savech = *rrptr; + if (rrptr != NULL) *rrptr = '\0'; + } + len = strlen(rptr) +1; + if (*rptr && sending_path_len + len < sizeof(sending_path)) { + if (*sending_path) + strcat(sending_path, "!"); + strcat(sending_path, rptr); + sending_path_len += len ; + } + if (rrptr != NULL) *rrptr = savech; + } + + if (strncmp(buffer,"Newsgroups: ",12)==0) { + if (*DefaultNewsgroups){ + fprintf(tmpfp,"Newsgroups: %s\r\n",DefaultNewsgroups); + } else { + fprintf(tmpfp,"%s\r\n",buffer); + } + ngmet = 1; + } else { + if (buffer[0] == '\0') { + if (!ngmet && *DefaultNewsgroups) { + fprintf(tmpfp,"Newsgroups: %s\r\n",DefaultNewsgroups); + } + if (!submet) { + fprintf(tmpfp,"Subject: (no subject)\r\n"); + } + if (!pathmet) { + fprintf(tmpfp,"Path: from-mail\r\n"); + } + if (!midmet) { + static int seed; + time_t now; + time(&now); + fprintf(tmpfp,"Message-ID: <%d@%d.%d.%d>\r\n",now,getpid(), getuid(), seed); + sprintf(mid, "<%d@%d.%d.%d>", now, getpid(), getuid(), seed); + seed++; + } + if (!orgmet && *DefaultOrganization) { + fprintf(tmpfp,"Organization: %s\r\n", DefaultOrganization); + } + if (!approvedmet && *DefaultModerator) { + fprintf(tmpfp,"Approved: %s\r\n", DefaultModerator); + } + } + if (strncmp(buffer,"From ",5) != 0 && strncmp(buffer,"To: ",4) !=0) { + if (buffer[0] == '\0') { + if (*sending_path) { + fprintf(tmpfp,"X-Sending-Path: %s\r\n",sending_path); + } + } + fprintf(tmpfp,"%s\r\n",buffer); + } + } + if (buffer[0]=='\0') break; + } + fprintf(stderr,"Article Body begin ...\n"); + pathagain = 0; + while (fgets(buffer, sizeof buffer, stdin) != NULL) { + char *tmpptr; + tmpptr = strchr(buffer,'\n'); + if (tmpptr != NULL) *tmpptr = '\0'; + if ( headbegin(buffer) ) { + FILE *oldfp = bbsnnrp->nnrpin; + pathagain = 1; + fputs(".\r\n",tmpfp); + fclose(tmpfp); + fprintf(stderr,"Try to post ...\n"); + tmpfp = fopen(tmpfilename,"r"); + bbsnnrp->nnrpin = tmpfp; + if (!discard) + if (INNBBSihave(bbsnnrp, -1, mid)== -1) { + fprintf(stderr,"post failed\n"); + } + bbsnnrp->nnrpin = oldfp; + fclose(tmpfp); + *mid = '\0'; + tmpfp = fopen(tmpfilename,"w"); + fprintf(tmpfp,"%s\r\n",buffer); + break; + } else { + fprintf(tmpfp,"%s\r\n",buffer); + } + } + if (!pathagain) break; + } + if (!pathagain && tmpfp) { + FILE *oldfp = bbsnnrp->nnrpin; + fputs(".\r\n",tmpfp); + fclose(tmpfp); + fprintf(stderr,"Try to post ...\n"); + tmpfp = fopen(tmpfilename,"r"); + bbsnnrp->nnrpin = tmpfp; + if (!discard) + if (INNBBSihave(bbsnnrp, -1, mid)== -1) { + fprintf(stderr,"post failed\n"); + } + bbsnnrp->nnrpin = oldfp; + fclose(tmpfp); + } + if (isfile(tmpfilename)) { + unlink(tmpfilename); + } +} + +static char *ACT_BUF, *RC_BUF; +int ACT_COUNT; + +initrcfiles(bbsnnrp) +nnrp_t *bbsnnrp; +{ + FILE *actfp, *rcfp; + char buff[1024]; + int actfd, i, count, actcount=0, rcount=0, maxcount; + struct stat st; + char *actlistptr, *ptr; + + actfd = open(bbsnnrp->activefile, O_RDWR); + if (actfd < 0) { + fprintf( stderr, "can't read/write %s\n", bbsnnrp->activefile ); + exit(1); + } + if (fstat(actfd, &st) != 0) { + fprintf( stderr, "can't stat %s\n", bbsnnrp->activefile ); + exit(1); + } + + bbsnnrp->actfd = actfd; + bbsnnrp->actsize = st.st_size; +#ifdef USE_MMAP + bbsnnrp->actpointer = mmap(0, st.st_size, PROT_WRITE | PROT_READ, + MAP_SHARED, actfd, 0); + if (bbsnnrp->actpointer == (char*)-1) { + fprintf( stderr, "mmap error \n"); + exit(1); + } +#else + if (bbsnnrp->actpointer == NULL) { + bbsnnrp->actpointer = (char*)mymalloc(st.st_size); + } else { + bbsnnrp->actpointer = (char*)myrealloc(bbsnnrp->actpointer,st.st_size); + } + if (bbsnnrp->actpointer == NULL || read(actfd, bbsnnrp->actpointer, st.st_size) <= 0) { + fprintf( stderr, "read act error \n"); + exit(1); + } +#endif + bbsnnrp->actend = bbsnnrp->actpointer + st.st_size; + i = 0, count = 0; + for (ptr = bbsnnrp->actpointer; ptr < bbsnnrp->actend && (actlistptr = (char*)strchr(ptr,'\n')) != NULL; ptr = actlistptr +1, ACT_COUNT++) { + if (*ptr == '\n') continue; + if (*ptr == '#') continue; + count ++; + } + bbsnnrp->newsrc = (newsrc_t*) mymalloc( sizeof(newsrc_t) * count); + ACT_COUNT = 0; + for (ptr = bbsnnrp->actpointer; ptr < bbsnnrp->actend && (actlistptr = (char*)strchr(ptr,'\n')) != NULL; ptr = actlistptr +1 ) { + register newsrc_t *rcptr; + char *nptr; + /**actlistptr = '\0';*/ + if (*ptr == '\n') continue; + if (*ptr == '#') continue; + rcptr = &bbsnnrp->newsrc[ACT_COUNT]; + rcptr->nameptr = NULL; + rcptr->namelen = 0; + rcptr->lowptr = NULL; + rcptr->lowlen = 0; + rcptr->highptr = NULL; + rcptr->highlen = 0; + rcptr->modeptr = NULL; + rcptr->low = 0; + rcptr->high = 0; + rcptr->mode = 'y'; + for (nptr= ptr ;*nptr && isspace(*nptr); ) nptr++; + if ( nptr == actlistptr ) continue; + rcptr->nameptr = nptr; + for (nptr++; *nptr && !isspace(*nptr); ) nptr++; + rcptr->namelen = (int)(nptr - rcptr->nameptr); + if ( nptr == actlistptr) continue; + for (nptr++ ;*nptr && isspace(*nptr); ) nptr++; + if ( nptr == actlistptr) continue; + rcptr->highptr = nptr; + rcptr->high = atol(nptr); + for (nptr++; *nptr && !isspace(*nptr); ) nptr++; + rcptr->highlen = (int)(nptr - rcptr->highptr); + if ( nptr == actlistptr) continue; + for (nptr++ ;*nptr && isspace(*nptr); ) nptr++; + if ( nptr == actlistptr) continue; + rcptr->lowptr = nptr; + rcptr->low = atol(nptr); + for (nptr++; *nptr && !isspace(*nptr); ) nptr++; + rcptr->lowlen = (int)(nptr - rcptr->lowptr); + if ( nptr == actlistptr) continue; + for (nptr++ ;*nptr && isspace(*nptr); ) nptr++; + if ( nptr == actlistptr) continue; + rcptr->mode = *nptr; + rcptr->modeptr = nptr; + ACT_COUNT ++; + } +} + +initsockets(server, bbsnnrp, type) +char *server; +nnrp_t *bbsnnrp; +char *type; +{ + int nnrpfd ; + int innbbsfd; + if (AskLocal) { + innbbsfd = unixclient(DefaultPath,"tcp"); + if (innbbsfd < 0) { + fprintf(stderr, "Connect to %s error. You may not run innbbsd\n", LOCALDAEMON); + /* unix connect fail, may run by inetd, try to connect to local once */ + innbbsfd = inetclient("localhost",DefaultPort,"tcp"); + if (innbbsfd < 0) { + exit(2); + } + close(innbbsfd); + /* try again */ + innbbsfd = unixclient(DefaultPath,"tcp"); + if (innbbsfd < 0) { + exit(3); + } + } + verboselog("INNBBS connect to %s\n",DefaultPath); + } else { + innbbsfd = inetclient(DefaultRemoteHost,DefaultPort,"tcp"); + if (innbbsfd < 0) { + fprintf(stderr, "Connect to %s at %s error. Remote Server not Ready\n", DefaultRemoteHost, DefaultPort); + exit(2); + } + verboselog("INNBBS connect to %s\n",DefaultRemoteHost); + } + if (type == StdinInputType) { + bbsnnrp->nnrpfd = 0; + bbsnnrp->innbbsfd = innbbsfd; + if ((bbsnnrp->nnrpin = fdopen(0,"r")) == NULL || + (bbsnnrp->nnrpout= fdopen(1,"w")) == NULL || + (bbsnnrp->innbbsin= fdopen(innbbsfd,"r")) == NULL || + (bbsnnrp->innbbsout= fdopen(innbbsfd,"w"))== NULL ) { + fprintf( stderr, "fdopen error\n"); + exit(3); + } + return; + } + nnrpfd = inetclient(server, "nntp","tcp"); + if (nnrpfd < 0) { + fprintf(stderr, " connect to %s error \n", server); + exit(2); + } + verboselog("NNRP connect to %s\n", server); + bbsnnrp->nnrpfd = nnrpfd; + bbsnnrp->innbbsfd = innbbsfd; + if ((bbsnnrp->nnrpin = fdopen(nnrpfd,"r")) == NULL || + (bbsnnrp->nnrpout= fdopen(nnrpfd,"w")) == NULL || + (bbsnnrp->innbbsin= fdopen(innbbsfd,"r")) == NULL || + (bbsnnrp->innbbsout= fdopen(innbbsfd,"w"))== NULL ) { + fprintf( stderr, "fdopen error\n"); + exit(3); + } +} + +closesockets() +{ + fclose(BBSNNRP.nnrpin); + fclose(BBSNNRP.nnrpout); + fclose(BBSNNRP.innbbsin); + fclose(BBSNNRP.innbbsout); + close(BBSNNRP.nnrpfd); + close(BBSNNRP.innbbsfd); +} + +updaterc(actptr, len, value) +char *actptr; +int len; +ULONG value; +{ + for (actptr += len -1; len -- >0; ) { + *actptr-- = value % 10 + '0'; + value /= 10; + } +} + +/* + if old file is empty, don't need to update + prevent from disk full +*/ +int +myrename(old,new) +char *old, *new; +{ + struct stat st; + if (stat(old,&st) != 0) return -1; + if (st.st_size <= 0) return -1; + return rename(old,new); +} + +flushrc(bbsnnrp) +nnrp_t *bbsnnrp; +{ + int backfd; + char *bak1; + if (bbsnnrp->actdirty == 0) return; + bak1 = (char*)strdup((char*)fileglue("%s.BAK",bbsnnrp->activefile)); + if (isfile(bak1)) { + myrename(bak1, (char*)fileglue("%s.BAK.OLD",bbsnnrp->activefile)); + } +#ifdef USE_MMAP + if ((backfd=open((char*)fileglue("%s.BAK",bbsnnrp->activefile),O_WRONLY | O_TRUNC | O_CREAT, 0664)) < 0 || write(backfd, bbsnnrp->actpointer, bbsnnrp->actsize) < bbsnnrp->actsize) +#else + myrename(bbsnnrp->activefile, bak1); + if ((backfd=open(bbsnnrp->activefile,O_WRONLY | O_TRUNC | O_CREAT, 0664)) < 0 || write(backfd, bbsnnrp->actpointer, bbsnnrp->actsize) < bbsnnrp->actsize) +#endif + { + char emergent[128]; + sprintf(emergent,"/tmp/bbsnnrp.%d.active",getpid()); + fprintf(stderr, "write to backup active fail. Maybe disk full\n"); + fprintf(stderr, "try to write in %s\n",emergent); + if ((backfd = open(emergent,O_WRONLY | O_TRUNC | O_CREAT, 0644))<0 || write(backfd, bbsnnrp->actpointer, bbsnnrp->actsize) < bbsnnrp->actsize) + { + fprintf(stderr, "write to %sfail.\n", emergent); + } else { + close(backfd); + } + /* if write fail, should leave */ + /*exit(1);*/ + } else { + close(backfd); + } + free(bak1); + bbsnnrp->actdirty = 0; +} + +writerc(bbsnnrp) +nnrp_t *bbsnnrp; +{ + if (bbsnnrp->actpointer) { + flushrc(bbsnnrp); +#ifdef USE_MMAP + if (munmap(bbsnnrp->actpointer, bbsnnrp->actsize) < 0) + fprintf(stderr, "can't unmap\n"); + /*free(bbsnnrp->actpointer);*/ + bbsnnrp->actpointer = NULL; +#endif + if (close(bbsnnrp->actfd) < 0) + fprintf(stderr, "can't close actfd\n"); + } +} + +static FILE* Xhdrfp; +static char NNRPbuffer[4096]; +static char INNBBSbuffer[4096]; + +char * +NNRPgets(string, len, fp) +char *string; +int len; +FILE *fp; +{ + char* re = fgets(string, len, fp); + char *ptr; + if (re != NULL) { + if ((ptr = (char*)strchr(string,'\r'))!=NULL) + *ptr = '\0'; + if ((ptr = (char*)strchr(string,'\n'))!=NULL) + *ptr = '\0'; + } + return re; +} + +int NNRPstat(bbsnnrp, artno, mid) +nnrp_t *bbsnnrp; + ULONG artno; +char **mid; +{ + char *ptr; + int code; + + *mid = NULL; + fprintf(bbsnnrp->nnrpout,"STAT %d\r\n",artno); + fflush(bbsnnrp->nnrpout); + verboselog("nnrpPut: STAT %d\n",artno); + NNRPgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin); + verboselog("nnrpGet: %s\n",NNRPbuffer); + + ptr = (char*) strchr(NNRPbuffer, ' '); + if (ptr != NULL) *ptr++ = '\0'; + code = atoi(NNRPbuffer); + ptr = (char*) strchr(ptr, ' '); + if (ptr != NULL) *ptr++ = '\0'; + *mid = ptr; + ptr = (char*) strchr(ptr, ' '); + if (ptr != NULL) *ptr++ = '\0'; + return code; +} + +int +NNRPxhdr(pattern, bbsnnrp, i, low, high) +char *pattern; +nnrp_t *bbsnnrp; +int i; +ULONG low, high; +{ + newsrc_t *rcptr = &bbsnnrp->newsrc[i]; + int size, code; + + Xhdrfp = bbsnnrp->nnrpin; + fprintf(bbsnnrp->nnrpout,"XHDR %s %d-%d\r\n",pattern,low, high ); +#ifdef BBSNNRPDEBUG + printf("XHDR %s %d-%d\r\n",pattern,low, high ); +#endif + fflush(bbsnnrp->nnrpout); + verboselog("nnrpPut: XHDR %s %d-%d\n",pattern,low, high ); + NNRPgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin); + verboselog("nnrpGet: %s\n", NNRPbuffer); + code = atoi(NNRPbuffer); + return code; +} + +int NNRPxhdrget(artno, mid, iscontrol) +int *artno; +char **mid; +int iscontrol; +{ + *mid = NULL; + *artno = 0; + if (NNRPgets(NNRPbuffer, sizeof NNRPbuffer, Xhdrfp) == NULL) + return 0; + else { + char *ptr, *s; + if (strcmp(NNRPbuffer,".")==0) return 0; + ptr = (char*)strchr(NNRPbuffer,' '); + if (!ptr) return 1; + *ptr++ = '\0'; + *artno = atol(NNRPbuffer); + if (iscontrol) { + ptr = (char*)strchr(s=ptr,' '); + if (!ptr) return 1; + *ptr++ = '\0'; + if (strcmp(s,"cancel") != 0) return 1; + } + *mid = ptr; + return 1; + } +} + +int INNBBSstat(bbsnnrp, i, mid) +nnrp_t *bbsnnrp; +int i; +char *mid; +{ + newsrc_t *rcptr = &bbsnnrp->newsrc[i]; + int size, code; + + fprintf(bbsnnrp->innbbsout,"STAT %s\r\n", mid); + fflush(bbsnnrp->innbbsout); + verboselog("innbbsPut: STAT %s\n", mid); + NNRPgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin); + verboselog("innbbsGet: %s\n", INNBBSbuffer); + return atol(INNBBSbuffer); +} + +int INNBBSihave(bbsnnrp, artno, mid) +nnrp_t *bbsnnrp; +ULONG artno; +char *mid; +{ + int size, code; + int header=1; + + if (DefaultNntpProtocol == NntpPostProtocol) { + fprintf(bbsnnrp->innbbsout,"POST\r\n"); + fflush(bbsnnrp->innbbsout); + verboselog("innbbsPut: POST %s\n", mid); + } else { + fprintf(bbsnnrp->innbbsout,"IHAVE %s\r\n", mid); + fflush(bbsnnrp->innbbsout); + verboselog("innbbsPut: IHAVE %s\n", mid); + } + if (NNRPgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin)==NULL){ + return -1; + } + verboselog("innbbsGet: %s\n", INNBBSbuffer); +#ifdef BBSNNRPDEBUG + printf("ihave got %s\n", INNBBSbuffer); +#endif + + if (DefaultNntpProtocol == NntpPostProtocol) { + if ((code=atol(INNBBSbuffer)) != NNTP_START_POST_VAL) { + if (code == NNTP_POSTFAIL_VAL) + return 0; + else + return -1; + } + } else { + if ((code=atol(INNBBSbuffer)) != INNBBSihaveOK) { + if (code == 435 || code == 437) + return 0; + else + return -1; + } + } + if (artno != -1) { + fprintf(bbsnnrp->nnrpout,"ARTICLE %d\r\n", artno); + verboselog("nnrpPut: ARTICLE %d\n", artno); +#ifdef BBSNNRPDEBUG + printf("ARTICLE %d\r\n", artno); +#endif + fflush(bbsnnrp->nnrpout); + if (NNRPgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin)==NULL) { + return -1; + } + verboselog("nnrpGet: %s\n", NNRPbuffer); +#ifdef BBSNNRPDEBUG + printf("article got %s\n", NNRPbuffer); +#endif + if (atol(NNRPbuffer) != NNRParticleOK) { + fputs(".\r\n",bbsnnrp->innbbsout); + fflush(bbsnnrp->innbbsout); + NNRPgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin); + verboselog("innbbsGet: %s\n",INNBBSbuffer); + return 0; + } + } + header = 1; + while ( fgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin) != NULL) + { + if (strcmp(NNRPbuffer,"\r\n") == 0) + header = 0; + if (strcmp(NNRPbuffer,".\r\n")==0) { + verboselog("nnrpGet: .\n"); + fputs(NNRPbuffer,bbsnnrp->innbbsout); + fflush(bbsnnrp->innbbsout); + verboselog("innbbsPut: .\n"); + if (NNRPgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin)==NULL) + return -1; + verboselog("innbbsGet: %s\n",INNBBSbuffer); +#ifdef BBSNNRPDEBUG + printf("end ihave got %s\n", INNBBSbuffer); +#endif + code = atol(INNBBSbuffer); + if (DefaultNntpProtocol == NntpPostProtocol) { + if (code == NNTP_POSTEDOK_VAL) + return 1; + if (code == NNTP_POSTFAIL_VAL) + return 0; + } else { + if (code == 235) + return 1; + if (code == 437 || code == 435) + return 0; + } + break; + } + if ( DefaultNntpProtocol == NntpPostProtocol && + header && strncasecmp(NNRPbuffer,"NNTP-Posting-Host: ",19)==0) { + fprintf(bbsnnrp->innbbsout,"X-%s",NNRPbuffer); + } else { + fputs(NNRPbuffer,bbsnnrp->innbbsout); + } + } + fflush(bbsnnrp->innbbsout); + return -1; +} + +int +NNRPgroup(bbsnnrp, i, low, high) +nnrp_t *bbsnnrp; +int i; +ULONG *low, *high; +{ + newsrc_t *rcptr = &bbsnnrp->newsrc[i]; + int size, code; + ULONG tmp; + + fprintf(bbsnnrp->nnrpout,"GROUP %-.*s\r\n", + rcptr->namelen, rcptr->nameptr ); + printf("GROUP %-.*s\r\n", rcptr->namelen, rcptr->nameptr ); + verboselog("nnrpPut: GROUP %-.*s\n", rcptr->namelen, rcptr->nameptr ); + fflush(bbsnnrp->nnrpout); + NNRPgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin); + verboselog("nnrpGet: %s\n",NNRPbuffer); + printf("%s\n",NNRPbuffer); + sscanf(NNRPbuffer, "%d %d %ld %ld", &code, &size, low, high); + if (*low > *high) { + tmp = *low; + *low = *high; + *high = tmp; + } + return code; +} + + +readnews(bbsnnrp) +nnrp_t *bbsnnrp; +{ + int i; + char buffer[4096]; + ULONG low, high; + + fgets(buffer, sizeof buffer, bbsnnrp->innbbsin); + verboselog("innbbsGet: %s", buffer); + if (atoi(buffer) != INNBBSconnectOK) { + fprintf(stderr, "INNBBS server not OK\n"); + return; + } +#ifdef BBSNNRPDEBUG + printf("%s",buffer); +#endif + fgets(buffer, sizeof buffer, bbsnnrp->nnrpin); + verboselog("nnrpGet: %s", buffer); + if (buffer[0] != '2') { + /*if (atoi(buffer) != NNRPconnectOK && atoi(buffer) != NNTP_NOPOSTOK_VAL) {*/ + fprintf(stderr, "NNRP server not OK\n"); + return; + } +#ifdef BBSNNRPDEBUG + printf("%s",buffer); +#endif + fputs("MODE READER\r\n", bbsnnrp->nnrpout); + fflush(bbsnnrp->nnrpout); + verboselog("nnrpPut: MODE READER\n"); + fgets(buffer, sizeof buffer, bbsnnrp->nnrpin); + verboselog("nnrpGet: %s",buffer); + + if ( DefaultNntpProtocol == NntpPostProtocol ) { + fputs("MODE READER\r\n", bbsnnrp->innbbsout); + fflush(bbsnnrp->innbbsout); + verboselog("innbbsPut: MODE READER\n"); + fgets(buffer, sizeof buffer, bbsnnrp->innbbsin); + verboselog("innbbsGet: %s",buffer); + } + +#ifdef BBSNNRPDEBUG + printf("%s",buffer); +#endif + + if (StatHistory == 0) { + fputs("MIDCHECK OFF\r\n", bbsnnrp->innbbsout); + fflush(bbsnnrp->innbbsout); + verboselog("innbbsPut: MIDCHECK OFF\n"); + fgets(buffer, sizeof buffer, bbsnnrp->innbbsin); + verboselog("innbbsGet: %s",buffer); + } + bbsnnrp->actdirty = 0; + for (i =0; i< ACT_COUNT; i++) { + int code = NNRPgroup(bbsnnrp, i, &low, &high); + newsrc_t *rcptr = &bbsnnrp->newsrc[i]; + int j; + ULONG artno; + char *mid; + int artcount; + +#ifdef BBSNNRPDEBUG + printf("got reply %d %ld %ld\n",code, low, high); +#endif + artcount = 0; + if (code == NNRPGroupOK) { + int xcount; + ULONG maxartno= rcptr->high; + int isCancelControl = (strncmp(rcptr->nameptr,"control",rcptr->namelen)==0) + || + (strncmp(rcptr->nameptr,"control.cancel",rcptr->namelen)==0) ; + +/* less than or equal to high, for server renumber */ + if (rcptr->low != low) { + bbsnnrp->actdirty = 1; + rcptr->low = low; + updaterc(rcptr->lowptr, rcptr->lowlen, rcptr->low); + } + if (ResetActive) { + if (rcptr->high != high) { + bbsnnrp->actdirty = 1; + rcptr->high = high; + updaterc(rcptr->highptr, rcptr->highlen, rcptr->high); + } + } else if (rcptr->high < high) { + int xhdrcode; + ULONG maxget=high; + int exception=0; + if (rcptr->high < low) { + bbsnnrp->actdirty = 1; + rcptr->high = low; + updaterc(rcptr->highptr, rcptr->highlen, low); + } + if (high > rcptr->high + Max_Stats) { + maxget = rcptr->high + Max_Stats; + } + if ( isCancelControl ) + xhdrcode = NNRPxhdr("Control",bbsnnrp, i, rcptr->high+1, maxget); + else + xhdrcode = NNRPxhdr("Message-ID",bbsnnrp, i, rcptr->high+1, maxget); + + maxartno = maxget; + if ( xhdrcode == NNRPXhdrOK) { + while (NNRPxhdrget(&artno, &mid, isCancelControl)) { +/*#define DEBUG*/ +#ifdef DEBUG + printf("no %d id %s\n",artno, mid); +#endif + if (artcount < Max_Arts) { + if (mid != NULL && !isCancelControl) { + if (!StatHistory || INNBBSstat(bbsnnrp,i,mid) != INNBBSstatOK) { + printf("** %d ** %d need it %s\n", artcount, artno,mid); + XHDR[artcount].artno = artno; + XHDR[artcount].header = restrdup(XHDR[artcount].header,mid); + /*INNBBSihave(bbsnnrp,i,artno,mid);*/ + /* to get it */ + artcount++; + } + } else if (mid != NULL) { + if (INNBBSstat(bbsnnrp,i,mid) == INNBBSstatOK) { + printf("** %d ** %d need cancel %s\n", artcount, artno,mid); + XHDR[artcount].artno = artno; + XHDR[artcount].header = restrdup(XHDR[artcount].header,mid); + artcount++; + } + } + maxartno = artno; + } + } + }/* while xhdr OK */ + exception = 0; + for (xcount = 0; xcount < artcount; xcount++) { + ULONG artno; + char *mid; + artno = XHDR[xcount].artno; + mid = XHDR[xcount].header; + if (isCancelControl) { + if (NNRPstat(bbsnnrp,artno,&mid) == NNRPstatOK) { + } + } + printf("** %d ** %d i have it %s\n", xcount, artno, mid); + if (!ResetActive && mid != NULL) + exception = INNBBSihave(bbsnnrp,artno,mid); + if (exception == -1) break; + if (rcptr->high != artno) { + rcptr->high = artno; + updaterc(rcptr->highptr, rcptr->highlen, rcptr->high); + } + } + if (rcptr->high != maxartno && exception != -1) { + bbsnnrp->actdirty = 1; + rcptr->high = maxartno; + updaterc(rcptr->highptr, rcptr->highlen, maxartno); + } + } + } + /* + flushrc(bbsnnrp); + */ + } + fprintf(bbsnnrp->innbbsout,"quit\r\n"); + fprintf(bbsnnrp->nnrpout,"quit\r\n"); + fflush(bbsnnrp->innbbsout); + fflush(bbsnnrp->nnrpout); + fgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin); + fgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin); + +/* bbsnnrp->newsrc[0].high = 1900; + updaterc(bbsnnrp->newsrc[0].highptr, bbsnnrp->newsrc[0].highlen, + bbsnnrp->newsrc[0].high); +*/ +} + +INNBBSDhalt() +{ +} |