/*
* 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"
#include "osdep.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(server, &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(server, bbsnnrp)
char *server;
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 == 411) {
FILE *ff = fopen(BBSHOME "/innd/log/badgroup.log", "a");
fprintf(ff, "%s\t%-.*s\r\n", server, rcptr->namelen, rcptr->nameptr);
fclose(ff);
} else 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()
{
}