diff options
Diffstat (limited to 'innbbsd/bbslink.c')
-rw-r--r-- | innbbsd/bbslink.c | 2021 |
1 files changed, 2021 insertions, 0 deletions
diff --git a/innbbsd/bbslink.c b/innbbsd/bbslink.c new file mode 100644 index 00000000..2b0b6f37 --- /dev/null +++ b/innbbsd/bbslink.c @@ -0,0 +1,2021 @@ +#if defined( LINUX ) +# include "innbbsconf.h" +# include "bbslib.h" +# include <varargs.h> +#else +# include <varargs.h> +# include "innbbsconf.h" +# include "bbslib.h" +#endif +#include "antisplam.h" + +#include <sys/mman.h> + +#ifndef AIX +# include <sys/fcntl.h> +#endif + +#if defined(PalmBBS) +#include <utime.h> +#endif + + +#include "daemon.h" +#include "nntp.h" +#include "externs.h" + +/* + * TODO 1. read newsfeeds.bbs, read nodelist.bbs, read bbsname.bbs 2. scan + * new posts and append to .link 3. rename .link to .send (must lock) 4. + * start to send .send out and append not sent to .link + * + * 5. node.LOCK (with pid) 6. log articles sent + */ + + +#ifndef MAXBUFLEN +#define MAXBUFLEN 256 +#endif + +#define MAX_OUTGO_POST 100 /* bbslink 一次處理的轉出最大文章數量 */ + +typedef struct my_out_bntp +{ + char *board, *filename, *userid, *nickname, *subject; +} my_out_bntp; +struct my_out_bntp out_bntp[MAX_OUTGO_POST]; + +int outgo_post=0; + +typedef struct Over_t +{ + time_t mtime; + char date[MAXBUFLEN]; + char nickname[MAXBUFLEN]; + char subject[MAXBUFLEN]; + char from[MAXBUFLEN]; + char msgid[MAXBUFLEN]; + char site[MAXBUFLEN]; + char board[MAXBUFLEN]; +} linkoverview_t; + +typedef struct SendOver_t +{ + char *board, *filename, *group, *from, *subject; + char *outgoingtype, *msgid, *path; + char *date, *control; + time_t mtime; +} soverview_t; + +typedef struct Stat_t +{ + int localsendout; + int localfailed; + int remotesendout; + int remotefailed; +} stat_t; + +static stat_t *BBSLINK_STAT; + +static int NoAction = 0; +static int Verbose = 0; +static int VisitOnly = 0; +static int NoVisit = 0; +static char *DefaultFeedSite = ""; +static int KillFormerBBSLINK = 0; + +extern char *SITE; +extern char *GROUPS; + +char NICKNAME[MAXBUFLEN]; + +char DATE_BUF[MAXBUFLEN]; +extern char *DATE; + +char FROM_BUF[MAXBUFLEN]; +extern char *FROM; + +#ifndef MapleBBS +char POSTER_BUF[MAXBUFLEN]; +char *POSTER; +#endif + +char MYADDR[MAXBUFLEN]; +char MYSITE[MAXBUFLEN]; + +char SUBJECT_BUF[MAXBUFLEN]; +extern char *SUBJECT; + +char MSGID_BUF[MAXBUFLEN]; +extern char *MSGID; + +char LINKPROTOCOL[MAXBUFLEN]; +int LINKPORT; +char ORGANIZATION[MAXBUFLEN]; +char NEWSCONTROL[MAXBUFLEN]; +char NEWSAPPROVED[MAXBUFLEN]; +char NNTPHOST_BUF[MAXBUFLEN]; +extern char *NNTPHOST; +char PATH_BUF[MAXBUFLEN]; +extern char *PATH; + +char CONTROL_BUF[MAXBUFLEN]; +extern char *CONTROL; + +char *BODY, *HEAD; + +int USEIHAVE = 1; +int USEPOST = 0; +int USEDATA = 0; +int FEEDTYPE = ' '; + +int NNTP = -1; +FILE *NNTPrfp = NULL; +FILE *NNTPwfp = NULL; +char NNTPbuffer[1024]; +static char *NEWSFEED; +static char *REMOTE = "REMOTE"; +static char *LOCAL = "LOCAL"; + +static int FD, FD_SIZE; +static char *FD_BUF; +static char *FD_END; + +static char *COMMENT = "\n"; +/*"[Ptt 送出]\n";*/ + +char *fileglue(); +int +is_outgo_post(board, filename, userid, nickname, subject) + char *board, *filename, *userid, *nickname, *subject; +{ + int mypost; + + for (mypost = 0; mypost < outgo_post; mypost++) + { + if (!strcmp(out_bntp[mypost].filename, filename)) + if (!strcmp(out_bntp[mypost].userid, userid)) + if (!strcmp(out_bntp[mypost].board, board)) + if (!strcmp(out_bntp[mypost].nickname, nickname)) + if (!strcmp(out_bntp[mypost].subject, subject)){ + if (Verbose) + printf("bad_cancel: %s, %s(%s), %s, %s\n", + board, userid, nickname, subject, filename); + bbslog("bad_cancel: %s, %s(%s), %s, %s\n", + board, userid, nickname, subject, filename); + return 1; + } + } + return 0; +} +/* +woju +Cross-fs rename() +*/ + +Rename(char* src, char* dst) +{ + char cmd[200]; + + if (rename(src, dst) == 0) + return 0; + + sprintf(cmd, "/bin/mv %s %s", src, dst); + return system(cmd); + +} + + +bbslink_un_lock(file) + char *file; +{ + char *lockfile = fileglue("%s.LOCK", file); + + if (isfile(lockfile)) + unlink(lockfile); +} + +bbslink_get_lock(file) + char *file; +{ + int lockfd; + char LockFile[MAXPATHLEN]; + + strncpy(LockFile, (char *) fileglue("%s.LOCK", file), 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) + { + if (KillFormerBBSLINK) + { + kill(pid, SIGTERM); + unlink(LockFile); + } + else + { + fprintf(stderr, "another process [%d] running\n", pid); + return 0; + } + } + 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, "lock %s error: another bbslink process running\n", LockFile); + return 0; + } + else + { + char buf[10]; + int pid; + + sprintf(buf, "%-.8d\n", getpid()); + write(lockfd, buf, strlen(buf)); + close(lockfd); + return 1; + } +} + + +int +tcpcommand(va_alist) +va_dcl +{ + va_list ap; + register char *fmt; + char *ptr; + + va_start(ap); + fmt = va_arg(ap, char *); + vfprintf(NNTPwfp, fmt, ap); + fprintf(NNTPwfp, "\r\n"); + fflush(NNTPwfp); + + fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp); + ptr = strchr(NNTPbuffer, '\r'); + if (ptr) + *ptr = '\0'; + ptr = strchr(NNTPbuffer, '\n'); + if (ptr) + *ptr = '\0'; + va_end(ap); + return atoi(NNTPbuffer); +} + +char * +tcpmessage() +{ + char *ptr; + + ptr = strchr(NNTPbuffer, ' '); + if (ptr) + return ptr; + return NNTPbuffer; +} + +read_article(lover, filename, userid) + linkoverview_t *lover; + char *filename, *userid; +{ + FILE *fp; + int fd; + struct stat st; + time_t mtime; + char *buffer; + char *artptr, *artend, *artback; + + if (stat(filename, &st) != 0) + return 0; + lover->mtime = st.st_mtime; + fd = open(filename, O_RDONLY); + if (fd < 0) + { + bbslog("<bbslink> Err: can't open %s\n", filename); + return 0; + } + + if (FD_BUF == NULL) + { + FD_BUF = mymalloc(st.st_size + 1 + strlen(COMMENT)); + } + else + { + FD_BUF = myrealloc(FD_BUF, st.st_size + 1 + strlen(COMMENT)); + } + FD_BUF[st.st_size] = '\0'; + read(fd, FD_BUF, st.st_size); + sprintf(FD_BUF + st.st_size, "%s", COMMENT); + st.st_size += strlen(COMMENT); + FD_SIZE = st.st_size; + for (buffer = FD_BUF, artend = FD_BUF + st.st_size, + artback = strchr(buffer, '\n'); + buffer && buffer < artend && *buffer; + artback = strchr(buffer, '\n') + ) + { + /* while( fgets(buffer, sizeof buffer, fp) != NULL) { */ + char *m, *n; + char *ptr; + + if (artback != NULL) + *artback = '\0'; + if (*buffer == '\0') + break; + +#ifndef MapleBBS + if (strstr(buffer, userid) != NULL) + { + m = strchr(buffer, '('); + n = strrchr(buffer, ')'); + if (m != NULL && n != NULL) + { + strncpy(lover->nickname, m + 1, n - m - 1); + lover->nickname[n - m - 1] = '\0'; + } + else + { + *lover->nickname = '\0'; + } + } + else if (strncmp(buffer, "Date: ", 11) == 0) + { + strcpy(lover->date, buffer + 11); + } + else if (strncmp(buffer, "發信站: ", 8) == 0) + { + m = strchr(buffer, '('); + n = strrchr(buffer, ')'); + strncpy(lover->date, m + 1, n - m - 1); + lover->date[n - m - 1] = '\0'; + } +#endif + + if (artback != NULL) + { + *artback = '\n'; + buffer = artback + 1; + } + else + { + break; + } + } + if (artback != NULL) + BODY = artback + 1; + else + BODY = ""; + close(fd); + return 1; +} + +save_outgoing(sover, filename, userid, poster, mtime) + soverview_t *sover, *filename, *userid, *poster; + time_t mtime; +{ + newsfeeds_t *nf; + char *group, *server, *serveraddr; + char *subject, *path; + char *board; + char *ptr1, *ptr2; + + board = sover->board; + + PATH = MYBBSID; + nf = (newsfeeds_t *) search_board(board); + if (nf == NULL) + { + bbslog("<bbslink> save_outgoing: No such board %s\n", board); + return; + } + else + { + group = nf->newsgroups; + server = nf->path; + } + if (!server || !*server) + { + sprintf(PATH_BUF, "%.*s (local)", sizeof PATH_BUF - 9, MYBBSID); + PATH = PATH_BUF; + serveraddr = ""; + sover->path = PATH; + } + for (ptr1 = server; ptr1 && *ptr1;) + { + nodelist_t *nl; + char savech; + + for (; *ptr1 && isspace(*ptr1); ptr1++); + if (!*ptr1) + break; + for (ptr2 = ptr1; *ptr2 && !isspace(*ptr2); ptr2++); + savech = *ptr2; + *ptr2 = '\0'; + nl = (nodelist_t *) search_nodelist_bynode(ptr1); + *ptr2 = savech; + ptr1 = ptr2++; + if (nl == NULL) + continue; + /* if (nl->feedfp == NULL) continue; */ + + if (nl->host && *nl->host) + { + if (nl->feedfp == NULL) + { + nl->feedfp = fopen(fileglue("%s/%s.link", INNDHOME, nl->node), "a"); + if (nl->feedfp == NULL) + { + bbslog("<save outgoing> append failed for %s/%s.link", INNDHOME, nl->node); + } + } + if (nl->feedfp != NULL) + { + flock(fileno(nl->feedfp), LOCK_EX); + fprintf(nl->feedfp, "%s\t%s\t%s\t%ld\t%s\t%s\n", sover->board, filename, group, mtime, FROM, sover->subject); + fflush(nl->feedfp); + flock(fileno(nl->feedfp), LOCK_UN); + } + } + if (savech == '\0') + break; + } +} + + +#ifndef MapleBBS +save_article(board, filename, sover) + char *board, *filename; + soverview_t *sover; +{ + FILE *FN; + + if (Verbose) + printf("<save_article> %s %s\n", board, filename); + FN = fopen(fileglue("%s/boards/%s/%s", BBSHOME, board, filename), "w"); + if (FN == NULL) + { + bbslog("<save_article> err: %s %s\n", board, filename); + if (Verbose) + printf("<save_article> err: %s %s\n", board, filename); + return 0; + } + flock(fileno(FN), LOCK_EX); + fprintf(FN, "發信人: %s, 信區: %s\n", POSTER, sover->board); + fprintf(FN, "標 題: %s\n", sover->subject); + fprintf(FN, "發信站: %s (%s)\n", MYSITE, sover->date); + fprintf(FN, "轉信站: %s\n", sover->path); + fprintf(FN, "\n"); + fputs(BODY, FN); + flock(fileno(FN), LOCK_UN); + fclose(FN); + +#if defined(PalmBBS) + { + struct utimbuf times; + + times.actime = sover->mtime; + times.modtime = sover->mtime; + utime(fileglue("%s/boards/%s/%s", BBSHOME, board, filename), ×); + utime(fileglue("%s/.bcache/%s", BBSHOME, board), NULL); + } +#endif +} +#endif + +/* process_article() read_article() save_outgoing() save_article() */ + +process_article(board, filename, userid, nickname, subject) + char *board, *filename, *userid, *nickname, *subject; +{ + char *n, *filepath; + char poster[MAXBUFLEN]; + soverview_t sover; + + if (!*userid) + { + return; + } + else if (!subject || !*subject) + { + subject = "無題"; + } + filepath = fileglue("%s/boards/%s/%s", BBSHOME, board, filename); + if (isfile(filepath)) + { + linkoverview_t lover; + + if (read_article(&lover, filepath, userid)) + { + +#ifndef MapleBBS + strncpy(POSTER_BUF, fileglue("%s@%s (%s)", userid, MYBBSID, nickname), sizeof POSTER_BUF); + POSTER = POSTER_BUF; +#endif + + strncpy(FROM_BUF, fileglue("%s.bbs@%s (%s)", userid, MYADDR, nickname), sizeof FROM_BUF); + FROM = FROM_BUF; + sover.from = FROM; + sover.board = board; + sover.subject = subject; + PATH = MYBBSID; + sover.path = MYBBSID; + sover.date = lover.date; + sover.mtime = lover.mtime; + if (!VisitOnly) + { + save_outgoing(&sover, filename, userid, poster, lover.mtime); + +#ifndef MapleBBS + save_article(board, filename, &sover); +#endif + } + } + } +} + + +char * +baseN(val, base, len) + int val, base, len; +{ + int n, ans; + static char str[MAXBUFLEN]; + char *pstr = str; + int index; + + for (index = len - 1; index >= 0; index--) + { + n = val % base; + val /= base; + if (n < 10) + { + n += '0'; + } + else if (n < 36) + { + n += 'A' - 10; + } + else if (n < 62) + { + n += 'a' - 36; + } + else + { + n = '_'; + } + str[index] = n; + } + str[len] = '\0'; + return str; +} + +char * +hash_value(str) + char *str; +{ + int val, n; + char *ptr; + + if (*str) + ptr = str + strlen(str) - 1; + else + ptr = str; + val = 0; + while (ptr >= str) + { + n = *ptr; + val = (val + n * 0x100) ^ n; + ptr--; + } + return baseN(val, 64, 3); +} + +/* process_cancel() save_outgoing() hash_value(); baseN(); ascii_date(); */ + + +read_outgoing(sover) + soverview_t *sover; +{ + char *board, *filename, *group, *from, *subject, *outgoingtype, *msgid, *path; + char *buffer, *bufferp; + FILE *ECHOMAIL, *FN; + char *hash; + char times[MAXBUFLEN]; + time_t mtime; + + board = sover->board; + filename = sover->filename; + group = sover->group; + mtime = sover->mtime; + from = sover->from; + subject = sover->subject; + outgoingtype = sover->outgoingtype; + msgid = sover->msgid; + path = sover->path; + if (Verbose) + { + printf("<read_outgoing> %s:%s:%s\n", board, filename, group); + printf(" => %ld:%s\n", mtime, from); + printf(" => %s\n", subject); + printf(" => %s:%s\n", outgoingtype, msgid); + printf(" => %s\n", path); + } + if (NEWSFEED == LOCAL) + { + char *end = strrchr(filename, '.'); + + if (end) + *end = '\0'; + strncpy(times, baseN(atol(filename + 2), 48, 6), sizeof times); + if (end) + *end = '.'; + hash = hash_value(fileglue("%s.%s", filename, board)); + sprintf(MSGID_BUF, "%s$%s@%s", times, hash, MYADDR); + } + else + { + strncpy(MSGID_BUF, msgid, sizeof MSGID_BUF); + } + sover->msgid = MSGID; + if (mtime == -1) + { + static char BODY_BUF[MAXBUFLEN]; + + strncpy(BODY_BUF, fileglue("%s\r\n", subject), sizeof BODY_BUF); + BODY = BODY_BUF; + sprintf(SUBJECT_BUF, "cmsg cancel <%s>", MSGID); + SUBJECT = SUBJECT_BUF; + sprintf(CONTROL_BUF, "cancel <%s>", MSGID); + CONTROL = CONTROL_BUF; + strncpy(MSGID_BUF, fileglue("%d.%s", getpid(), MSGID_BUF), sizeof MSGID_BUF); + sprintf(DATE_BUF, "%s", ascii_date(time(NULL))); + DATE = DATE_BUF; + sover->subject = SUBJECT; + sover->control = CONTROL; + sover->msgid = MSGID; + sover->date = DATE; + } + else + { + sover->control = CONTROL; + sover->date = DATE_BUF; + DATE = DATE_BUF; + *CONTROL = '\0'; + sprintf(DATE, "%s", ascii_date((mtime))); + if (NEWSFEED == LOCAL && !NoAction) + { + SITE = MYSITE; + PATH = MYBBSID; + GROUPS = group; + +#ifndef MapleBBS + echomaillog(); +#endif + } + BODY = ""; + FD = open(fileglue("%s/boards/%s/%s", BBSHOME, board, filename), O_RDONLY); + if (FD < 0) + { + if (Verbose) + printf(" !! can't open %s/boards/%s/%s\n", BBSHOME, board, filename); + else + fprintf(stderr, "can't open %s/boards/%s/%s\n", BBSHOME, board, filename); + return -1; + } + + FD_SIZE = filesize(fileglue("%s/boards/%s/%s", BBSHOME, board, filename)); + if (FD_BUF == NULL) + { + FD_BUF = (char *) mymalloc(FD_SIZE + 1 + strlen(COMMENT)); + } + else + { + FD_BUF = (char *) myrealloc(FD_BUF, FD_SIZE + 1 + strlen(COMMENT)); + } + FD_END = FD_BUF + FD_SIZE; + *FD_END = '\0'; + read(FD, FD_BUF, FD_SIZE); + sprintf(FD_END, "%s", COMMENT); + FD_SIZE += strlen(COMMENT); + FD_END += strlen(COMMENT); + if (Verbose) + { + printf("<read in> %s/boards/%s/%s\n", BBSHOME, board, filename); + } + + *ORGANIZATION = '\0'; + *NEWSCONTROL = '\0'; + *NEWSAPPROVED = '\0'; + *NNTPHOST_BUF = '\0'; + NNTPHOST = NULL; + + for (buffer = FD_BUF, bufferp = strchr(buffer, '\n'); + buffer && *buffer; bufferp = strchr(buffer, '\n')) + { + if (bufferp) + *bufferp = '\0'; + if (*buffer == '\0') + { + break; + } + /* printf("get buffer %s\n", buffer); */ + if (NEWSFEED == REMOTE) + { + if (strncmp(buffer, "Date: ", 11) == 0) + { + strcpy(DATE_BUF, buffer + 11); + DATE = DATE_BUF; + } + else if (strncmp(buffer, "發信站: ", 8) == 0) + { + char *m, *n; + + m = strchr(buffer, '('); + n = strrchr(buffer, ')'); + if (m && n) + { + strncpy(DATE_BUF, m + 1, n - m - 1); + DATE_BUF[n - m - 1] = '\0'; + DATE = DATE_BUF; + strncpy(ORGANIZATION, buffer + 8, m - 8 - buffer - 1); + ORGANIZATION[m - 8 - buffer - 1] = '\0'; + } + } + else if (strncmp(buffer, "Control: ", 9) == 0) + { + strcpy(NEWSCONTROL, buffer + 9); + } + else if (strncmp(buffer, "Approved: ", 10) == 0) + { + strcpy(NEWSAPPROVED, buffer + 10); + } + else if (strncmp(buffer, "Origin: ", 8) == 0) + { + strcpy(NNTPHOST_BUF, buffer + 8); + NNTPHOST = NNTPHOST_BUF; + } + } + if (bufferp) + { + *bufferp = '\n'; + buffer = bufferp + 1; + } + else + { + break; + } + } + if (bufferp) + { + BODY = bufferp + 1; + } + else + BODY = ""; + if (bufferp) + for (buffer = bufferp + 1, bufferp = strchr(buffer, '\n'); + buffer && *buffer; bufferp = strchr(buffer, '\n')) + { + if (bufferp) + *bufferp = '\0'; + /* printf("get line (%s)\n", buffer); */ + /* if( strcmp(buffer,".")==0 ) { buffer[1]='.'; buffer[2]='\0'; } */ + if (NEWSFEED == REMOTE && + strncmp(NEWSCONTROL, "cancel", 5) == 0 && + strncmp(buffer, "------------------", 18) == 0) + { + break; + } + else if (strncmp(buffer, "◆ From: ", 9) == 0) + { + strcpy(NNTPHOST_BUF, buffer + 9); + NNTPHOST = NNTPHOST_BUF; + } + /* $BODY[ @BODY ] = "$_\r\n"; */ + if (bufferp) + { + *bufferp = '\n'; + buffer = bufferp + 1; + } + else + { + break; + } + } + /* # fprintf("BODY @BODY\n"; */ + close(FD); + } + return 0; +} + +#ifdef TEST +#endif + +openfeed(node) + nodelist_t *node; +{ + if (node->feedfp == NULL) + { + node->feedfp = fopen(fileglue("%s/%s.link", INNDHOME, node->node), "a"); + } +} + +queuefeed(node, textline) + nodelist_t *node; + char *textline; +{ + openfeed(node); + if (node->feedfp != NULL) + { + flock(fileno(node->feedfp), LOCK_EX); + fprintf(node->feedfp, "%s", textline); + fflush(node->feedfp); + flock(fileno(node->feedfp), LOCK_UN); + } +} + +post_article(node, site, sover, textline) + nodelist_t *node; + char *site; + soverview_t *sover; + char *textline; +{ + int status; + char *filename = sover->filename; + char *msgid = sover->msgid; + char *board = sover->board; + char *bodyp, *body; + + if (Verbose) + fprintf(stdout, "<post_article> %s %s %s\n", site, filename, msgid); + if (NoAction && Verbose) + { + printf(" ==>%s\n", sover->path); + printf(" ==>%s:%s\n", sover->from, sover->group); + printf(" ==>%s:%s\n", sover->subject, sover->date); + body = BODY; + bodyp = strchr(body, '\n'); + if (bodyp) + *bodyp = '\0'; + printf(" ==>%s\n", body); + if (bodyp) + *bodyp = '\n'; + if (bodyp) + { + body = bodyp + 1; + bodyp = strchr(body, '\n'); + if (bodyp) + *bodyp = '\0'; + printf(" ==>%s\n", body); + if (bodyp) + *bodyp = '\n'; + } + } + if (NoAction) + return 1; + if (NEWSFEED == REMOTE) + { + fprintf(NNTPwfp, "Path: %s\r\n", sover->path); + fprintf(NNTPwfp, "From: %s\r\n", sover->from); + fprintf(NNTPwfp, "Newsgroups: %s\r\n", sover->group); + fprintf(NNTPwfp, "Subject: %s\r\n", sover->subject); + /* # fprintf( NNTPwfp,"Post with subject ($subject)\n"); */ + fprintf(NNTPwfp, "Date: %s\r\n", sover->date); + if (*ORGANIZATION) + fprintf(NNTPwfp, "Organization: %s\r\n", ORGANIZATION); + fprintf(NNTPwfp, "Message-ID: <%s>\r\n", sover->msgid); + if (*NEWSCONTROL) + fprintf(NNTPwfp, "Control: %s\r\n", NEWSCONTROL); + if (*NEWSAPPROVED) + fprintf(NNTPwfp, "Approved: %s\r\n", NEWSAPPROVED); + } + else + { + fprintf(NNTPwfp, "Path: %s\r\n", MYBBSID); + fprintf(NNTPwfp, "From: %s\r\n", sover->from); + fprintf(NNTPwfp, "Newsgroups: %s\r\n", sover->group); + fprintf(NNTPwfp, "Subject: %s\r\n", sover->subject); + fprintf(NNTPwfp, "Date: %s\r\n", sover->date); + fprintf(NNTPwfp, "Organization: %s\r\n", MYSITE); + fprintf(NNTPwfp, "Message-ID: <%s>\r\n", sover->msgid); + fprintf(NNTPwfp, "X-Filename: %s/%s\r\n", sover->board, sover->filename); + } + if (NNTPHOST && *NNTPHOST && USEIHAVE) + fprintf(NNTPwfp, "NNTP-Posting-Host: %s\r\n", NNTPHOST); + else if (NNTPHOST && *NNTPHOST) + fprintf(NNTPwfp, "X-Auth-From: %s\r\n", NNTPHOST); + if (*CONTROL) + { + fprintf(NNTPwfp, "Control: %s\r\n", CONTROL); + } + fputs("\r\n", NNTPwfp); + for (body = BODY, bodyp = strchr(body, '\n'); + body && *body; bodyp = strchr(body, '\n')) + { + if (bodyp) + *bodyp = '\0'; + + fputs(body, NNTPwfp); + if (body[0] == '.' && body[1] == '\0') + fputs(".", NNTPwfp); + fputs("\r\n", NNTPwfp); + if (bodyp) + { + *bodyp = '\n'; + body = bodyp + 1; + } + else + { + break; + } + } + /* print "send out @BODY\n"; */ + status = tcpcommand("."); + /* 435 duplicated article 437 invalid header */ + + if (USEIHAVE) + { + if (status == 235) + { + if (NEWSFEED == LOCAL) + { + bbslog("Sendout <%s> from %s/%s\n", msgid, board, filename); + } + } + else if (status == 437 || status == 435) + { + bbslog("<bbslink> :Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid); + if (Verbose) + printf(":Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid); + return 0; + } + else + { + bbslog("<bbslink> :Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid); + if (Verbose) + printf(":Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid); + if (!strstr(tcpmessage(), "Article not posted")) + queuefeed(node, textline); + return 0; + } + } + else if (USEPOST) + { + if (status == 240) + { + bbslog("Sendout <%s> from %s/%s\n", msgid, board, filename); + } + else if (status == 437 || status == 435) + { + bbslog("<bbslink> :Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid); + if (Verbose) + printf(":Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid); + return 0; + } + else + { + bbslog("<bbslink> :Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid); + if (!strstr(tcpmessage(), "Article not posted")) + queuefeed(node, textline); + return 0; + } + } + else + { + if (status == 250) + { + bbslog("<bbslink> DATA Sendout <%s> from %s/%s\n", msgid, board, filename); + if (Verbose) + printf("<DATA Sendout> <%s> from %s/%s\n", msgid, board, filename); + } + else + { + bbslog("<bbslink> :Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid); + if (Verbose) + printf(":Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid); + if (!strstr(tcpmessage(), "Article not posted")) + queuefeed(node, textline); + return 0; + } + } + return 1; +} + +process_cancel(board, filename, userid, nickname, subject) + char *board, *filename, *userid, *nickname, *subject; +{ + time_t mtime; + soverview_t sover; + + if (!userid || !*userid) + { + return; + } + mtime = -1; + strncpy(FROM_BUF, fileglue("%s.bbs@%s (%s)", userid, MYADDR, nickname), sizeof FROM_BUF); + FROM = FROM_BUF; + sover.from = FROM; + sover.board = board; + sover.subject = subject; + PATH = MYBBSID; + sover.path = MYBBSID; + /* save_outgoing(&sover, filename, userid, poster, -1); */ + save_outgoing(&sover, filename, userid, userid, -1); +} + +open_link(hostname, hostprot, hostport) + char *hostname, *hostprot, *hostport; +{ + USEIHAVE = 1; + USEPOST = 0; + USEDATA = 0; + FEEDTYPE = ' '; + if (Verbose) + printf("<OPEN_link> %s %s %s\n", hostname, hostprot, hostport); + if (strncasecmp(hostprot, "IHAVE", 5) != 0) + { + USEIHAVE = 0; + USEPOST = 1; + if (strncasecmp(hostprot, "POST", 4) == 0) + { + USEPOST = 1; + } + else if (strncasecmp(hostprot, "DATA", 4) == 0) + { + USEPOST = 0; + USEDATA = 1; + } + } + + FEEDTYPE = hostname[0]; + if (!USEDATA) + { + char *atsign; + + if (FEEDTYPE == '-' || FEEDTYPE == '+') + { + hostname = hostname + 1; + } + atsign = strchr(hostname, '@'); + if (atsign != NULL) + { + hostname = atsign + 1; + } + if (!NoAction) + { + if (Verbose) + printf("<inetclient> %s %s\n", hostname, hostport); + if ((NNTP = inetclient(hostname, hostport, "tcp")) < 0) + { + bbslog("<bbslink> :Err: server %s %s error: cant connect\n", hostname, hostport); + if (Verbose) + printf(":Err: server %s %s error: cant connect\n", hostname, hostport); + return 0; + /* exit( 0 ); */ + /* return; */ + } + NNTPrfp = fdopen(NNTP, "r"); + NNTPwfp = fdopen(NNTP, "w"); + fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp); + if (atoi(NNTPbuffer) != 200) + { + bbslog("<bbslink> :Err: server error: %s", NNTPbuffer); + if (Verbose) + printf(":Err: server error: %s", NNTPbuffer); + return 0; + /* exit( 0 ); */ + } + } + else + { + if (Verbose) + printf("<inetclient> %s %s\n", hostname, hostport); + } + } + else + { + if (!NoAction) + { + if (Verbose) + printf("<inetclient> localhost %s\n", hostport); + if ((NNTP = inetclient("localhost", hostport, "tcp")) < 0) + { + bbslog("<bbslink> :Err: server %s port %s error: cant connect\n", hostname, hostport); + if (Verbose) + printf(":Err: server error: cant connect"); + return 0; + /* exit( 0 ); */ + /* return; */ + } + NNTPrfp = fdopen(NNTP, "r"); + NNTPwfp = fdopen(NNTP, "w"); + fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp); + if (strncmp(NNTPbuffer, "220", 3) != 0) + { + bbslog("<bbslink> :Err: server error: %s", NNTPbuffer); + if (Verbose) + printf(":Err: server error: %s", NNTPbuffer); + return 0; + /* exit( 0 ); */ + } + if (strncmp(NNTPbuffer, "220-", 4) == 0) + { + fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp); + } + } + else + { + if (Verbose) + printf("<inetclient> %s %s\n", hostname, hostport); + } + } + return 1; +} + +send_outgoing(node, site, hostname, sover, textline) + nodelist_t *node; + soverview_t *sover; + char *hostname, *site; + char *textline; +{ + int status; + char *board, *filepath, *msgid; + int returnstatus = 0; + + board = sover->board; + filepath = sover->filename; + msgid = sover->msgid; + + if (Verbose) + printf("<send_outgoing> %s:%s:%s:%s\n", site, board, filepath, msgid); + if (BODY != NULL && !NoAction) + { + if (USEIHAVE) + { +/* status = tcpcommand("IHAVE <%s>", msgid);*/ + char buf[80]; + sprintf(buf, "IHAVE <%s>", msgid); + status = tcpcommand(buf); + if (status == 335) + { + returnstatus = post_article(node, site, sover, textline); + } + else if (status == 435) + { + bbslog("<bbslink> :Warn: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid); + if (Verbose) + printf(":Warn: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid); + returnstatus = 0; + } + else + { + bbslog("<bbslink> :Err: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid); + if (Verbose) + printf(":Err: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid); + if (!strstr(tcpmessage(), "Article not posted")) + queuefeed(node, textline); + returnstatus = 0; + } + } + else if (USEPOST) + { + tcpcommand("MODE READER"); + status = tcpcommand("POST"); + if (status == 340) + { + returnstatus = post_article(node, site, sover, textline); + } + else if (status == 441) + { + bbslog("<bbslink> :Warn: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid); + if (Verbose) + printf(":Warn: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid); + returnstatus = 0; + } + else + { + bbslog("<bbslink> :Err: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid); + if (Verbose) + printf(":Err: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid); + if (!strstr(tcpmessage(), "Article not posted")) + queuefeed(node, textline); + returnstatus = 0; + } + } + else + { + tcpcommand("HELO"); + tcpcommand("MAIL FROM: bbs"); + tcpcommand("RCPT TO: %s", hostname); + status = tcpcommand("DATA"); + if (status == 354) + { + returnstatus = post_article(node, site, sover, textline); + } + else + { + bbslog("<bbslink> :Err: %d %s, DATA <%s>\n", status, (char *) tcpmessage(), msgid); + if (Verbose) + printf(":Err: %d %s, DATA <%s>\n", status, (char *) tcpmessage(), msgid); + if (!strstr(tcpmessage(), "Article not posted")) + queuefeed(node, textline); + returnstatus = 0; + } + } + } + else if (NoAction) + { + returnstatus = post_article(node, site, sover, textline); + } + return returnstatus; +} + +save_nntplink(node, overview) + nodelist_t *node; + char *overview; +{ + FILE *POSTS; + char buffer[1024]; + + openfeed(node); + POSTS = fopen(overview, "r"); + if (POSTS == NULL) + return 0; + openfeed(node); + /* if (node->feedfp == NULL) return 0; */ + flock(fileno(node->feedfp), LOCK_EX); + while (fgets(buffer, sizeof buffer, POSTS) != NULL) + { + fputs(buffer, node->feedfp); + fflush(node->feedfp); + } + flock(fileno(node->feedfp), LOCK_UN); + fclose(POSTS); + if (Verbose) + printf("<Unlinking> %s\n", overview); + if (!NoAction) + unlink(overview); + return 1; +} + + +char * +get_tmpfile(tmpfile) + char *tmpfile; +{ + FILE *FN; + static char result[256]; + + FN = fopen(tmpfile, "r"); + fgets(result, sizeof result, FN); + fclose(FN); + unlink(tmpfile); + return (result); +} + +/* cancel moderating posts */ + +cancel_outgoing(board, filename, from, subject) + char *board, *filename, *from, *subject; +{ + char *base, filepath[MAXPATHLEN]; + FILE *FN; + char *result; + char TMPFILE[MAXPATHLEN]; + + if (Verbose) + { + printf("<cancel_outgoing> %s %s %s %s\n", board, filename, from, subject); + } + + sprintf(TMPFILE, "/tmp/cancel_outgoing.%d.%d", getuid(), getpid()); + + bbslog("<cancel_outgoing> Try to move moderated post from %s to deleted\n", board); + if (Verbose) + printf("Try to move moderated post from %s to deleted\n", board); + FN = popen(fileglue("%s/bbspost post %s/boards/deleted > %s", + INNDHOME, BBSHOME, TMPFILE), "w"); + if (FN == NULL) + { + bbslog("<cancel_outgoing> can't run %s/bbspost\n", INNDHOME); + if (Verbose) + printf("<cancel_outgoing> can't run %s/bbspost\n", INNDHOME); + return 0; + } + fprintf(FN, "%s\n", from); + fprintf(FN, "%s\n", subject); + fprintf(FN, "發信人: %s, 信區: %s\n", from, board); + fprintf(FN, "標 題: %s\n", subject); + fprintf(FN, "發信站: %s (%s)\n", MYSITE, DATE); + fprintf(FN, "轉信站: %s\n", MYBBSID); + fputs("\n", FN); + fputs(BODY, FN); + pclose(FN); + result = (char *) get_tmpfile(TMPFILE); + if (strncmp(result, "post to ", 8) == 0) + { + /* try to remove it */ + strncpy(filepath, fileglue("%s/boards/%s/%s", BBSHOME, board, filename), sizeof filepath); + if (isfile(filepath)) + { + Rename(filepath, fileglue("%s.cancel", filepath)); + } + FN = fopen(filepath, "w"); + + fprintf(FN, "發信人: %s, 信區: %s\n", from, board); + fprintf(FN, "標 題: <article cancelled and mailed to the moderator\n"); + fprintf(FN, "發信站: %s (%s)\n", MYSITE, DATE); + fprintf(FN, "轉信站: %s\n", MYBBSID); + fprintf(FN, "\n"); + fputs("\n", FN); + fprintf(FN, "你的文章 \"%s\" 已經送往審核中. 請等待回覆.\n", subject); + fputs("\n", FN); + fputs("Your post has been sent to the moderator and move\n", FN); + fputs("into the deleted board. If the post accepted by the moderator,\n", FN); + fputs("it will be posted in this board again. Please wait.\n", FN); + + } + else + { + bbslog("%s", result); + } + + bbslog("%s/bbspost cancel %s %s %s moderate\n", INNDHOME, BBSHOME, board, filename); + if (Verbose) + printf("%s/bbspost cancel %s %s %s moderate\n", INNDHOME, BBSHOME, board, filename); + system(fileglue("%s/bbspost cancel %s %s %s moderate", + INNDHOME, BBSHOME, board, filename)); + return 1; +} + +/* + * send_nntplink open_link read_outgoing send_outgoing post_article + * cancel_outgoing + */ +send_nntplink(node, site, hostname, hostprot, hostport, overview, nlcount) + nodelist_t *node; + char *site, *hostname, *hostprot, *hostport, *overview; + int nlcount; +{ + FILE *POSTS; + char textline[1024]; + char baktextline[1024]; + char *filepath; + int status; + + if (Verbose) + { + printf("<send nntplink> %s %s %s %s\n", site, hostname, hostprot, hostport); + printf(" ==> %s\n", overview); + } + if (!open_link(hostname, hostprot, hostport)) + { + save_nntplink(node, overview); + return 0; + } + POSTS = fopen(overview, "r"); + if (POSTS == NULL) + { + if (Verbose) + printf("open %s failed\n", overview); + return 0; + } + while (fgets(textline, sizeof textline, POSTS) != NULL) + { + char *linebreak = strchr(textline, '\n'); + char *ptr; + char *board, *filename, *subject, *group, *mtime, *from; + char *outgoingtype; + char *msgid, *path; + soverview_t soverview; + + strcpy(baktextline, textline); + if (linebreak) + *linebreak = '\0'; + + board = "", filename = "", mtime = "", group = "", from = "", subject = ""; + outgoingtype = "", msgid = "", path = ""; + /* get board field */ + board = textline; + ptr = strchr(textline, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* filename field */ + filename = ptr; + + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + + *ptr++ = '\0'; + + /* group field */ + group = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* mtime field */ + mtime = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* from field */ + from = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* subject */ + subject = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + goto try_read_outgoing; + *ptr++ = '\0'; + + /* outgoing type field */ + outgoingtype = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + goto try_read_outgoing; + *ptr++ = '\0'; + + /* msgid */ + msgid = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + goto try_read_outgoing; + *ptr++ = '\0'; + + /* path */ + path = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + goto try_read_outgoing; + +try_read_outgoing: + + NEWSFEED = LOCAL; + if (outgoingtype && msgid && path && *outgoingtype && *msgid && *path) + { + char *left, *right; + + NEWSFEED = REMOTE; + left = strchr(msgid, '<'); + right = strrchr(msgid, '>'); + if (left) + msgid = left + 1; + if (right) + *right = '\0'; + } + soverview.board = board; + soverview.filename = filename; + soverview.group = group; + soverview.mtime = atol(mtime); + soverview.from = from; + soverview.subject = subject; + soverview.outgoingtype = outgoingtype; + soverview.msgid = msgid; + soverview.path = path; + if (read_outgoing(&soverview) == 0) + { + int sendresult = send_outgoing(node, site, hostname, &soverview, baktextline); + int sendfailed = 1 - sendresult; + + if (NEWSFEED == REMOTE) + { + BBSLINK_STAT[nlcount].remotesendout += sendresult; + BBSLINK_STAT[nlcount].remotefailed += sendfailed; + } + else + { + BBSLINK_STAT[nlcount].localsendout += sendresult; + BBSLINK_STAT[nlcount].localfailed += sendfailed; + } + if (node->feedtype == '-') + { + if (!NoAction && sendresult) + cancel_outgoing(board, filename, from, subject); + } + } + } + fclose(POSTS); + close_link(); + if (Verbose) + printf("<Unlinking> %s\n", overview); + if (!NoAction) + unlink(overview); +} + +close_link() +{ + int status; + + if (Verbose) + printf("<close_link>\n"); + if (NoAction) + return; + status = tcpcommand("QUIT"); + if (status != 205 && status != 221) + { + bbslog("<bbslink> :Err: Cannot quit message '%d %s'\n", status, (char *) tcpmessage()); + if (Verbose) + printf(":Err: Cannot quit message '%d %s'\n", status, (char *) tcpmessage()); + } + fclose(NNTPwfp); + fclose(NNTPrfp); + close(NNTP); +} + + +/* + * send_article() send_nntplink() read_outgoing() + * + */ + +send_article() +{ + char *site, *addr, *protocol, *port, *op; + char *nntphost; + int nlcount; + + chdir(INNDHOME); + + for (nlcount = 0; nlcount < NLCOUNT; nlcount++) + { + nodelist_t *node; + char linkfile[MAXPATHLEN]; + char sendfile[MAXPATHLEN]; + char feedfile[MAXPATHLEN]; + char feedingfile[MAXPATHLEN]; + char protocol[MAXBUFLEN], port[MAXBUFLEN]; + + node = NODELIST + nlcount; + site = node->node; + nntphost = node->host; + op = node->protocol; + + if (DefaultFeedSite && *DefaultFeedSite) + { + if (strcmp(node->node, DefaultFeedSite) != 0) + continue; + } + + if (op && (strncasecmp(op, "ihave", 5) == 0 || + strncasecmp(op, "post", 4) == 0 || + strncasecmp(op, "data", 4) == 0)) + { + char *left, *right; + + left = strchr(op, '('), right = strrchr(op, ')'); + if (left && right) + { + *left = '\0'; + *right = '\0'; + strncpy(protocol, op, sizeof protocol); + strncpy(port, left + 1, sizeof port); + *left = '('; + *right = ')'; + } + else + { + strncpy(protocol, op, sizeof protocol); + strncpy(port, "nntp", sizeof port); + } + } + else + { + strcpy(protocol, "IHAVE"); + strcpy(port, "nntp"); + } + sprintf(linkfile, "%s.link", site); + sprintf(sendfile, "%s.sending", site); + sprintf(feedfile, "%s.feed", site); + sprintf(feedingfile, "%s.feeding", site); + if (isfile(sendfile) && !iszerofile(sendfile)) + { + if (bbslink_get_lock(sendfile)) + { + send_nntplink(node, site, nntphost, protocol, port, sendfile, nlcount); + bbslink_un_lock(sendfile); + } + } + if (isfile(linkfile) && !iszerofile(linkfile)) + { + if (!NoAction) + { + if (bbslink_get_lock(sendfile) && bbslink_get_lock(linkfile) && + bbslink_get_lock(feedingfile)) + { + if (isfile(sendfile) && !iszerofile(sendfile)) + { + save_nntplink(node, sendfile); + } + if (node->feedfp) + { + fclose(node->feedfp); + node->feedfp = NULL; + } + Rename(linkfile, sendfile); + send_nntplink(node, site, nntphost, protocol, port, sendfile, nlcount); + bbslink_un_lock(linkfile); + bbslink_un_lock(sendfile); + bbslink_un_lock(feedingfile); + } + } + else + { + send_nntplink(node, site, nntphost, protocol, port, linkfile, nlcount); + } + } + if (isfile(feedingfile) && !iszerofile(feedingfile)) + { + if (bbslink_get_lock(feedingfile)) + { + send_nntplink(node, site, nntphost, protocol, port, feedingfile, nlcount); + bbslink_un_lock(feedingfile); + } + } + if (isfile(feedfile) && !iszerofile(feedfile)) + { + if (!NoAction) + { + if (bbslink_get_lock(feedfile) && bbslink_get_lock(feedingfile)) + { + if (isfile(feedingfile) && !iszerofile(feedingfile)) + { + save_nntplink(node, feedingfile); + if (node->feedfp) + { + fclose(node->feedfp); + node->feedfp = NULL; + } + } + Rename(feedfile, feedingfile); + system(fileglue("%s/ctlinnbbsd reload > /dev/null", INNDHOME)); + send_nntplink(node, site, nntphost, protocol, port, feedingfile, nlcount); + bbslink_un_lock(feedfile); + bbslink_un_lock(feedingfile); + } + } + else + { + send_nntplink(node, site, nntphost, protocol, port, feedfile, nlcount); + } + } + } +} + +/* bntplink() bbspost() process_article() process_cancel() send_article() */ + + +show_usage(argv) + char *argv; +{ + fprintf(stderr, "%s initialization failed or improper options !!\n", argv); + fprintf(stderr, "Usage: %s [options] bbs_home\n", argv); + fprintf(stderr, " -v (show transmission status)\n"); + fprintf(stderr, " -n (dont send out articles and leave queue untouched)\n"); + fprintf(stderr, " -s site (only process articles sent to site)\n"); + fprintf(stderr, " -V (visit only: bbspost visit)\n"); + fprintf(stderr, " -N (no visit, and only process batch queue)\n"); + fprintf(stderr, " -k (kill the former bbslink process before started)\n\n"); + fprintf(stderr, "本程式要正常執行必須將以下檔案置於 %s/innd 下:\n", BBSHOME); + fprintf(stderr, "bbsname.bbs 設定貴站的 BBS ID (請儘量簡短)\n"); + fprintf(stderr, "nodelist.bbs 設定網路各 BBS 站的 ID, Address 和 fullname\n"); + fprintf(stderr, "newsfeeds.bbs 設定網路信件的 newsgroup board nodelist ...\n"); +} + + +bntplink(argc, argv) + int argc; + char **argv; +{ + static char *OUTING = ".outing"; + nodelist_t *nl; + int linkport; + char result[4096]; + char cancelfile[MAXPATHLEN], cancelpost[MAXPATHLEN]; + char bbslink_lockfile[MAXPATHLEN]; + FILE *NEWPOST; + char *left, *right; + int nlcount; + +// strcpy(BBSHOME, argv[0]); + if (initial_bbs("link") == 0) + { + return -1; + } + + BBSLINK_STAT = (stat_t *) malloc(sizeof(stat_t) * (NLCOUNT + 1)); + for (nlcount = 0; nlcount < NLCOUNT; nlcount++) + { + BBSLINK_STAT[nlcount].localsendout = 0; + BBSLINK_STAT[nlcount].remotesendout = 0; + BBSLINK_STAT[nlcount].localfailed = 0; + BBSLINK_STAT[nlcount].remotefailed = 0; + } + + nl = (nodelist_t *) search_nodelist_bynode(MYBBSID); + if (nl == NULL) + { + *MYADDR = '\0'; + *MYSITE = '\0'; + *LINKPROTOCOL = '\0'; + } + else + { + strncpy(MYADDR, nl->host, sizeof MYADDR); + strncpy(LINKPROTOCOL, nl->protocol, sizeof LINKPROTOCOL); + strncpy(MYSITE, nl->comments, sizeof MYSITE); + } + if (Verbose) + { + printf("MYADDR: %s\n", MYADDR); + printf("MYSITE: %s\n", MYSITE); + } + left = strchr(nl->protocol, '('); + right = strrchr(nl->protocol, ')'); + if (left && right) + { + *right = '\0'; + strncpy(LINKPROTOCOL, nl->protocol, sizeof LINKPROTOCOL); + LINKPORT = atoi(left + 1); + *right = ')'; + } + + if (!NoVisit) + { + sprintf(bbslink_lockfile, "%s/.bbslink.visit", INNDHOME); + if (!Rename(fileglue("%s/out.bntp", INNDHOME), OUTING) && bbslink_get_lock(bbslink_lockfile)) + { + /* When try to visit new post, try to lock it */ + NEWPOST = fopen(OUTING, "r"); + if (NEWPOST == NULL) + { + bbslog("<bbslink> Err: can't open %s\n", OUTING); + bbslink_un_lock(bbslink_lockfile); + return -1; + } + while (fgets(result, sizeof result, NEWPOST)) + { + /* chop( $_ ); */ + char *board, *filename, *userid, *nickname, *subject; + char *ptr; + + ptr = strchr(result, '\n'); + if (ptr) + *ptr = '\0'; + + board = filename = userid = nickname = subject = NULL; + /* board field */ + board = result; + ptr = strchr(result, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* filename field */ + filename = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* userid field */ + userid = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* nickname field */ + nickname = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* subject field */ + subject = ptr; + /* ptr = strchr(ptr, '\t'); if (ptr == NULL) continue; ptr++ = '\0'; */ + + if(bad_subject(subject)) continue; + + if(outgo_post < MAX_OUTGO_POST){ + out_bntp[outgo_post].board = board; + out_bntp[outgo_post].filename = filename; + out_bntp[outgo_post].userid = userid; + out_bntp[outgo_post].nickname = nickname; + out_bntp[outgo_post].subject = subject; + outgo_post++; + } + + process_article(board, filename, userid, nickname, subject); + } + fclose(NEWPOST); + unlink(OUTING); + bbslink_un_lock(bbslink_lockfile); + } /* getlock */ + } /* if NoVisit is false */ + + sprintf(cancelpost, "%s/cancel.bntp", INNDHOME); + if (isfile(cancelpost)) + { + FILE *CANCELFILE; + + if (bbslink_get_lock(cancelpost) && bbslink_get_lock(cancelfile)) + { + sprintf(cancelfile, "%s.%d", cancelpost, getpid()); + Rename(cancelpost, cancelfile); + CANCELFILE = fopen(cancelfile, "r"); + while (fgets(result, sizeof result, CANCELFILE) != NULL) + { + /* chop( $_ ); */ + char *board, *filename, *userid, *nickname, *subject; + char *ptr, **sptr; + + ptr = strchr(result, '\n'); + if (ptr) + *ptr = '\0'; + board = filename = userid = nickname = subject = NULL; + + /* board field */ + board = result; + ptr = strchr(result, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* filename field */ + filename = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* userid field */ + userid = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* nickname field */ + nickname = ptr; + ptr = strchr(ptr, '\t'); + if (ptr == NULL) + continue; + *ptr++ = '\0'; + + /* subject field */ + subject = ptr; + /* ptr = strchr(ptr, '\t'); if (ptr == NULL) continue; ptr++ = '\0'; */ + if(!is_outgo_post(board, filename, userid, nickname, subject)) + process_cancel(board, filename, userid, nickname, subject); + } + fclose(CANCELFILE); + if (Verbose) + printf("Unlinking %s\n", cancelfile); + if (!NoAction) + unlink(cancelfile); + bbslink_un_lock(cancelfile); + bbslink_un_lock(cancelpost); + } + } + + for (nlcount = 0; nlcount < NLCOUNT; nlcount++) + { + if (NODELIST[nlcount].feedfp != NULL) + { + fclose(NODELIST[nlcount].feedfp); + NODELIST[nlcount].feedfp = NULL; + } + } + + send_article(); + for (nlcount = 0; nlcount < NLCOUNT; nlcount++) + { + int localsendout, remotesendout, localfailed, remotefailed; + + localsendout = BBSLINK_STAT[nlcount].localsendout; + remotesendout = BBSLINK_STAT[nlcount].remotesendout; + localfailed = BBSLINK_STAT[nlcount].localfailed; + remotefailed = BBSLINK_STAT[nlcount].remotefailed; + if (localsendout || remotesendout || localfailed || remotefailed) + bbslog("<bbslink> [%s]%s lsend:%d rsend:%d lfail:%d rfail:%d\n", + NODELIST[nlcount].node, NoAction ? "NoAction" : "", localsendout, remotesendout, + localfailed, remotefailed); + if (NODELIST[nlcount].feedfp != NULL) + { + fclose(NODELIST[nlcount].feedfp); + NODELIST[nlcount].feedfp = NULL; + } + } + if (BBSLINK_STAT); + free(BBSLINK_STAT); + return 0; +} +/* +termbbslink(sig) + int sig; +{ + bbslog("kill signal received %d, terminated\n", sig); + if (Verbose) + printf("kill signal received %d, terminated\n", sig); + exit(0); +} +*/ +void +termbbslink() +{ + bbslog("kill signal received ??, terminated\n"); + if (Verbose) + printf("kill signal received ??, terminated\n"); + exit(0); +} + +char *REMOTEUSERNAME = ""; +char *REMOTEHOSTNAME = ""; + +extern char *optarg; +extern int opterr, optind; + +main(argc, argv) + int argc; + char **argv; +{ + int c, errflag = 0; + + CONTROL = CONTROL_BUF; + MSGID = MSGID_BUF; + + /* For debug Only */ +#define DEBUGBBSLINK + +#ifdef DEBUGBBSLINK + NoAction = 0; + Verbose = 0; + VisitOnly = 0; + NoVisit = 0; + DefaultFeedSite = ""; +#endif + + while ((c = getopt(argc, argv, "s:hnvVNk")) != -1) + switch (c) + { + case 's': + DefaultFeedSite = optarg; + break; + case 'n': + NoAction = 1; + break; + case 'v': + Verbose = 1; + break; + case 'V': + VisitOnly = 1; + break; + case 'N': + NoVisit = 1; + break; + case 'k': + KillFormerBBSLINK = 1; + break; + case 'h': + default: + errflag++; + break; + } + if (errflag > 0) + { + show_usage(argv[0]); + return (1); + } + if (argc - optind < 1) + { + show_usage(argv[0]); + exit(1); + } + signal(SIGTERM, termbbslink); + if (bntplink(argc - optind, argv + optind) != 0) + { + show_usage(argv[0]); + exit(1); + } + return 0; +} |