/*-------------------------------------------------------*/
/* bbs.c ( NTHU CS MapleBBS Ver 2.36 ) */
/*-------------------------------------------------------*/
/* target : bulletin boards' routines */
/* create : 95/03/29 */
/* update : 95/12/15 */
/*-------------------------------------------------------*/
#include "bbs.h"
extern int mail_reply();
extern char currdirect[64];
extern void strip_ansi(char *,char *,int );
time_t board_note_time;
time_t board_visit_time;
static char *brd_title;
static int continue_flag;
char real_name[20];
int local_article;
#define UPDATE_USEREC (currmode |= MODE_DIRTY)
/* substitute_record(fn_passwd, &cuser, sizeof(userec), usernum) */
static int
g_board_names(fhdr)
boardheader *fhdr;
{
AddNameList(fhdr->brdname);
return 0;
}
void
make_blist()
{
CreateNameList();
apply_boards(g_board_names);
}
void
set_board()
{
boardheader *bp;
boardheader *getbcache();
bp = getbcache(currboard);
board_note_time = bp->bupdate;
brd_title = bp->BM;
if (brd_title[0] <= ' ')
brd_title = "徵求中";
sprintf(currBM, "板主:%s", brd_title);
brd_title = (bp->bvote == 1 ? "本看板進行投票中" : bp->title + 7);
currmode = (currmode & MODE_DIRTY) | MODE_STARTED;
if (HAS_PERM(PERM_ALLBOARD) ||
(HAS_PERM(PERM_BM) && is_BM(currBM + 6)))
{
currmode |= (MODE_BOARD | MODE_POST);
}
else if (haspostperm(currboard))
currmode |= MODE_POST;
}
static void
readtitle()
{
showtitle(currBM, brd_title);
outs("\
[←]離開 [→]閱\讀 [^P]發表文章 [b]備忘錄 [d]刪除 [z]精華區 [TAB]文摘 [h]elp\n\
編號 日 期 作 者 文 章 標 題 ");
}
static void
readdoent(num, ent)
int num;
fileheader *ent;
{
int type;
char *mark, *title, color;
type = brc_unread(ent->filename) ? '+' : ' ';
if ((currmode & MODE_BOARD) && (ent->filemode & FILE_DIGEST))
type = (type == ' ') ? '*' : '#';
else
/*Ptt add if*/
if(HAS_PERM(PERM_BM) || HAS_PERM(PERM_SYSOP))
{
if (ent->filemode & FILE_MARKED)
type = (type == ' ') ? 'm' : 'M';
if (ent->filemode & FILE_TAGED)
type = 'D';
}
title = subject(mark = ent->title);
if (title == mark)
{
color = '1';
mark = "□";
}
else
{
color = '3';
mark = "R:";
}
if (title[47])
strcpy(title + 44, " …"); /* 把多餘的 string 砍掉 */
if (strncmp(currtitle, title, 40))
prints("%6d %c %-7s%-13.12s%s %s\n", num, type,
ent->date, ent->owner, mark, title);
else
prints("%6d %c %-7s%-13.12sm%s %s\n", num, type,
ent->date, ent->owner, color, mark, title);
}
int
cmpbnames(bname, brec)
char *bname;
boardheader *brec;
{
return (!ci_strncmp(bname, brec->brdname, sizeof(brec->brdname)));
}
int
cmpfilename(fhdr)
fileheader *fhdr;
{
return (!strcmp(fhdr->filename, currfile));
}
/*
woju
*/
int
cmpfmode(fhdr)
fileheader *fhdr;
{
return (fhdr->filemode & currfmode);
}
int
cmpfowner(fhdr)
fileheader *fhdr;
{
return !strcasecmp(fhdr->owner, currowner);
}
int
do_select(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char bname[20];
char bpath[60];
struct stat st;
move(0, 0);
clrtoeol();
make_blist();
namecomplete(MSG_SELECT_BOARD, bname);
setbpath(bpath, bname);
if ((*bname == '\0') || (stat(bpath, &st) == -1))
{
move(2, 0);
clrtoeol();
outs(err_bid);
/*
woju
pressanykey();
*/
return FULLUPDATE;
}
/*
board_visit_time = 0x7fffffff;
*/
brc_initial(bname);
set_board();
setbdir(direct, currboard);
move(1, 0);
clrtoeol();
return NEWDIRECT;
}
/* ----------------------------------------------------- */
/* 改良 innbbsd 轉出信件、連線砍信之處理程序 */
/* ----------------------------------------------------- */
outgo_post(fh, board)
fileheader *fh;
char *board;
{
FILE *foo;
if (foo = fopen("innd/out.bntp", "a"))
{
fprintf(foo, "%s\t%s\t%s\t%s\t%s\n", board,
fh->filename, cuser.userid, cuser.username, fh->title);
fclose(foo);
}
}
static void
cancelpost(fh, by_BM)
fileheader *fh;
int by_BM;
{
FILE *fin, *fout;
char *ptr, *brd;
fileheader postfile;
char genbuf[200];
char nick[STRLEN], fn1[STRLEN], fn2[STRLEN];
setbfile(fn1, currboard, fh->filename);
if (fin = fopen(fn1, "r"))
{
brd = by_BM ? "deleted" : "junk";
setbpath(fn2, brd);
stampfile(fn2, &postfile);
memcpy(postfile.owner, fh->owner, IDLEN + TTLEN + 10);
postfile.savemode = 'D';
if (fh->savemode == 'S')
{
nick[0] = '\0';
while (fgets(genbuf, sizeof(genbuf), fin))
{
if (!strncmp(genbuf, str_author1, LEN_AUTHOR1) ||
!strncmp(genbuf, str_author2, LEN_AUTHOR2))
{
if (ptr = strrchr(genbuf, ')'))
*ptr = '\0';
if (ptr = (char *) strchr(genbuf, '('))
strcpy(nick, ptr + 1);
break;
}
}
if (fout = fopen("innd/cancel.bntp", "a"))
{
fprintf(fout, "%s\t%s\t%s\t%s\t%s\n",
currboard, fh->filename, cuser.userid, nick, fh->title);
fclose(fout);
}
}
fclose(fin);
Rename(fn1, fn2);
setbdir(genbuf, brd);
append_record(genbuf, &postfile, sizeof(postfile));
}
}
/* ----------------------------------------------------- */
/* 發表、回應、編輯、轉錄文章 */
/* ----------------------------------------------------- */
void
do_reply_title(row, title)
int row;
char *title;
{
char genbuf[200];
char genbuf2[4];
if (ci_strncmp(title, str_reply, 4))
sprintf(save_title, "Re: %s", title);
else
strcpy(save_title, title);
save_title[TTLEN - 1] = '\0';
sprintf(genbuf, "採用原標題《%.60s》嗎?[Y] ", save_title);
getdata(row, 0, genbuf, genbuf2, 4, LCECHO);
if (*genbuf2 == 'n')
getdata(++row, 0, "標題:", save_title, TTLEN, DOECHO);
}
static void
do_reply(fhdr)
fileheader *fhdr;
{
char genbuf[200];
getdata(b_lines - 1, 0, "▲ 回應至 (F)看板 (M)作者信箱 (B)二者皆是 (Q)取消?[F] ", genbuf, 3, LCECHO);
switch (genbuf[0])
{
case 'm':
mail_reply(0, fhdr, 0);
case 'q':
break;
case 'b':
curredit = EDIT_BOTH;
default:
strcpy(currtitle, fhdr->title);
strcpy(quote_user, fhdr->owner);
quote_file[79] = fhdr->savemode;
do_post();
}
*quote_file = 0;
}
/*
woju
*/
brdperm(char* brdname, char* userid)
{
boardheader *bp;
boardheader *getbcache();
int uid = searchuser(userid);
bp = getbcache(currboard);
if (uid && bp) {
int level = bp->level;
char* ptr = bp->BM;
char buf[64], manager[IDLEN + 1];
userec xuser;
get_record(fn_passwd, &xuser, sizeof(xuser), uid);
if ((level & PERM_POSTMASK) || ((level)?xuser.userlevel&(level):1))
return 1;
if (ptr[0] <= ' ')
return 0;
if (userid_is_BM(userid, ptr))
return 1;
if ((level & 0xffff) != PERM_SYSOP)
return 0;
strncpy(manager, ptr, IDLEN + 1);
if (ptr = strchr(manager, '/'))
*ptr = 0;
sethomefile(buf, manager, fn_overrides);
return (belong(buf, userid));
}
return 0;
}
do_postnotify(char* fpath)
{
fileheader mhdr;
char title[128], buf1[80], buf[80];
FILE* fp;
char genbuf[200];
setuserfile(genbuf, "postnotify");
if (fp = fopen(genbuf, "r")) {
char last_fname[80];
boardheader *bp;
boardheader *getbcache();
strcpy(last_fname, fpath);
bp = getbcache(currboard);
while (fgets(buf, 80, fp))
if (brdperm(currboard, buf)) {
sethomepath(buf1, buf);
stampfile(buf1, &mhdr);
strcpy(mhdr.owner, cuser.userid);
strcpy(mhdr.title, "[新]");
strncat(mhdr.title, save_title, TTLEN - 4);
mhdr.savemode = 0;
mhdr.filemode = 0;
sethomedir(title, buf);
do_append(title, &mhdr, sizeof(mhdr));
unlink(buf1);
Link(last_fname, buf1);
strcpy(last_fname, buf1);
}
fclose(fp);
}
}
do_unanonymous_post(char* fpath)
{
fileheader mhdr;
char title[128], buf1[80], buf[80];
FILE* fp;
char genbuf[200];
setbpath(genbuf, "UnAnonymous");
if (dashd(genbuf)) {
stampfile(genbuf, &mhdr);
unlink(genbuf);
Link(fpath, genbuf);
strcpy(mhdr.owner, cuser.userid);
strcpy(mhdr.title, save_title);
mhdr.savemode = 0;
mhdr.filemode = 0;
setbdir(title, "UnAnonymous");
append_record(title, &mhdr, sizeof(mhdr));
}
}
/* Ptt test */
getindex(fpath,fname,size)
char *fpath;
char *fname;
int size;
{
int fd, now=0;
fileheader fhdr;
if ((fd = open(fpath, O_RDONLY, 0)) != -1)
{
while((read(fd, &fhdr, size) == size)){
now++;
if(!strcmp(fhdr.filename,fname)){
close(fd);
return now;
}
}
close(fd);
}
return 0;
}
int
do_post()
{
fileheader postfile;
char fpath[80], buf[80];
int aborted;
char genbuf[200];
clear();
if (!(currmode & MODE_POST) && (strcmp(cuser.userid,"Sex") && strcmp(currboard,"sex")))
{
move(5, 10);
outs("對不起,您目前無法在此發表文章!");
pressanykey();
return FULLUPDATE;
}
more("etc/post.note", NA);
prints("發表文章於【 %s 】看板\n\n", currboard);
if (quote_file[0])
do_reply_title(20, currtitle);
else
{
getdata(21, 0, "標題:", save_title, TTLEN, DOECHO);
strip_ansi(save_title,save_title,0);
}
if (save_title[0] == '\0')
return FULLUPDATE;
curredit &= ~EDIT_MAIL;
setutmpmode(POSTING);
/* 未具備 Internet 權限者,只能在站內發表文章 */
if (HAS_PERM(PERM_INTERNET))
local_article = 0;
else
local_article = 1;
buf[0] = 0;
aborted = vedit(buf, YEA);
if (aborted == -1)
{
unlink(buf);
pressanykey();
return FULLUPDATE;
}
/* build filename */
setbpath(fpath, currboard);
stampfile(fpath, &postfile);
Rename(buf, fpath);
strcpy(postfile.owner, cuser.userid);
/* set owner to Anonymous , for Anonymous board */
#ifdef HAVE_ANONYMOUS
/* Ptt and Jaky */
if (!strcmp(currboard, "Anonymous"))
{
if(!strcmp(real_name,"r"))
{
strcpy (postfile.owner, cuser.userid);
}
else
{
sprintf (postfile.owner,"%s.",real_name);
}
}
#endif
strcpy(postfile.title, save_title);
if (aborted == 1) /* local save */
{
postfile.savemode = 'L';
postfile.filemode = FILE_LOCAL;
}
else
postfile.savemode = 'S';
setbdir(buf, currboard);
if (append_record(buf, &postfile, sizeof(postfile)) != -1)
{
if(currmode & MODE_SELECT)
append_record(currdirect,&postfile,sizeof(postfile));
if (aborted != 1)
outgo_post(&postfile, currboard);
brc_addlist(postfile.filename);
outs("順利貼出佈告,");
if (strcmp(currboard, "Test") && strcmp(currboard, "Anonymous"))
{
prints("這是您的第 %d 篇文章。 稿籌 %d 銀。",
++cuser.numposts,aborted/2);
inmoney(aborted/2);
UPDATE_USEREC;
}
else
outs("測試信件不列入紀錄,敬請包涵。");
/* 回應到原作者信箱 */
if (curredit & EDIT_BOTH)
{
char *str, *msg = "回應至作者信箱";
if (str = strchr(quote_user, '.'))
{
if (bbs_sendmail(fpath, save_title, str + 1) < 0)
msg = "作者無法收信";
}
else
{
sethomepath(genbuf, quote_user);
stampfile(genbuf, &postfile);
unlink(genbuf);
Link(fpath, genbuf);
strcpy(postfile.owner, cuser.userid);
strcpy(postfile.title, save_title);
postfile.savemode = 'B';/* both-reply flag */
sethomedir(genbuf, quote_user);
if (append_record(genbuf, &postfile, sizeof(postfile)) == -1)
msg = err_uid;
}
outs(msg);
curredit ^= EDIT_BOTH;
}
if (strcmp("Anonymous", currboard))
do_postnotify(fpath);
else
do_unanonymous_post(fpath);
}
pressanykey();
return FULLUPDATE;
}
static int
reply_post(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
if (!(currmode & MODE_POST))
return DONOTHING;
setdirpath(quote_file, direct, fhdr->filename);
do_reply(fhdr);
*quote_file = 0;
return FULLUPDATE;
}
static int
edit_post(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char fpath[80], fpath0[80];
extern bad_user(char* name);
char genbuf[200];
fileheader postfile;
int edit_mode;
if (HAS_PERM(PERM_SYSOP) ||
!strcmp(fhdr->owner, cuser.userid) && strcmp(cuser.userid, "guest") &&
/* strcmp(currboard, "Anonymous") && */ !bad_user(cuser.userid))
edit_mode = 0;
else
edit_mode = 2;
setdirpath(genbuf, direct, fhdr->filename);
local_article = fhdr->filemode & FILE_LOCAL;
strcpy(save_title, fhdr->title);
if (vedit(genbuf, edit_mode) != -1) {
setbpath(fpath, currboard);
stampfile(fpath, &postfile);
unlink(fpath);
setbfile(fpath0, currboard, fhdr->filename);
Rename(fpath0, fpath);
strcpy(fhdr->filename, postfile.filename);
strcpy(fhdr->title, save_title);
brc_addlist(postfile.filename);
substitute_record(direct, fhdr, sizeof(*fhdr), ent);
if (strcmp(currboard, "Anonymous"))
do_postnotify(fpath);
}
return FULLUPDATE;
}
static int
cross_post(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char xboard[20], fname[80], xfpath[80], xtitle[80], inputbuf[10];
fileheader xfile;
FILE *xptr;
int author = 0;
char genbuf[200];
char genbuf2[4];
make_blist();
move(2, 0);
clrtoeol();
move(3, 0);
clrtoeol();
move(1, 0);
namecomplete("轉錄本文章於看板:", xboard);
if (*xboard == '\0' || !haspostperm(xboard))
return FULLUPDATE;
ent = 1;
if (HAS_PERM(PERM_SYSOP) || !strcmp(fhdr->owner, cuser.userid))
{
getdata(2, 0, "(1)原文轉載 (2)舊轉錄格式?[1] ",
genbuf, 3, DOECHO);
if (genbuf[0] != '2')
{
ent = 0;
getdata(2, 0, "保留原作者名稱嗎?[Y] ", inputbuf, 3, DOECHO);
if (inputbuf[0] != 'n' && inputbuf[0] != 'N') author = 1;
}
}
if (ent)
sprintf(xtitle, "[轉錄]%.66s", fhdr->title);
else
strcpy(xtitle, fhdr->title);
sprintf(genbuf, "採用原標題《%.60s》嗎?[Y] ", xtitle);
getdata(2, 0, genbuf, genbuf2, 4, LCECHO);
if (*genbuf2 == 'n')
{
if (getdata(2, 0, "標題:", genbuf, TTLEN, DOECHO))
strcpy(xtitle, genbuf);
}
getdata(2, 0, "(S)存檔 (L)站內 (Q)取消?[Q] ", genbuf, 3, LCECHO);
if (genbuf[0] == 'l' || genbuf[0] == 's')
{
int currmode0 = currmode;
currmode = 0;
setbpath(xfpath, xboard);
stampfile(xfpath, &xfile);
if (author)
strcpy(xfile.owner, fhdr->owner);
else
strcpy(xfile.owner, cuser.userid);
strcpy(xfile.title, xtitle);
if (genbuf[0] == 'l')
{
xfile.savemode = 'L';
xfile.filemode = FILE_LOCAL;
}
else
xfile.savemode = 'S';
setbfile(fname, currboard, fhdr->filename);
if (ent)
{
xptr = fopen(xfpath, "w");
strcpy(save_title, xfile.title);
strcpy(xfpath, currboard);
strcpy(currboard, xboard);
write_header(xptr);
strcpy(currboard, xfpath);
fprintf(xptr, "※ [本文轉錄自 %s 看板]\n\n", currboard);
b_suckinfile(xptr, fname);
addsignature(xptr);
fclose(xptr);
}
else
{
unlink(xfpath);
Link(fname, xfpath);
}
setbdir(fname, xboard);
append_record(fname, (char *) &xfile, sizeof(xfile));
if (!xfile.filemode)
outgo_post(&xfile, xboard);
cuser.numposts++;
UPDATE_USEREC;
outs("文章轉錄完成");
pressanykey();
currmode = currmode0;
}
return FULLUPDATE;
}
static int
read_post(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char genbuf[200];
int more_result;
if (fhdr->owner[0] == '-')
return DONOTHING;
setdirpath(genbuf, direct, fhdr->filename);
if ((more_result = more(genbuf, YEA)) == -1)
return DONOTHING;
brc_addlist(fhdr->filename);
strncpy(currtitle, subject(fhdr->title), 40);
strncpy(currowner, subject(fhdr->owner), IDLEN + 2);
/*
woju
*/
switch (more_result) {
case 1:
return READ_PREV;
case 2:
return RELATE_PREV;
case 3:
return READ_NEXT;
case 4:
return RELATE_NEXT;
case 5:
return RELATE_FIRST;
case 6:
return FULLUPDATE;
case 7:
case 8:
if (currmode & MODE_POST)
{
strcpy(quote_file, genbuf);
do_reply(fhdr);
*quote_file = 0;
}
return FULLUPDATE;
case 9:
return 'A';
case 10:
return 'a';
case 11:
return '/';
case 12:
return '?';
}
outmsg(" 閱\讀文章 (R/Y)回信 "
"(=[]<>)相關主題 (↑↓)上下封 (←)離開 ");
switch (egetch())
{
case 'q':
case 'Q':
case KEY_LEFT:
break;
case ' ':
case KEY_RIGHT:
case KEY_DOWN:
case KEY_PGDN:
case 'n':
case Ctrl('N'):
return READ_NEXT;
case KEY_UP:
case 'p':
case Ctrl('P'):
case KEY_PGUP:
return READ_PREV;
case '=':
return RELATE_FIRST;
case ']':
case 't':
return RELATE_NEXT;
case '[':
return RELATE_PREV;
case '.':
case '>':
return THREAD_NEXT;
case ',':
case '<':
return THREAD_PREV;
/*
woju
*/
case Ctrl('R'): if (currutmp->msgs[0].last_pid) {
show_last_call_in();
my_write(currutmp->msgs[0].last_pid, "水球丟回去:");
return FULLUPDATE;
}
return DONOTHING;
case Ctrl('C'):
cal();
return FULLUPDATE;
break;
case Ctrl('U'):
t_users();
return FULLUPDATE;
case KEY_ESC: if (KEY_ESC_arg == 'n') {
edit_note();
return FULLUPDATE;
}
return DONOTHING;
case Ctrl('I'):
t_idle();
return FULLUPDATE;
case 'y':
case 'r':
case 'R':
case 'Y':
if (currmode & MODE_POST)
{
strcpy(quote_file, genbuf);
do_reply(fhdr);
*quote_file = 0;
}
}
return FULLUPDATE;
}
/* ----------------------------------------------------- */
/* 採集精華區 */
/* ----------------------------------------------------- */
b_man()
{
char buf[64];
setapath(buf, currboard);
a_menu(currboard, buf, HAS_PERM(PERM_ALLBOARD) ? 2 :
(currmode & MODE_BOARD ? 1 : 0));
return FULLUPDATE;
}
static int
cite_post(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char fpath[256];
char title[TTLEN+1];
setbfile(fpath, currboard, fhdr->filename);
strcpy(title, "◇ ");
strncpy(title+3, fhdr->title, TTLEN-3);
title[TTLEN] = '\0';
a_copyitem(fpath, title, 0);
b_man();
return FULLUPDATE;
}
int
edit_title(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char genbuf[200];
if (HAS_PERM(PERM_SYSOP))
{
fileheader tmpfhdr = *fhdr;
int dirty = 0;
if (getdata(b_lines - 1, 0, "標題:", genbuf, TTLEN, DOECHO))
{
strcpy(tmpfhdr.title, genbuf);
dirty++;
}
if (getdata(b_lines - 1, 0, "作者:", genbuf, IDLEN + 2, DOECHO))
{
strcpy(tmpfhdr.owner, genbuf);
dirty++;
}
if (getdata(b_lines - 1, 0, "日期:", genbuf, 6, DOECHO))
{
sprintf(tmpfhdr.date, "%+5s", genbuf);
dirty++;
}
if (getdata(b_lines - 1, 0, "確定(Y/N)?[n] ", genbuf, 3, DOECHO) &&
*genbuf == 'y' && dirty) {
*fhdr = tmpfhdr;
substitute_record(direct, fhdr, sizeof(*fhdr), ent);
if(currmode & MODE_SELECT)
{
int now;
setbdir(genbuf,currboard);
now=getindex(genbuf,fhdr->filename,sizeof(fileheader));
substitute_record(genbuf,fhdr,sizeof(*fhdr),now);
}
}
return FULLUPDATE;
}
return DONOTHING;
}
static
post_tag(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
if ((currstat != READING) || (currmode & MODE_SELECT)){
int now;
char genbuf[100];
fhdr->filemode ^= FILE_TAGED;
setbdir(genbuf,currboard);
now=getindex(genbuf,fhdr->filename,sizeof(fileheader));
substitute_record(genbuf,fhdr,sizeof(*fhdr),now);
sprintf(genbuf, "boards/%s/SR.%s", currboard, cuser.userid);
substitute_record(genbuf, fhdr, sizeof(*fhdr), ent);
return POS_NEXT;
}
if ((currstat != READING) || (currmode & MODE_BOARD)) {
fhdr->filemode ^= FILE_TAGED;
substitute_record(direct, fhdr, sizeof(*fhdr), ent);
return POS_NEXT;
}
return DONOTHING;
}
static int
post_del_tag(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char genbuf[3];
if ((currstat != READING) || (currmode & MODE_BOARD)) {
getdata(1, 0, "確定刪除標記文章(Y/N)? [N]", genbuf, 3, LCECHO);
if (genbuf[0] == 'y')
{
char buf[STRLEN];
currfmode = FILE_TAGED;
if (currmode & MODE_SELECT){
unlink(direct);
currmode ^= MODE_SELECT;
setbdir(direct, currboard);
delete_files(direct, cmpfmode);
}
if (delete_files(direct, cmpfmode))
return DIRCHANGED;
}
return FULLUPDATE;
}
return DONOTHING;
}
static int
mark_post(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
if( currmode & MODE_SELECT){
int now;
char genbuf[100];
fhdr->filemode ^= FILE_MARKED;
setbdir(genbuf,currboard);
now = getindex(genbuf,fhdr->filename,sizeof(fileheader));
substitute_record(genbuf, fhdr, sizeof(*fhdr), now);
return PART_REDRAW;
}
if (currmode & MODE_BOARD)
{
fhdr->filemode ^= FILE_MARKED;
substitute_record(direct, fhdr, sizeof(*fhdr), ent);
return PART_REDRAW;
}
return DONOTHING;
}
int
del_range(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char num1[8], num2[8];
int inum1, inum2;
if ((currstat != READING) || (currmode & MODE_BOARD))
{
getdata(1, 0, "[設定刪除範圍] 起點:", num1, 5, DOECHO);
inum1 = atoi(num1);
if (inum1 <= 0)
{
outmsg("起點有誤");
refresh();
sleep(1);
return FULLUPDATE;
}
getdata(1, 28, "終點:", num2, 5, DOECHO);
inum2 = atoi(num2);
if (inum2 < inum1)
{
outmsg("終點有誤");
refresh();
sleep(1);
return FULLUPDATE;
}
getdata(1, 48, msg_sure_ny, num1, 3, LCECHO);
if (*num1 == 'y')
{
outmsg("處理中,請稍後...");
refresh();
if(currmode & MODE_SELECT)
{
int fd,size=sizeof(fileheader);
char genbuf[100];
fileheader rsfh;
int i=inum1,now;
if(currstat==RMAIL)
sethomedir(genbuf,cuser.userid);
else
setbdir(genbuf,currboard);
if((fd=(open(direct,O_RDONLY, 0)))!=-1)
{
if (lseek(fd, (off_t)(size * (inum1 - 1)), SEEK_SET) != -1)
{
while(read(fd,&rsfh,size) == size)
{
if(i>inum2)
break;
now=getindex(genbuf,rsfh.filename,size);
strcpy(currfile,rsfh.filename);
delete_file (genbuf, sizeof(fileheader), now, cmpfilename);
i++;
}
}
close(fd);
}
}
delete_range(direct, inum1, inum2, NULL);
fixkeep(direct, inum1);
return DIRCHANGED;
}
return FULLUPDATE;
}
return DONOTHING;
}
static void
lazy_delete(fhdr)
fileheader *fhdr;
{
char buf[20];
sprintf(buf, "-%s", fhdr->owner);
strncpy(fhdr->owner, buf, IDLEN + 1);
strcpy(fhdr->title, "<< article deleted >>");
fhdr->savemode = 'L';
}
int
del_one(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
if ((currstat != READING) || (currmode & MODE_BOARD))
{
strcpy(currfile, fhdr->filename);
if (!update_file(direct, sizeof(fileheader), ent, cmpfilename, lazy_delete))
{
cancelpost(fhdr, YEA);
lazy_delete(fhdr);
return PART_REDRAW;
}
}
return DONOTHING;
}
static int
del_post(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char buf[80];
char *t;
int not_owned,money;
char genbuf[100];
if ((fhdr->filemode & FILE_MARKED)
|| (fhdr->filemode & FILE_DIGEST) || (fhdr->owner[0] == '-'))
return DONOTHING;
not_owned = strcmp(fhdr->owner, cuser.userid);
if (!(currmode & MODE_BOARD) && not_owned || !strcmp(cuser.userid, "guest"))
return DONOTHING;
getdata(1, 0, msg_del_ny, genbuf, 3, LCECHO);
if (genbuf[0] == 'y')
{
strcpy(currfile, fhdr->filename);
/*
if (!update_file(direct, sizeof(fileheader), ent, cmpfilename, lazy_delete))
*/
setbfile(genbuf,currboard,fhdr->filename);
money = (int) dashs(genbuf) / 25;
if (!delete_file (direct, sizeof(fileheader), ent, cmpfilename)) {
if( currmode & MODE_SELECT ){
int now;
setbdir(genbuf,currboard);
now=getindex(genbuf,fhdr->filename,sizeof(fileheader));
delete_file (genbuf, sizeof(fileheader),now,cmpfilename);
}
cancelpost(fhdr, not_owned);
if (!not_owned && strcmp(currboard, "Test"))
{
if (cuser.numposts)
cuser.numposts--;
UPDATE_USEREC;
move(b_lines - 1, 0);
clrtoeol();
if(money<0) money = 0;
demoney(money);
prints("%s,您的文章減為 %d 篇,支付清潔費 %d 銀", msg_del_ok,
cuser.numposts,money);
refresh();
sleep(1);
}
/*
lazy_delete(fhdr);
return FULLUPDATE;
*/
return DIRCHANGED;
}
}
return FULLUPDATE;
}
/* ----------------------------------------------------- */
/* 依序讀新文章 */
/* ----------------------------------------------------- */
static int sequent_ent;
static int
sequent_messages(fptr)
fileheader *fptr;
{
static int idc;
char ans[6];
char genbuf[200];
if (fptr == NULL)
return (idc = 0);
if (++idc < sequent_ent)
return 0;
if (!brc_unread(fptr->filename))
return 0;
if (continue_flag)
{
genbuf[0] = 'y';
}
else
{
prints("讀取文章於:[%s] 作者:[%s]\n標題:[%s]",
currboard, fptr->owner, fptr->title);
getdata(3, 0, "(Y/N/Quit) [Y]: ", genbuf, 3, LCECHO);
}
if (genbuf[0] != 'y' && genbuf[0])
{
clear();
return (genbuf[0] == 'q' ? QUIT : 0);
}
setbfile(genbuf, currboard, fptr->filename);
brc_addlist(fptr->filename);
if (more(genbuf, YEA) == 0)
outmsg(" (R)回信 (↓,n)下一封 (←,q)離開 ");
continue_flag = 0;
switch (egetch())
{
case KEY_LEFT:
case 'e':
case 'q':
case 'Q':
break;
case 'y':
case 'r':
case 'Y':
case 'R':
if (currmode & MODE_POST)
{
strcpy(quote_file, genbuf);
do_reply(fptr);
*quote_file = 0;
}
break;
case ' ':
case KEY_DOWN:
case '\n':
case 'n':
continue_flag = 1;
}
clear();
return 0;
}
static int
sequential_read(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char buf[40];
clear();
sequent_messages((fileheader *) NULL);
sequent_ent = ent;
continue_flag = 0;
setbdir(buf, currboard);
apply_record(buf, sequent_messages, sizeof(fileheader));
return FULLUPDATE;
}
/* ----------------------------------------------------- */
/* 看板備忘錄、文摘、精華區 */
/* ----------------------------------------------------- */
static int
b_notes_edit()
{
if (currmode & MODE_BOARD)
{
struct stat st;
char buf[64];
int aborted;
setbfile(buf, currboard, fn_notes);
aborted = vedit(buf, NA);
if (aborted == -1)
{
clear();
outs(msg_cancel);
pressanykey();
}
else
{
boardheader fh;
int pos;
getdata(3, 0, "請設定有效期限(0 - 9999)天?", buf, 5, DOECHO);
aborted = atol(buf);
pos = search_record(fn_board, &fh, sizeof(fh), cmpbnames, currboard);
fh.bupdate = aborted ? time(0) + aborted * 86400 : 0;
substitute_record(fn_board, &fh, sizeof(fh), pos);
touch_boards();
}
return FULLUPDATE;
}
return 0;
}
static int
b_water_edit()
{
if (currmode & MODE_BOARD)
{
friend_edit(BOARD_WATER);
return FULLUPDATE;
}
return 0;
}
static int
visable_list_edit()
{
if (currmode & MODE_BOARD)
{
friend_edit(BOARD_VISABLE);
return FULLUPDATE;
}
return 0;
}
static int
can_vote_edit()
{
if (currmode & MODE_BOARD)
{
friend_edit(FRIEND_CANVOTE);
return FULLUPDATE;
}
return 0;
}
static int
bh_title_edit()
{
boardheader bp;
boardheader *getbcache();
int bid;
if (currmode & MODE_BOARD)
{
char genbuf[BTLEN];
bid = getbnum(currboard);
if (get_record(fn_board, &bp, sizeof(boardheader), bid) == -1)
{
outs(err_bid);
pressanykey();
return -1;
}
move(1,0);
clrtoeol();
getdata_str(1,0,"請輸入看板新中文敘述:", genbuf,BTLEN -
16,DOECHO, bp.title + 7);
if(!genbuf[0]) return 0;
strip_ansi( genbuf,genbuf,0);
strcpy(bp.title + 7,genbuf);
substitute_record(fn_board, &bp, sizeof(boardheader), bid);
touch_boards();
log_usies("SetBoard", currboard);
return FULLUPDATE;
}
return 0;
}
static int
b_notes()
{
char buf[64];
setbfile(buf, currboard, fn_notes);
if (more(buf, NA) == -1)
{
clear();
move(4, 20);
outs("本看板尚無「備忘錄」。");
}
pressanykey();
return FULLUPDATE;
}
int
board_select()
{
char fpath[80];
char genbuf[100];
currmode &= ~MODE_SELECT;
sprintf(fpath,"SR.%s",cuser.userid);
setbfile(genbuf,currboard,fpath);
unlink(genbuf);
if(currstat==RMAIL)
sethomedir(currdirect,cuser.userid);
else
setbdir(currdirect, currboard);
return NEWDIRECT;
}
int
board_digest()
{
if(currmode & MODE_SELECT)
board_select();
currmode ^= MODE_DIGEST;
if (currmode & MODE_DIGEST)
currmode &= ~MODE_POST;
else if (haspostperm(currboard))
currmode |= MODE_POST;
setbdir(currdirect, currboard);
return NEWDIRECT;
}
int
board_etc()
{
if (!HAS_PERM(PERM_SYSOP))
return DONOTHING;
currmode ^= MODE_ETC;
if (currmode & MODE_ETC)
currmode &= ~MODE_POST;
else if (haspostperm(currboard))
currmode |= MODE_POST;
setbdir(currdirect, currboard);
return NEWDIRECT;
}
static int
good_post(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char genbuf[200];
char genbuf2[200];
if ((currmode & MODE_DIGEST) || !(currmode & MODE_BOARD))
return DONOTHING;
if (fhdr->filemode & FILE_DIGEST)
{
fhdr->filemode = (fhdr->filemode & ~FILE_DIGEST);
}
else
{
fileheader digest;
char *ptr, buf[64];
memcpy(&digest, fhdr, sizeof(digest));
digest.filename[0] = 'G';
strcpy(buf, direct);
ptr = strrchr(buf, '/') + 1;
ptr[0] = '\0';
sprintf(genbuf, "%s%s", buf, digest.filename);
if (!dashf(genbuf)) {
digest.savemode = digest.filemode = 0;
sprintf(genbuf2, "%s%s", buf, fhdr->filename);
Link(genbuf2, genbuf);
strcpy(ptr, fn_mandex);
append_record(buf, &digest, sizeof(digest));
}
fhdr->filemode = (fhdr->filemode & ~FILE_MARKED) | FILE_DIGEST;
}
substitute_record(direct, fhdr, sizeof(*fhdr), ent);
if( currmode & MODE_SELECT){
int now;
char genbuf[100];
setbdir(genbuf,currboard);
now=getindex(genbuf,fhdr->filename,sizeof(fileheader));
substitute_record(genbuf,fhdr,sizeof(*fhdr),now);
}
return PART_REDRAW;
}
/* help for board reading */
static char *board_help[] =
{
"\0全功\能看板操作說明",
"\01基本命令",
"(p)(↑) 上移一篇文章 (^P) 發表文章",
"(n)(↓) 下移一篇文章 (d) 刪除文章",
"(P)(PgUp) 上移一頁 (S) 循序閱\讀新文章",
"(N)(PgDn) 下移一頁 (##) 跳到 ## 號文章",
"(r)(→) 閱\讀此篇文章 ($) 跳到最後一篇文章",
"\01進階命令",
"(tab)/z 文摘模式/精華區 (a)(A) 找尋作者",
"(b) 展讀備忘錄 (?)(/) 找尋標題",
"(V,R) 投票/查詢投票結果 (=) 找尋首篇文章",
"(x) 轉錄文章到其他看板 ([]<>-+) 主題式閱\讀",
#ifdef INTERNET_EMAIL
"(F) 將文章寄回 Internet 郵箱",
"(U) 將文章 uuencode 後寄回郵箱",
#endif
"(Z) Z-modem 傳檔",
"(E) 重編文章",
"\01板主命令",
"(m) 保留此篇文章 (W/w/v) 編輯備忘錄/水桶名單/可看見名單",
"(M/o) 舉行投票/編私投票名單 (c/g) 選錄精華/文摘",
"(D) 刪除一段範圍的文章 (T/B) 重編文章標題/重編看版標題",
NULL
};
static int
b_help()
{
show_help(board_help);
return FULLUPDATE;
}
/* ----------------------------------------------------- */
/* 看板功能表 */
/* ----------------------------------------------------- */
extern int b_vote();
extern int b_results();
extern int b_vote_maintain();
struct one_key read_comms[] = {
KEY_TAB, board_digest,
'C', board_etc,
'b', b_notes,
'c', cite_post,
'r', read_post,
'z', b_man,
'D', del_range,
/*
woju
Ctrl('D'), del_one,
*/
'S', sequential_read,
'E', edit_post,
'T', edit_title,
's', do_select,
'R', b_results,
'V', b_vote,
'M', b_vote_maintain,
'B', bh_title_edit,
'W', b_notes_edit,
't', post_tag,
'w', b_water_edit,
'v', visable_list_edit,
'o', can_vote_edit,
Ctrl('D'), post_del_tag,
'x', cross_post,
'h', b_help,
'g', good_post,
'y', reply_post,
'd', del_post,
'm', mark_post,
Ctrl('P'), do_post,
'\0', NULL
};
ReadSelect()
{
int mode0 = currutmp->mode;
int stat0 = currstat;
char genbuf[200];
currstat = XMODE;
if (do_select(0, 0, genbuf) == NEWDIRECT)
Read();
currutmp->mode = mode0;
currstat = stat0;
}
void
log_board( mode, usetime )
char *mode;
time_t usetime;
{
time_t now;
FILE *fp;
char buf[ 256 ];
now = time(0);
sprintf( buf, "USE %-20.20s Stay: %5ld (%s) %s",
mode, usetime ,cuser.userid ,ctime(&now)+4);
if( (fp = fopen(FN_USEBOARD, "a" )) != NULL ) {
fputs( buf, fp );
fclose( fp );
}
}
int
Read()
{
int mode0 = currutmp->mode;
int stat0 = currstat;
char buf[40];
time_t usetime = time(0);
setutmpmode(READING);
set_board();
if (board_visit_time < board_note_time)
{
setbfile(buf, currboard, fn_notes);
more(buf, NA);
pressanykey();
}
setbdir(buf, currboard);
curredit &= ~EDIT_MAIL;
i_read(READING, buf, readtitle, readdoent, read_comms);
log_board(currboard, time(0) - usetime);
brc_update();
currutmp->mode = mode0;
currstat = stat0;
return 0;
}
int
Select()
{
char genbuf[200];
setutmpmode(SELECT);
do_select(0, NULL, genbuf);
return 0;
}
int
Post()
{
do_post();
return 0;
}