From ae31e19f92e717919ac8e3db9039eb38d2b89aae Mon Sep 17 00:00:00 2001 From: in2 Date: Thu, 7 Mar 2002 15:13:44 +0000 Subject: Initial revision git-svn-id: http://opensvn.csie.org/pttbbs/pttbbs/trunk/pttbbs@1 63ad8ddf-47c3-0310-b6dd-a9e9d9715204 --- innbbsd/receive_article.c | 1204 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1204 insertions(+) create mode 100644 innbbsd/receive_article.c (limited to 'innbbsd/receive_article.c') diff --git a/innbbsd/receive_article.c b/innbbsd/receive_article.c new file mode 100644 index 00000000..40f2609c --- /dev/null +++ b/innbbsd/receive_article.c @@ -0,0 +1,1204 @@ +/* + * 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(); + */ + + +#ifndef PowerBBS +#include "innbbsconf.h" +#include "daemon.h" +#include "bbslib.h" +#include "inntobbs.h" +#include "antisplam.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 */ +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 + + +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 */ +receive_article() +{ + int i; + char *user, *userptr; + char *ngptr, *nngptr, *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[MAXPATHLEN], *firstpathbase; + char *lesssym, *nameptrleft, *nameptrright; + static char sitebuf[80]; + +#ifdef HMM_USE_ANTI_SPAM + char *notitle[] = + {"行銷", "業務代表", "徵", "資訊", "免費", "大贈送", "傳銷", "未滿", + "年費", "傳呼", "價", "操你媽", "未成年", "馬賽克", "信用", "賺錢", + "=?", "!!!", + "操你", "操你", "幹妳", "操妳","**","★★","**","$$","泡麵", NULL}, + *nofrom[] = + {"TaipeiNet.Net", "hotmail.com", "mt.touc.edu.tw", "ms11.hinet.net", NULL}, + *nocont[] = + {"名額有限", "優惠價", "動作要快", "訂購", "特價", "專賣", "BBC", + "幹你", "操你", "幹妳", "操妳","每片","最新目錄", "http://", "收錢", + "創業", "付款", "廣告信", "只賣", "市價", "NCg", "ICAg", 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])) + { + morelog_to(INNBBSD_SPAM, "spam from [%s]: %s\n", nofrom[i], FROM); + morelog_to(INNBBSD_SPAM, " %s %s %s %s\n", FROM, PATH, GROUPS, SUBJECT); + 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])) + { + morelog_to(INNBBSD_SPAM, "spam body [%s]: %s\n", nocont[i]); + morelog_to(INNBBSD_SPAM, " %s %s %s %s\n", FROM, PATH, GROUPS, SUBJECT); + bbslog(":Ptt: spam body [%s]: %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])) + { + morelog_to(INNBBSD_SPAM, "spam title [%s]: %s\n", notitle[i], SUBJECT); + morelog_to(INNBBSD_SPAM, " %s %s %s %s\n", FROM, PATH, GROUPS, SUBJECT); + 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; + + strptime(DATE, "%d %b %Y %X GMT", &tmbuf); + datevalue = timegm(&tmbuf); + } + + 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, 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/%s", BBSHOME, boardptr); + if (!isdir(boardhome)) + { + bbslog(":Err: unable to write %s\n", boardhome); + } + else + { + char *fname; + /* + * if ( !isdir( 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/%s", BBSHOME, fname); + firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/"); + } + 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; +} + +receive_control() +{ + char *boardhome, *fname; + char firstpath[MAXPATHLEN], *firstpathbase; + char **splitptr, *ngptr; + newsfeeds_t *nf; + + bbslog("control post %s\n", HEADER[CONTROL_H]); + boardhome = (char *) fileglue("%s/boards/control", BBSHOME); + testandmkdir(boardhome); + *firstpath = '\0'; + if (isdir(boardhome)) + { + fname = (char *) post_article(boardhome, FROM, "control", bbspost_write_control, NULL, firstpath); + if (fname != NULL) + { + if (firstpath[0] == '\0') + sprintf(firstpath, "%s/boards/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/"); + 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; +} + +cancel_article_front(msgid) + char *msgid; +{ + char *ptr = (char *) DBfetch(msgid); + char *filelist, filename[2048]; + char histent[4096]; + char firstpath[MAXPATHLEN], *firstpathbase; + 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/%s", BBSHOME, file); + bbslog("cancel post %s\n", filename); + if (isfile(filename)) + { + FILE *fp = fopen(filename, "r"); + char buffer[1024]; + char xfrom0[100], xfrom[100], xpath[1024], *boardhome; + + 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)) + { + 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/deleted", BBSHOME); + testandmkdir(boardhome); + if (isdir(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/deleted/%s", BBSHOME, fname); + firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/"); + } + 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/"); + 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 userec_t record; + struct fileheader_t header; + char *subject = SUBJECT; + char index[MAXPATHLEN]; + static char name[MAXPATHLEN]; + char article[MAXPATHLEN]; + char buf[MAXPATHLEN], *ptr; + 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.%d.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]) + strcpy(&userid[IDLEN], "."); + strcpy(header.owner, userid); + strncpy(header.title, subject, TTLEN); + header.savemode = 'M'; + { + struct tm *ptime; + ptime = localtime(&datevalue); + sprintf(header.date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday); + } +#endif + + append_record(index, &header, sizeof(header)); + + if((bid = getbnum(board)) > 0) + touchbtotal(bid); + return name; +} + +/* +woju +Cross-fs rename() +*/ + +Rename(char* src, 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); +} + + +cancelpost(fileheader_t *fhdr, char* boardname) +{ + int fd; + char fpath[MAXPATHLEN]; + + sprintf(fpath, BBSHOME "/boards/%s/%s", boardname, fhdr->filename); + if ((fd = open(fpath, O_RDONLY)) >= 0) { + fileheader_t postfile; + char fn2[MAXPATHLEN] = BBSHOME "/boards/deleted", *junkdir; + + stampfile(fn2, &postfile); + memcpy(postfile.owner, fhdr->owner, IDLEN + TTLEN + 10); + postfile.savemode = 'D'; + 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 */ +/* ---------------------------- */ + +typedef struct +{ + char newfn[MAXPATHLEN]; + char oldfn[MAXPATHLEN]; + char lockfn[MAXPATHLEN]; +} 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(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; +} + +cancel_article(homepath, board, file) + char *homepath; + char *board, *file; +{ + struct fileheader_t header; + struct stat state; + char dirname[MAXPATHLEN]; + char buf[MAXPATHLEN]; + long numents, 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/%s/.DIR", homepath, 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] == '-')) + 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[MAXPATHLEN]; + 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/%s", homepath, board); + stat(bdir, &stbuf); +#endif + + sprintf(fname, "%s/boards/%s/%s", homepath, 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 -- cgit v1.2.3