/*
* BBS implementation dependendent part
*
* The only two interfaces you must provide
*
* #include "inntobbs.h" int receive_article(); 0 success not 0 fail
*
* if (storeDB(HEADER[MID_H], hispaths) < 0) { .... fail }
*
* int cancel_article_front( char *msgid ); 0 success not 0 fail
*
* char *ptr = (char*)DBfetch(msgid);
*
* 收到之文章內容 (body)在 char *BODY, 檔頭 (header)在 char *HEADER[] SUBJECT_H,
* FROM_H, DATE_H, MID_H, NEWSGROUPS_H, NNTPPOSTINGHOST_H, NNTPHOST_H,
* CONTROL_H, PATH_H, ORGANIZATION_H
*/
/*
* Sample Implementation
*
* receive_article() --> post_article() --> bbspost_write_post();
* cacnel_article_front(mid) --> cancel_article() --> bbspost_write_cancel();
*/
#include "bbs.h"
#include "externs.h"
#include <stdlib.h>
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE /* glibc2 needs this */
#endif
#include <time.h>
#ifndef PowerBBS
#include "innbbsconf.h"
#include "daemon.h"
#include "bbslib.h"
#include "inntobbs.h"
#include "antisplam.h"
#include "his.h"
extern int Junkhistory;
char *post_article ARG((char *, char *, char *, int (*) (), char *, char *));
int cancel_article ARG((char *, char *, char *));
#ifdef MapleBBS
#include "config.h"
#include "pttstruct.h"
#define _BBS_UTIL_C_
#else
report()
{
/* Function called from record.o */
/* Please leave this function empty */
}
#endif
#if defined(PalmBBS)
#ifndef PATH
#define PATH XPATH
#endif
#ifndef HEADER
#define HEADER XHEADER
#endif
#endif
/* process post write */
int
bbspost_write_post(fh, board, filename)
int fh;
char *board;
char *filename;
{
char *fptr, *ptr;
FILE *fhfd = fdopen(fh, "w");
if (fhfd == NULL) {
bbslog("can't fdopen, maybe disk full\n");
return -1;
}
fprintf(fhfd, "發信人: %.60s, 看板: %s\n", FROM, board);
fprintf(fhfd, "標 題: %.70s\n", SUBJECT);
fprintf(fhfd, "發信站: %.43s (%s)\n", SITE, DATE);
fprintf(fhfd, "轉信站: %.70s\n", PATH);
#ifndef MapleBBS
if (POSTHOST != NULL) {
fprintf(fhfd, "Origin: %.70s\n", POSTHOST);
}
#endif
fprintf(fhfd, "\n");
for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r')) {
int ch = *ptr;
*ptr = '\0';
fputs(fptr, fhfd);
*ptr = ch;
}
fputs(fptr, fhfd);
fflush(fhfd);
fclose(fhfd);
return 0;
}
#ifdef KEEP_NETWORK_CANCEL
/* process cancel write */
bbspost_write_cancel(fh, board, filename)
int fh;
char *board, *filename;
{
char *fptr, *ptr;
FILE *fhfd = fdopen(fh, "w"), *fp;
char buffer[256];
if (fhfd == NULL) {
bbslog("can't fdopen, maybe disk full\n");
return -1;
}
fprintf(fhfd, "發信人: %s, 信區: %s\n", FROM, board);
fprintf(fhfd, "標 題: %s\n", SUBJECT);
fprintf(fhfd, "發信站: %.43s (%s)\n", SITE, DATE);
fprintf(fhfd, "轉信站: %.70s\n", PATH);
if (HEADER[CONTROL_H] != NULL) {
fprintf(fhfd, "Control: %s\n", HEADER[CONTROL_H]);
}
if (POSTHOST != NULL) {
fprintf(fhfd, "Origin: %s\n", POSTHOST);
}
fprintf(fhfd, "\n");
for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r')) {
int ch = *ptr;
*ptr = '\0';
fputs(fptr, fhfd);
*ptr = ch;
}
fputs(fptr, fhfd);
if (POSTHOST != NULL) {
fprintf(fhfd, "\n * Origin: ● %.26s ● From: %.40s\n", SITE, POSTHOST);
}
fprintf(fhfd, "\n---------------------\n");
fp = fopen(filename, "r");
if (fp == NULL) {
bbslog("can't open %s\n", filename);
return -1;
}
while (fgets(buffer, sizeof buffer, fp) != NULL) {
fputs(buffer, fhfd);
}
fclose(fp);
fflush(fhfd);
fclose(fhfd);
{
fp = fopen(filename, "w");
if (fp == NULL) {
bbslog("can't write %s\n", filename);
return -1;
}
fprintf(fp, "發信人: %s, 信區: %s\n", FROM, board);
fprintf(fp, "標 題: %.70s\n", SUBJECT);
fprintf(fp, "發信站: %.43s (%s)\n", SITE, DATE);
fprintf(fp, "轉信站: %.70s\n", PATH);
if (POSTHOST != NULL) {
fprintf(fhfd, "Origin: %s\n", POSTHOST);
}
if (HEADER[CONTROL_H] != NULL) {
fprintf(fhfd, "Control: %s\n", HEADER[CONTROL_H]);
}
fprintf(fp, "\n");
for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r')) {
*ptr = '\0';
fputs(fptr, fp);
}
fputs(fptr, fp);
if (POSTHOST != NULL) {
fprintf(fp, "\n * Origin: ● %.26s ● From: %.40s\n", SITE, POSTHOST);
}
fclose(fp);
}
return 0;
}
#endif
int
bbspost_write_control(fh, board, filename)
int fh;
char *board;
char *filename;
{
char *fptr, *ptr;
FILE *fhfd = fdopen(fh, "w");
if (fhfd == NULL) {
bbslog("can't fdopen, maybe disk full\n");
return -1;
}
fprintf(fhfd, "Path: %s!%s\n", MYBBSID, HEADER[PATH_H]);
fprintf(fhfd, "From: %s\n", FROM);
fprintf(fhfd, "Newsgroups: %s\n", GROUPS);
fprintf(fhfd, "Subject: %s\n", SUBJECT);
fprintf(fhfd, "Date: %s\n", DATE);
fprintf(fhfd, "Organization: %s\n", SITE);
if (POSTHOST != NULL) {
fprintf(fhfd, "NNTP-Posting-Host: %.70s\n", POSTHOST);
}
if (HEADER[CONTROL_H] != NULL) {
fprintf(fhfd, "Control: %s\n", HEADER[CONTROL_H]);
}
if (HEADER[APPROVED_H] != NULL) {
fprintf(fhfd, "Approved: %s\n", HEADER[APPROVED_H]);
}
if (HEADER[DISTRIBUTION_H] != NULL) {
fprintf(fhfd, "Distribution: %s\n", HEADER[DISTRIBUTION_H]);
}
fprintf(fhfd, "\n");
for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r')) {
int ch = *ptr;
*ptr = '\0';
fputs(fptr, fhfd);
*ptr = ch;
}
fputs(fptr, fhfd);
fflush(fhfd);
fclose(fhfd);
return 0;
}
time_t datevalue;
/* process cancel write */
int
receive_article()
{
char *user, *userptr;
char *ngptr, *pathptr;
char **splitptr;
static char userid[32];
static char xdate[32];
static char xpath[180];
newsfeeds_t *nf;
char *boardhome;
char hispaths[4096];
char firstpath[PATHLEN], *firstpathbase;
char *lesssym, *nameptrleft, *nameptrright;
#ifdef HMM_USE_ANTI_SPAM
int i;
char *notitle[] =
{NULL},
*nofrom[] =
{NULL},
*nocont[] =
{"http://msi-team.com", "http://affluence.rithosts.net",
"http://www.fly-team.com", "http://fly-team.com",
"http://whymis.com", "http://www.msihk.com",
"http://Autopost.e8d8d.com", "http://www.e8d8d.com",
"http://whymsi.com", "httpwww.e8d8d.com", "http://freeway.163.to/",
"MSI團隊", "MSI系統", "MSI經營", "本訊息由AUTO POST發送",
"MSI團隊", "USANA", "http://uuu.to/ommplan",
"靠一份網路事業創業與加盟圓夢", "http://www.usanaomm.net",
"優莎娜MSI", "Robert G.Allen", "http://www.whyomm.cn",
"http://home.pchome.com.tw/store/deryes/",
"http://xyzoo.hkoo.net/", "mypiece.com/",
"【新舊歐盟醫學院招生】", "《台鹽多寶在家工作系統》",
"jin-hua@hotmail.com", "010-82330590", "http://www.s-bus.com",
"http://fone.4hk.cc/mkslk", "http://kiki.hkoo.net/fongy",
"http://myokay.nowgo.net/jojo/", "0911685648",
"http://digi.hkgo.cc/mile", "http://love520.hk852.cc/mytw",
"美容保養品公司USANA", "Robert G. Allen", "Multiple Streams of Income",
"http://www.twstars.com", "36005081", "3123835",
".hkgo.cc/", ".hk852.cc/", ".4hk.cc/", ".2hk.cc/", ".xdd.cc/",
".hkoo.net/", ".nowgo.net/", "http://www.taconet.com.tw/jscha/",
"www.ejiajia.net", "ufjt0356@ms9.hinet.net", "jt0356@yahoo.com.tw",
"http://www.IT-Test.Net", "http://uuu.to/", "greenhouse6688",
"http://www.s-bus.com", "http://goods.sytes.net/", ".uni.cc/",
"http://www.1-care.com", "美商優莎納生技公司", "Http://www.It-Test.Net",
"http://home.pchome.com.tw/happy/eykk6767/", "http://www.agelopp.com/",
"http://www.togetrich.net", "http://www.newchance.ligsystem.com/",
"jimtist@yahoo.com", "http://fleamarket.mine.nu", "http://e-car.mine.nu",
"漂亮美媚", "超 多 美 眉", "漂亮妹妹", "http://%6F",
".mini.to/", "-------- ### --------", "babylove.24cc.cc",
"This is a multi-part message in MIME format.",
"OCAgIFNreXBlOmp1bnNreWVwCg==", "ooqq.bbs@bbs.wretch.cc",
"http://jsvcd.3cc.cc", "http://bestgirl.mytw.net", "http://98.to/",
"http://www.boss888.net", "amuro.bbs@bbs.csie.nctu.edu.tw",
"http://www.whymsi.com", "http://www.msi-team.com/", NULL};
#endif
if (FROM == NULL) {
bbslog(":Err: article without usrid %s\n", MSGID);
return 0;
} else {
#ifdef HMM_USE_ANTI_SPAM
for (i = 0; nofrom[i]; i++)
if (strstr(FROM, nofrom[i])) {
bbslog(":Ptt: spam from [%s]: %s\n", nofrom[i], FROM);
return 0;
}
#endif
}
if (!BODY) {
bbslog(":Err: article without body %s\n", MSGID);
return 0;
} else {
#ifdef HMM_USE_ANTI_SPAM
for (i = 0; nocont[i]; i++)
if (strstr(BODY, nocont[i])) {
bbslog(":Ptt: spam body: %s\n", nocont[i]);
return 0;
}
#endif
}
if (!SUBJECT) {
bbslog(":Err: article without subject %s\n", MSGID);
return 0;
} else {
#ifdef HMM_USE_ANTI_SPAM
for (i = 0; notitle[i]; i++)
if (strstr(SUBJECT, notitle[i])) {
bbslog(":Ptt: spam title [%s]: %s\n", notitle[i], SUBJECT);
return 0;
}
#endif
}
user = (char *)strchr(FROM, '@');
lesssym = (char *)strchr(FROM, '<');
nameptrleft = NULL, nameptrright = NULL;
if (lesssym == NULL || lesssym >= user) {
lesssym = FROM;
nameptrleft = strchr(FROM, '(');
if (nameptrleft != NULL)
nameptrleft++;
nameptrright = strrchr(FROM, ')');
} else {
nameptrleft = FROM;
nameptrright = strrchr(FROM, '<');
lesssym++;
}
if (user != NULL) {
*user = '\0';
userptr = (char *)strchr(FROM, '.');
if (userptr != NULL) {
*userptr = '\0';
strncpy(userid, lesssym, sizeof userid);
*userptr = '.';
} else {
strncpy(userid, lesssym, sizeof userid);
}
*user = '@';
} else {
strncpy(userid, lesssym, sizeof userid);
}
strcat(userid, ".");
{
struct tm tmbuf;
/* RFC-1036 says the second format is the correct one. But we keep
* the first format for backward compatible.
*/
if (strptime(DATE, "%d %b %Y %X ", &tmbuf) != NULL)
datevalue = timegm(&tmbuf);
else if (strptime(DATE, "%a, %d %b %Y %X ", &tmbuf) != NULL)
datevalue = timegm(&tmbuf);
else
datevalue = -1;
}
if (datevalue > 0) {
char *p;
strncpy(xdate, ctime(&datevalue), sizeof(xdate));
p = (char *)strchr(xdate, '\n');
if (p != NULL)
*p = '\0';
DATE = xdate;
}
#ifndef MapleBBS
if (SITE == NULL || *SITE == '\0') {
if (nameptrleft != NULL && nameptrright != NULL) {
char savech = *nameptrright;
*nameptrright = '\0';
strncpy(sitebuf, nameptrleft, sizeof sitebuf);
*nameptrright = savech;
SITE = sitebuf;
} else
/* SITE = "(Unknown)"; */
SITE = "";
}
if (strlen(MYBBSID) > 70) {
bbslog(" :Err: your bbsid %s too long\n", MYBBSID);
return 0;
}
#endif
sprintf(xpath, "%s!%.*s", MYBBSID, (int)(sizeof(xpath) - strlen(MYBBSID) - 2), PATH);
PATH = xpath;
for (pathptr = PATH; pathptr != NULL && (pathptr = strstr(pathptr, ".edu.tw")) != NULL;) {
if (pathptr != NULL) {
strcpy(pathptr, pathptr + 7);
}
}
xpath[71] = '\0';
#ifndef MapleBBS
echomaillog();
#endif
*hispaths = '\0';
splitptr = (char **)BNGsplit(GROUPS);
firstpath[0] = '\0';
firstpathbase = firstpath;
for (ngptr = *splitptr; ngptr != NULL; ngptr = *(++splitptr)) {
char *boardptr, *nboardptr;
if (*ngptr == '\0')
continue;
nf = (newsfeeds_t *) search_group(ngptr);
if (nf == NULL) {
bbslog("unwanted \'%s\'\n", ngptr);
continue;
}
if (nf->board == NULL || !*nf->board)
continue;
if (nf->path == NULL || !*nf->path)
continue;
for (boardptr = nf->board, nboardptr = (char *)strchr(boardptr, ','); boardptr != NULL && *boardptr != '\0'; nboardptr = (char *)strchr(boardptr, ',')) {
if (nboardptr != NULL) {
*nboardptr = '\0';
}
if (*boardptr == '\t') {
goto boardcont;
}
boardhome = (char *)fileglue("%s/boards/%c/%s", BBSHOME, boardptr[0], boardptr);
if (!dashd(boardhome)) {
bbslog(":Err: unable to write %s\n", boardhome);
} else {
char *fname;
/*
* if ( !dashd( boardhome )) { bbslog( ":Err: unable to write
* %s\n",boardhome); testandmkdir(boardhome); }
*/
fname = (char *)post_article(boardhome, userid, boardptr,
bbspost_write_post, NULL, firstpath);
if (fname != NULL) {
fname = (char *)fileglue("%s/%s", boardptr, fname);
if (firstpath[0] == '\0') {
sprintf(firstpath, "%s/boards/%c, %s", BBSHOME, fname[0], fname);
firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/x/");
}
if (strlen(fname) + strlen(hispaths) + 1 < sizeof(hispaths)) {
strcat(hispaths, fname);
strcat(hispaths, " ");
}
} else {
bbslog("fname is null %s\n", boardhome);
return -1;
}
}
boardcont:
if (nboardptr != NULL) {
*nboardptr = ',';
boardptr = nboardptr + 1;
} else
break;
} /* for board1,board2,... */
/*
* if (nngptr != NULL) ngptr = nngptr + 1; else break;
*/
if (*firstpathbase)
feedfplog(nf, firstpathbase, 'P');
}
if (*hispaths)
bbsfeedslog(hispaths, 'P');
if (Junkhistory || *hispaths) {
if (storeDB(HEADER[MID_H], hispaths) < 0) {
bbslog("store DB fail\n");
/* I suspect here will introduce duplicated articles */
/* return -1; */
}
}
return 0;
}
int
receive_control(void)
{
char *boardhome, *fname;
char firstpath[PATHLEN], *firstpathbase;
char **splitptr, *ngptr;
newsfeeds_t *nf;
bbslog("control post %s\n", HEADER[CONTROL_H]);
boardhome = (char *)fileglue("%s/boards/c/control", BBSHOME);
testandmkdir(boardhome);
*firstpath = '\0';
if (dashd(boardhome)) {
fname = (char *)post_article(boardhome, FROM, "control", bbspost_write_control, NULL, firstpath);
if (fname != NULL) {
if (firstpath[0] == '\0')
sprintf(firstpath, "%s/boards/c/control/%s", BBSHOME, fname);
if (storeDB(HEADER[MID_H], (char *)fileglue("control/%s", fname)) < 0) {
}
bbsfeedslog(fileglue("control/%s", fname), 'C');
firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/x/");
splitptr = (char **)BNGsplit(GROUPS);
for (ngptr = *splitptr; ngptr != NULL; ngptr = *(++splitptr)) {
if (*ngptr == '\0')
continue;
nf = (newsfeeds_t *) search_group(ngptr);
if (nf == NULL)
continue;
if (nf->board == NULL)
continue;
if (nf->path == NULL)
continue;
feedfplog(nf, firstpathbase, 'C');
}
}
}
return 0;
}
int
cancel_article_front(msgid)
char *msgid;
{
char *ptr = (char *)DBfetch(msgid);
char *filelist, filename[2048];
char histent[4096];
char firstpath[PATHLEN], *firstpathbase = firstpath;
if (ptr == NULL) {
bbslog("cancel failed(DBfetch): %s\n", msgid);
return 0;
}
strncpy(histent, ptr, sizeof histent);
ptr = histent;
#ifdef DEBUG
printf("**** try to cancel %s *****\n", ptr);
#endif
filelist = strchr(ptr, '\t');
if (filelist != NULL) {
filelist++;
}
*firstpath = '\0';
for (ptr = filelist; ptr && *ptr;) {
char *file;
for (; *ptr && isspace(*ptr); ptr++);
if (*ptr == '\0')
break;
file = ptr;
for (ptr++; *ptr && !isspace(*ptr); ptr++);
if (*ptr != '\0') {
*ptr++ = '\0';
}
sprintf(filename, "%s/boards/%c/%s", BBSHOME, file[0], file);
bbslog("cancel post %s\n", filename);
if (dashf(filename)) {
FILE *fp = fopen(filename, "r");
char buffer[1024];
char xfrom0[100], xfrom[100], xpath[1024];
if (fp == NULL)
continue;
strncpy(xfrom0, HEADER[FROM_H], 99);
xfrom0[99] = 0;
strtok(xfrom0, ", ");
while (fgets(buffer, sizeof buffer, fp) != NULL) {
char *hptr;
if (buffer[0] == '\n')
break;
hptr = strchr(buffer, '\n');
if (hptr != NULL)
*hptr = '\0';
if (strncmp(buffer, "發信人: ", 8) == 0) {
strncpy(xfrom, buffer + 8, 99);
xfrom[99] = 0;
strtok(xfrom, ", ");
} else if (strncmp(buffer, "轉信站: ", 8) == 0) {
strcpy(xpath, buffer + 8);
}
}
fclose(fp);
if (strcmp(xfrom0, xfrom) && !search_issuer(FROM)) {
bbslog("Invalid cancel %s, path: %s!%s, [`%s` != `%s`]\n",
FROM, MYBBSID, PATH, xfrom0, xfrom);
return 0;
}
#ifdef KEEP_NETWORK_CANCEL
bbslog("cancel post %s\n", filename);
boardhome = (char *)fileglue("%s/boards/d/deleted", BBSHOME);
testandmkdir(boardhome);
if (dashd(boardhome)) {
char subject[1024];
char *fname;
if (POSTHOST) {
sprintf(subject, "cancel by: %.1000s", POSTHOST);
} else {
char *body, *body2;
body = strchr(BODY, '\r');
if (body != NULL)
*body = '\0';
body2 = strchr(BODY, '\n');
if (body2 != NULL)
*body = '\0';
sprintf(subject, "%.1000s", BODY);
if (body != NULL)
*body = '\r';
if (body2 != NULL)
*body = '\n';
}
if (*subject) {
SUBJECT = subject;
}
fname = (char *)post_article(boardhome, FROM, "deleted", bbspost_write_cancel, filename, firstpath);
if (fname != NULL) {
if (firstpath[0] == '\0') {
sprintf(firstpath, "%s/boards/d/deleted/%s", BBSHOME, fname);
firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/x/");
}
if (storeDB(HEADER[MID_H], (char *)fileglue("deleted/%s", fname)) < 0) {
/* should do something */
bbslog("store DB fail\n");
/* return -1; */
}
bbsfeedslog(fileglue("deleted/%s", fname), 'D');
#ifdef OLDDISPATCH
{
char board[256];
newsfeeds_t *nf;
char *filebase = filename + strlen(BBSHOME) + strlen("/boards/x/");
char *filetail = strrchr(filename, '/');
if (filetail != NULL) {
strncpy(board, filebase, filetail - filebase);
nf = (newsfeeds_t *) search_board(board);
if (nf != NULL && nf->board && nf->path) {
feedfplog(nf, firstpathbase, 'D');
}
}
}
#endif
} else {
bbslog(" fname is null %s %s\n", boardhome, filename);
return -1;
}
}
#else
/* bbslog("**** %s should be removed\n", filename); */
/*
* unlink(filename);
*/
#endif
{
char *fp = strrchr(file, '/');
if (fp != NULL) {
*fp = '\0';
cancel_article(BBSHOME, file, fp + 1);
*fp = '/';
}
}
}
}
if (*firstpath) {
char **splitptr, *ngptr;
newsfeeds_t *nf;
splitptr = (char **)BNGsplit(GROUPS);
for (ngptr = *splitptr; ngptr != NULL; ngptr = *(++splitptr)) {
if (*ngptr == '\0')
continue;
nf = (newsfeeds_t *) search_group(ngptr);
if (nf == NULL)
continue;
if (nf->board == NULL)
continue;
if (nf->path == NULL)
continue;
feedfplog(nf, firstpathbase, 'D');
}
}
return 0;
}
#if defined(PhoenixBBS) || defined(SecretBBS) || defined(PivotBBS) || defined(MapleBBS)
/* for PhoenixBBS's post article and cancel article */
#include "config.h"
char *
post_article(homepath, userid, board, writebody, pathname, firstpath)
char *homepath;
char *userid, *board;
int (*writebody) ();
char *pathname, *firstpath;
{
struct fileheader_t header;
char *subject = SUBJECT;
char index[PATHLEN];
static char name[PATHLEN];
char article[PATHLEN];
FILE *fidx;
int fh, bid;
time_t now;
int linkflag;
/*
* Ptt if(bad_subject(subject)) return NULL;
*/
sprintf(index, "%s/.DIR", homepath);
if ((fidx = fopen(index, "r")) == NULL) {
if ((fidx = fopen(index, "w")) == NULL) {
bbslog(":Err: Unable to post in %s.\n", homepath);
return NULL;
}
}
fclose(fidx);
now = time(NULL);
while (1) {
sprintf(name, "M.%ld.A", ++now);
sprintf(article, "%s/%s", homepath, name);
fh = open(article, O_CREAT | O_EXCL | O_WRONLY, 0644);
if (fh >= 0)
break;
if (errno != EEXIST) {
bbslog(" Err: can't writable or other errors\n");
return NULL;
}
}
#ifdef DEBUG
printf("post to %s\n", article);
#endif
linkflag = 1;
if (firstpath && *firstpath) {
close(fh);
unlink(article);
#ifdef DEBUGLINK
bbslog("try to link %s to %s", firstpath, article);
#endif
linkflag = link(firstpath, article);
if (linkflag) {
fh = open(article, O_CREAT | O_EXCL | O_WRONLY, 0644);
}
}
if (linkflag) {
if (writebody) {
if ((*writebody) (fh, board, pathname) < 0)
return NULL;
} else {
if (bbspost_write_post(fh, board, pathname) < 0)
return NULL;
}
close(fh);
}
bzero((void *)&header, sizeof(header));
#ifndef MapleBBS
strcpy(header.filename, name);
strncpy(header.owner, userid, IDLEN);
strncpy(header.title, subject, STRLEN);
header.filename[STRLEN - 1] = 'M';
#else
strcpy(header.filename, name);
if (userid[IDLEN-1])
{
userid[IDLEN-1] = '.';
userid[IDLEN] = '\0';
}
strcpy(header.owner, userid);
strncpy(header.title, subject, TTLEN);
/* no need to apply this... FILE_MULTI is used for mail group reply only now. */
// header.filemode |= FILE_MULTI;
{
struct tm *ptime;
ptime = localtime(&datevalue);
sprintf(header.date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
}
#endif
{
int i;
for( i = 0 ; header.title[i] != 0 && i < sizeof(header.title) ; ++i )
if( header.title[i] == '\n' ||
header.title[i] == '\r' ||
header.title[i] == '\033' ){
header.title[i] = 0;
break;
}
}
append_record(index, &header, sizeof(header));
if ((bid = getbnum(board)) > 0) {
touchbtotal(bid);
}
return name;
}
/*
* woju Cross-fs rename()
*/
#if 0 // moved to libbbsutil
int
Rename(const char *src, const char *dst)
{
char cmd[200];
bbslog("Rename: %s -> %s\n", src, dst);
if (rename(src, dst) == 0)
return 0;
sprintf(cmd, "/bin/mv %s %s", src, dst);
return system(cmd);
}
#endif
void
cancelpost(fileheader_t * fhdr, char *boardname)
{
int fd;
char fpath[PATHLEN];
sprintf(fpath, BBSHOME "/boards/%c/%s/%s", boardname[0], boardname, fhdr->filename);
if ((fd = open(fpath, O_RDONLY)) >= 0) {
fileheader_t postfile;
char fn2[PATHLEN] = BBSHOME "/boards/d/deleted";
stampfile(fn2, &postfile);
memcpy(postfile.owner, fhdr->owner, IDLEN + TTLEN + 10);
close(fd);
Rename(fpath, fn2);
strcpy(strrchr(fn2, '/') + 1, ".DIR");
append_record(fn2, &postfile, sizeof(postfile));
} else
bbslog("cancelpost: %s opened error\n", fpath);
}
/* ---------------------------- */
/* new/old/lock file processing */
/* ---------------------------- */
#if 0
typedef struct {
char newfn[PATHLEN];
char oldfn[PATHLEN];
char lockfn[PATHLEN];
} nol;
static void
nolfilename(n, fpath)
nol *n;
char *fpath;
{
sprintf(n->newfn, "%s.new", fpath);
sprintf(n->oldfn, "%s.old", fpath);
sprintf(n->lockfn, "%s.lock", fpath);
}
int
delete_record(const char *fpath, int size, int id)
{
nol my;
char abuf[512];
int fdr, fdw, fd;
int count;
fileheader_t fhdr;
nolfilename(&my, fpath);
if ((fd = open(my.lockfn, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1)
return -1;
flock(fd, LOCK_EX);
if ((fdr = open(fpath, O_RDONLY, 0)) == -1) {
#ifdef HAVE_REPORT
report("delete_record failed!!! (open)");
#endif
flock(fd, LOCK_UN);
close(fd);
return -1;
}
if ((fdw = open(my.newfn, O_WRONLY | O_CREAT | O_EXCL, 0644)) == -1) {
flock(fd, LOCK_UN);
#ifdef HAVE_REPORT
report("delete_record failed!!! (open tmpfile)");
#endif
close(fd);
close(fdr);
return -1;
}
count = 1;
while (read(fdr, abuf, size) == size) {
if (id == count) {
memcpy(&fhdr, abuf, sizeof(fhdr));
bbslog("delete_record: %d, %s, %s\n", count, fhdr.owner, fhdr.title);
}
if (id != count++ && (write(fdw, abuf, size) == -1)) {
bbslog("delete_record: %s failed!!! (write)\n", fpath);
#ifdef HAVE_REPORT
report("delete_record failed!!! (write)");
#endif
unlink(my.newfn);
close(fdr);
close(fdw);
flock(fd, LOCK_UN);
close(fd);
return -1;
}
}
close(fdr);
close(fdw);
if (Rename(fpath, my.oldfn) == -1 || Rename(my.newfn, fpath) == -1) {
#ifdef HAVE_REPORT
report("delete_record failed!!! (Rename)");
#endif
flock(fd, LOCK_UN);
close(fd);
return -1;
}
flock(fd, LOCK_UN);
close(fd);
return 0;
}
#endif
int
cancel_article(homepath, board, file)
char *homepath;
char *board, *file;
{
struct fileheader_t header;
struct stat state;
char dirname[PATHLEN];
long size, time, now;
int fd, lower, ent;
if (file == NULL || file[0] != 'M' || file[1] != '.' ||
(time = atoi(file + 2)) <= 0) {
bbslog("cancel_article: invalid filename `%s`\n", file);
return 0;
}
size = sizeof(header);
sprintf(dirname, "%s/boards/%c/%s/.DIR", homepath, board[0], board);
if ((fd = open(dirname, O_RDONLY)) == -1) {
bbslog("cancel_article: open `%s` error\n", dirname);
return 0;
}
fstat(fd, &state);
ent = ((long)state.st_size) / size;
lower = 0;
while (1) {
ent -= 8;
if (ent <= 0 || lower >= 2)
break;
lseek(fd, size * ent, SEEK_SET);
if (read(fd, &header, size) != size) {
ent = 0;
break;
}
now = atoi(header.filename + 2);
lower = (now < time) ? lower + 1 : 0;
}
if (ent < 0)
ent = 0;
while (read(fd, &header, size) == size) {
if (strcmp(file, header.filename) == 0) {
if ((header.filemode & FILE_MARKED)
|| (header.filemode & FILE_DIGEST) || (header.owner[0] == '-')
|| !strchr(header.owner,'.'))
break;
delete_record(dirname, sizeof(fileheader_t), lseek(fd, 0, SEEK_CUR) / size);
cancelpost(&header, board);
break;
}
now = atoi(header.filename + 2);
if (now > time)
break;
}
close(fd);
return 0;
}
#elif defined(PalmBBS)
#undef PATH XPATH
#undef HEADER XHEADER
#include "server.h"
char *
post_article(homepath, userid, board, writebody, pathname, firstpath)
char *homepath;
char *userid, *board;
int (*writebody) ();
char *pathname, *firstpath;
{
PATH msgdir, msgfile;
static PATH name;
READINFO readinfo;
SHORT fileid;
char buf[PATHLEN];
struct stat stbuf;
int fh;
strcpy(msgdir, homepath);
if (stat(msgdir, &stbuf) == -1 || !S_ISDIR(stbuf.st_mode)) {
/* A directory is missing! */
bbslog(":Err: Unable to post in %s.\n", msgdir);
return NULL;
}
get_filelist_ids(msgdir, &readinfo);
for (fileid = 1; fileid <= BBS_MAX_FILES; fileid++) {
int oumask;
if (test_readbit(&readinfo, fileid))
continue;
fileid_to_fname(msgdir, fileid, msgfile);
sprintf(name, "%04x", fileid);
#ifdef DEBUG
printf("post to %s\n", msgfile);
#endif
if (firstpath && *firstpath) {
#ifdef DEBUGLINK
bbslog("try to link %s to %s", firstpath, msgfile);
#endif
if (link(firstpath, msgfile) == 0)
break;
}
oumask = umask(0);
fh = open(msgfile, O_CREAT | O_EXCL | O_WRONLY, 0664);
umask(oumask);
if (writebody) {
if ((*writebody) (fh, board, pathname) < 0)
return NULL;
} else {
if (bbspost_write_post(fh, board, pathname) < 0)
return NULL;
}
close(fh);
break;
}
#ifdef CACHED_OPENBOARD
{
char *bname;
bname = strrchr(msgdir, '/');
if (bname)
notify_new_post(++bname, 1, fileid, stbuf.st_mtime);
}
#endif
return name;
}
cancel_article(homepath, board, file)
char *homepath;
char *board, *file;
{
PATH fname;
#ifdef CACHED_OPENBOARD
PATH bdir;
struct stat stbuf;
sprintf(bdir, "%s/boards/%c/%s", homepath, board[0], board);
stat(bdir, &stbuf);
#endif
sprintf(fname, "%s/boards/%c/%s/%s", homepath, board[0], board, file);
unlink(fname);
/* kill it now! the function is far small then original.. :) */
/* because it won't make system load heavy like before */
#ifdef CACHED_OPENBOARD
notify_new_post(board, -1, hex2SHORT(file), stbuf.st_mtime);
#endif
}
#else
error("You should choose one of the systems: PhoenixBBS, PowerBBS, or PalmBBS")
#endif
#else
receive_article()
{
}
cancel_article_front(msgid)
char *msgid;
{
}
#endif