summaryrefslogtreecommitdiffstats
path: root/innbbsd/bbsnnrp.c
diff options
context:
space:
mode:
authorin2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2002-03-07 23:13:44 +0800
committerin2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2002-03-07 23:13:44 +0800
commitae31e19f92e717919ac8e3db9039eb38d2b89aae (patch)
treec70164d6a1852344f44b04a653ae2815043512af /innbbsd/bbsnnrp.c
downloadpttbbs-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.c1187
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()
+{
+}