summaryrefslogtreecommitdiffstats
path: root/innbbsd/receive_article.c
diff options
context:
space:
mode:
Diffstat (limited to 'innbbsd/receive_article.c')
-rw-r--r--innbbsd/receive_article.c1204
1 files changed, 1204 insertions, 0 deletions
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