diff options
Diffstat (limited to 'mbbsd/bbs.c')
-rw-r--r-- | mbbsd/bbs.c | 1904 |
1 files changed, 1904 insertions, 0 deletions
diff --git a/mbbsd/bbs.c b/mbbsd/bbs.c new file mode 100644 index 00000000..15db1c91 --- /dev/null +++ b/mbbsd/bbs.c @@ -0,0 +1,1904 @@ +/* $Id: bbs.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "config.h" +#include "pttstruct.h" +#include "perm.h" +#include "modes.h" +#include "common.h" +#include "proto.h" + +static int g_board_names(boardheader_t *fhdr) { + AddNameList(fhdr->brdname); + return 0; +} + +extern userec_t cuser; +extern void touchdircache(int bid); +extern int TagNum; + +static void mail_by_link(char* owner, char* title, char* path) { + char genbuf[200]; + fileheader_t mymail; + + sprintf(genbuf,BBSHOME"/home/%c/%s", cuser.userid[0], cuser.userid); + stampfile(genbuf, &mymail); + strcpy(mymail.owner, owner); + sprintf(mymail.title, title); + mymail.savemode = 0; + unlink(genbuf); + Link(path, genbuf); + sprintf(genbuf,BBSHOME"/home/%c/%s/.DIR",cuser.userid[0],cuser.userid); + + append_record(genbuf, &mymail, sizeof(mymail)); +} + +extern int usernum; + +void anticrosspost() { + char buf[200]; + time_t now = time(NULL); + + sprintf(buf, + "\033[1;33;46m%s \033[37;45mcross post 文章 \033[37m %s\033[m", + cuser.userid, ctime(&now)); + log_file("etc/illegal_money", buf); + + post_violatelaw(cuser.userid, "Ptt系統警察", "Cross-post", "罰單處份"); + cuser.userlevel |= PERM_VIOLATELAW; + cuser.vl_count ++; + mail_by_link("Ptt警察部隊", "Cross-Post罰單", + BBSHOME "/etc/crosspost.txt"); + passwd_update(usernum, &cuser); + exit(0); +} + +/* Heat CharlieL*/ +int save_violatelaw() { + char buf[128], ok[3]; + + setutmpmode(VIOLATELAW); + clear(); + stand_title("繳罰單中心"); + + if(!(cuser.userlevel & PERM_VIOLATELAW)) { + mprints(22, 0, "\033[1;31m你無聊啊? 你又沒有被開罰單~~\033[m"); + pressanykey(); + return 0; + } + + reload_money(); + if(cuser.money < (int)cuser.vl_count*1000) { + sprintf(buf, "\033[1;31m這是你第 %d 次違反本站法規" + "必須繳出 %d $Ptt ,你只有 %d 元, 錢不夠啦!!\033[m", + (int)cuser.vl_count, (int)cuser.vl_count * 1000, cuser.money); + mprints(22, 0, buf); + pressanykey(); + return 0; + } + + move(5,0); + prints("\033[1;37m你知道嗎? 因為你的違法 " + "已經造成很多人的不便\033[m\n"); + prints("\033[1;37m你是否確定以後不會再犯了?\033[m\n"); + + if(!getdata(10,0,"確定嗎?[y/n]:", ok, 2, LCECHO) || + ok[0] == 'n' || ok[0] == 'N') { + mprints(22,0,"\033[1;31m等你想通了再來吧!! " + "我相信你不會知錯不改的~~~\033[m"); + pressanykey(); + return 0; + } + + sprintf(buf, "這是你第 %d 次違法 必須繳出 %d $Ptt", + cuser.vl_count, cuser.vl_count*1000); + mprints(11,0,buf); + + if(!getdata(10, 0, "要付錢[y/n]:", ok, 2, LCECHO) || + ok[0] == 'N' || ok[0] == 'n') { + + mprints(22,0, "\033[1;31m 嗯 存夠錢 再來吧!!!\033[m"); + pressanykey(); + return 0; + } + + demoney(-1000*cuser.vl_count); + cuser.userlevel &= (~PERM_VIOLATELAW); + passwd_update(usernum, &cuser); + return 0; +} + +void make_blist() { + CreateNameList(); + apply_boards(g_board_names); +} + +extern int currbid; +extern char currBM[]; +extern int currmode; +extern char currboard[]; +static time_t board_note_time; +static char *brd_title; + +void set_board() { + boardheader_t *bp; + + bp = getbcache(currbid); + board_note_time = bp->bupdate; + brd_title = bp->BM; + if(brd_title[0] <= ' ') + brd_title = "徵求中"; + sprintf(currBM, "板主:%s", brd_title); + brd_title = ((bp->bvote != 2 && bp->bvote) ? "本看板進行投票中" : + bp->title + 7); + currmode = (currmode & (MODE_DIRTY | MODE_MENU)) | MODE_STARTED ; + + if (HAS_PERM(PERM_ALLBOARD) || is_BM(bp->BM)) + currmode = 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\033[7m 編號 日 期 作 者 文 章 標 題" + " \033[m"); +} + +extern int brc_num; +extern int brc_list[]; +extern char currtitle[]; + +extern int Tagger(); + +static void readdoent(int num, fileheader_t *ent) { + int type; + char *mark, *title, color; + + type = brc_unread(ent->filename,brc_num,brc_list) ? '+' : ' '; + + if((currmode & MODE_BOARD) && (ent->filemode & FILE_DIGEST)) + type = (type == ' ') ? '*' : '#'; + else if(currmode & MODE_BOARD || HAS_PERM(PERM_LOGINOK)) { + if(ent->filemode & FILE_MARKED) + type = (type == ' ') ? 'm' : 'M'; + + else if (TagNum && !Tagger(atoi(ent->filename + 2), 0, TAG_NIN)) + type = 'D'; + + else if (ent->filemode & FILE_SOLVED) + type = 's'; + } + + 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.12s\033[1;3%cm%s %s\033[m\n", num, type, + ent->date, ent->owner, color, mark, title); +} + +extern char currfile[]; + +int cmpfilename(fileheader_t *fhdr) { + return (!strcmp(fhdr->filename, currfile)); +} + +extern unsigned char currfmode; + +int cmpfmode(fileheader_t *fhdr) { + return (fhdr->filemode & currfmode); +} + +extern char currowner[]; + +int cmpfowner(fileheader_t *fhdr) { + return !strcasecmp(fhdr->owner, currowner); +} + +extern char *err_bid; +extern userinfo_t *currutmp; + +int whereami(int ent, fileheader_t *fhdr, char *direct) { + boardheader_t *bh, *p[32], *root; + int i,j; + + if(!currutmp->brc_id) return 0; + + move(1,0); + clrtobot(); + bh=getbcache(currutmp->brc_id); + root=getbcache(1); + p[0]=bh; + for(i=0;i<31 && p[i]->parent!=root && p[i]->parent;i++) + p[i+1]=p[i]->parent; + j=i; + prints("我在哪?\n%-40.40s %.13s\n", p[j]->title+7, p[j]->BM); + for(j--;j>=0;j--) + prints("%*s %-13.13s %-37.37s %.13s\n", (i-j)*2, "", + p[j]->brdname, p[j]->title, + p[j]->BM); + + pressanykey(); + return FULLUPDATE; +} +static int do_select(int ent, fileheader_t *fhdr, char *direct) { + char bname[20]; + char bpath[60]; + boardheader_t *bh; + struct stat st; + int i; + + move(0, 0); + clrtoeol(); + make_blist(); + namecomplete(MSG_SELECT_BOARD, bname); + if(bname[0]=='\0' || !(i = getbnum(bname))) + return FULLUPDATE; + bh = getbcache(i); + if(!Ben_Perm(bh)) return FULLUPDATE; + strcpy(bname, bh->brdname); + currbid=i; + + setbpath(bpath, bname); + if((*bname == '\0') || (stat(bpath, &st) == -1)) { + move(2, 0); + clrtoeol(); + outs(err_bid); + return FULLUPDATE; + } + + currutmp->brc_id = currbid; + + brc_initial(bname); + set_board(); + setbdir(direct, currboard); + + move(1, 0); + clrtoeol(); + return NEWDIRECT; +} + +/* ----------------------------------------------------- */ +/* 改良 innbbsd 轉出信件、連線砍信之處理程序 */ +/* ----------------------------------------------------- */ +void outgo_post(fileheader_t *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); + } +} + +extern char *str_author1; +extern char *str_author2; + +static void cancelpost(fileheader_t *fh, int by_BM) { + FILE *fin, *fout; + char *ptr, *brd; + fileheader_t 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)); + } +} + +extern char *str_reply; +extern char save_title[]; + +/* ----------------------------------------------------- */ +/* 發表、回應、編輯、轉錄文章 */ +/* ----------------------------------------------------- */ +void do_reply_title(int row, char *title) { + char genbuf[200]; + char genbuf2[4]; + + if(strncasecmp(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[0] == 'n' || genbuf2[0] == 'N') + getdata(++row, 0, "標題:", save_title, TTLEN, DOECHO); +} + +static void do_unanonymous_post(char* fpath) { + fileheader_t mhdr; + char title[128]; + 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)); + } +} + +extern char quote_file[]; +extern char quote_user[]; +extern int curredit; +extern unsigned int currbrdattr; +extern char currdirect[]; +extern char *err_uid; + +#ifdef NO_WATER_POST +static time_t last_post_time = 0; +static time_t water_counts = 0; +#endif +int local_article; +char real_name[20]; + +static int do_general() { + fileheader_t postfile; + char fpath[80], buf[80]; + int aborted, defanony, ifuseanony; + char genbuf[200],*owner; + boardheader_t *bp; + int islocal; + + ifuseanony = 0; + bp = getbcache(currbid); + + clear(); + if(!(currmode & MODE_POST)) { + move(5, 10); + outs("對不起,您目前無法在此發表文章!"); + pressanykey(); + return FULLUPDATE; + } + +#ifdef NO_WATER_POST + /* 三分鐘內最多發表五篇文章 */ + if(currutmp->lastact - last_post_time < 60 * 3) { + if(water_counts >= 5) { + move(5, 10); + outs("對不起,您的文章太水囉,多思考一下,待會再post吧!"); + pressanykey(); + return FULLUPDATE; + } + } else { + last_post_time = currutmp->lastact; + water_counts = 0; + } +#endif + + setbfile(genbuf, currboard, FN_POST_NOTE ); + + if(more(genbuf,NA) == -1) + more("etc/"FN_POST_NOTE , NA); + + move(19,0); + prints("發表文章於【\033[33m %s\033[m 】 \033[32m%s\033[m 看板\n\n", + currboard, bp->title + 7); + + 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; + curredit &= ~EDIT_ITEM; + setutmpmode(POSTING); + + /* 未具備 Internet 權限者,只能在站內發表文章 */ + if(HAS_PERM(PERM_INTERNET)) + local_article = 0; + else + local_article = 1; + + /* build filename */ + setbpath(fpath, currboard); + stampfile(fpath, &postfile); + + aborted = vedit(fpath, YEA, &islocal); + if(aborted == -1) { + unlink(fpath); + pressanykey(); + return FULLUPDATE; + } + water_counts++; /* po成功 */ + + /* set owner to Anonymous , for Anonymous board */ + +#ifdef HAVE_ANONYMOUS + /* Ptt and Jaky */ + defanony=currbrdattr & BRD_DEFAULTANONYMOUS; + if((currbrdattr & BRD_ANONYMOUS) && + ((strcmp(real_name,"r") && defanony) || (real_name[0] && !defanony)) + ) { + strcat(real_name,"."); + owner = real_name; + ifuseanony=1; + } else + owner = cuser.userid; +#else + owner = cuser.userid; +#endif + /* 錢 */ + aborted = (aborted > MAX_POST_MONEY * 2) ? MAX_POST_MONEY : aborted / 2; + postfile.money = aborted; + strcpy(postfile.owner, owner); + strcpy(postfile.title, save_title); + if(islocal) { /* local save */ + postfile.savemode = 'L'; + postfile.filemode = FILE_LOCAL; + } else + postfile.savemode = 'S'; + + setbdir(buf, currboard); + if(append_record(buf, &postfile, sizeof(postfile)) != -1) { + setbtotal(currbid); + + if(currmode & MODE_SELECT) + append_record(currdirect,&postfile,sizeof(postfile)); + if(!islocal && !(bp->brdattr & BRD_NOTRAN)) + outgo_post(&postfile, currboard); + brc_addlist(postfile.filename); + + if(!(currbrdattr & BRD_HIDE) && + (!bp->level || (currbrdattr & BRD_POSTMASK))) { + setbpath(genbuf, ALLPOST); + stampfile(genbuf, &postfile); + unlink(genbuf); + + /* jochang: boards may spread across many disk */ + /* link doesn't work across device, + Link doesn't work if we have same-time-across-device posts, + we try symlink now */ + { + /* we need absolute path for symlink */ + char abspath[256]=BBSHOME"/"; + strcat(abspath,fpath); + symlink(abspath,genbuf); + } + strcpy(postfile.owner, owner); + strcpy(postfile.title, save_title); + postfile.savemode = 'L'; + setbdir(genbuf, ALLPOST); + if(append_record(genbuf, &postfile, sizeof(postfile)) != -1) { + setbtotal(getbnum(ALLPOST)); + } + } + + outs("順利貼出佈告,"); + +#ifdef MAX_POST_MONEY + aborted = (aborted > MAX_POST_MONEY) ? MAX_POST_MONEY : aborted; +#endif + if(strcmp(currboard, "Test") && !ifuseanony) { + prints("這是您的第 %d 篇文章。 稿酬 %d 銀。", + ++cuser.numposts, aborted ); + demoney(aborted); + passwd_update(usernum, &cuser); /* post 數 */ + } else + outs("測試信件不列入紀錄,敬請包涵。"); + + /* 回應到原作者信箱 */ + + if(curredit & EDIT_BOTH) { + char *str, *msg = "回應至作者信箱"; + + if((str = strchr(quote_user, '.'))) { + if( +#ifndef USE_BSMTP + bbs_sendmail(fpath, save_title, str + 1) +#else + bsmtp(fpath, save_title, str + 1 ,0) +#endif + < 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(currbrdattr & BRD_ANONYMOUS) + do_unanonymous_post(fpath); + } + pressanykey(); + return FULLUPDATE; +} + +int do_post() { + boardheader_t *bp; + bp = getbcache(currbid); + if(bp->brdattr & BRD_VOTEBOARD) + return do_voteboard(); + else if(!(bp->brdattr & BRD_GROUPBOARD)) + return do_general(); + touchdircache(currbid); + return 0; +} + +extern int b_lines; +extern int curredit; + +static void do_generalboardreply(fileheader_t *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; +} + +int getindex(char *fpath, char *fname, int size) { + int fd, now=0; + fileheader_t 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 invalid_brdname(char *brd) { + register char ch; + + ch = *brd++; + if(not_alnum(ch)) + return 1; + while((ch = *brd++)) { + if(not_alnum(ch) && ch != '_' && ch != '-' && ch != '.') + return 1; + } + return 0; +} + +static void do_reply(fileheader_t *fhdr) { + boardheader_t *bp; + bp = getbcache(currbid); + if (bp->brdattr & BRD_VOTEBOARD) + do_voteboardreply(fhdr); + else + do_generalboardreply(fhdr); +} + +static int reply_post(int ent, fileheader_t *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(int ent, fileheader_t *fhdr, char *direct) { + char fpath[80], fpath0[80]; + char genbuf[200]; + fileheader_t postfile; + boardheader_t *bp; + bp = getbcache(currbid); + if (!HAS_PERM(PERM_SYSOP) && (bp->brdattr & BRD_VOTEBOARD)) + return DONOTHING; + + if ((!HAS_PERM(PERM_SYSOP)) && + strcmp(fhdr->owner, cuser.userid)) + return DONOTHING; + setutmpmode(REEDIT); + setdirpath(genbuf, direct, fhdr->filename); + local_article = fhdr->filemode & FILE_LOCAL; + strcpy(save_title, fhdr->title); + +/* rocker.011018: 這裡是不是該檢查一下修改文章後的money和原有的比較? */ + if(vedit(genbuf, 0, NULL) != -1) { + setbpath(fpath, currboard); + stampfile(fpath, &postfile); + unlink(fpath); + setbfile(fpath0, currboard, fhdr->filename); + + Rename(fpath0, fpath); + +/* rocker.011018: fix 串接模式改文章後文章就不見的bug */ + if ((currmode & MODE_SELECT) && (fhdr->money & FHR_REFERENCE)) + { + fileheader_t hdr; + int num; + + num = fhdr->money & ~FHR_REFERENCE; + setbdir(fpath0, currboard); + get_record(fpath0, &hdr, sizeof (hdr), num); + + /* 再這裡要check一下原來的dir裡面是不是有被人動過... */ + if (!strcmp (hdr.filename, fhdr->filename)) + { + strcpy(hdr.filename, postfile.filename); + strcpy(hdr.title, save_title); + substitute_record(fpath0, &hdr, sizeof(hdr), num); + } + } + + strcpy(fhdr->filename, postfile.filename); + strcpy(fhdr->title, save_title); + brc_addlist(postfile.filename); + substitute_record(direct, fhdr, sizeof(*fhdr), ent); +/* rocker.011018: 順便更新一下cache */ + touchdircache(currbid); + } + return FULLUPDATE; +} + +extern crosspost_t postrecord; +#define UPDATE_USEREC (currmode |= MODE_DIRTY) + +static int cross_post(int ent, fileheader_t *fhdr, char *direct) { + char xboard[20], fname[80], xfpath[80], xtitle[80], inputbuf[10]; + fileheader_t xfile; + FILE *xptr; + int author = 0; + char genbuf[200]; + char genbuf2[4]; + boardheader_t *bp; + make_blist(); + move(2, 0); + clrtoeol(); + move(3, 0); + clrtoeol(); + move(1, 0); + bp = getbcache(currbid); + if (bp && (bp->brdattr & BRD_VOTEBOARD)) + return FULLUPDATE; + namecomplete("轉錄本文章於看板:", xboard); + if(*xboard == '\0' || !haspostperm(xboard)) + return FULLUPDATE; + + if((ent = str_checksum(fhdr->title)) != 0 && + ent == postrecord.checksum[0]) { + /* 檢查 cross post 次數 */ + if(postrecord.times++ > MAX_CROSSNUM) + anticrosspost(); + } else { + postrecord.times = 0; + postrecord.checksum[0] = ent; + } + + 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[0] == 'n' || genbuf2[0] == 'N') { + if(getdata_str(2, 0, "標題:", genbuf, TTLEN, DOECHO,xtitle)) + 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,0); + fclose(xptr); +/* Cross fs有問題 + } else { + unlink(xfpath); + link(fname, xfpath); + } +*/ + setbdir(fname, xboard); + append_record(fname, &xfile, sizeof(xfile)); + bp = getbcache(getbnum(xboard)); + if(!xfile.filemode && !(bp->brdattr && BRD_NOTRAN)) + outgo_post(&xfile, xboard); + setbtotal(getbnum(xboard)); + cuser.numposts++; + UPDATE_USEREC; + outs("文章轉錄完成"); + pressanykey(); + currmode = currmode0; + } + return FULLUPDATE; +} + +static int read_post(int ent, fileheader_t *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); + + 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("\033[34;46m 閱\讀文章 \033[31;47m (R/Y)\033[30m回信 \033[31m" + "(=[]<>)\033[30m相關主題 \033[31m(↑↓)\033[30m上下封 \033[31m(←)" + "\033[30m離開 \033[m"); + + 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; + + case Ctrl('C'): + cal(); + return FULLUPDATE; + break; + + 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; +} + +/* ----------------------------------------------------- */ +/* 採集精華區 */ +/* ----------------------------------------------------- */ +static int b_man() { + char buf[64]; + + setapath(buf, currboard); + if( (currmode & MODE_BOARD) || HAS_PERM(PERM_SYSOP) ){ + char genbuf[128]; + int fd; + sprintf(genbuf, "%s/.rebuild", buf); + if( (fd = open(genbuf, O_CREAT, 0640)) > 0 ) + close(fd); + } + return a_menu(currboard, buf, HAS_PERM(PERM_ALLBOARD) ? 2 : + (currmode & MODE_BOARD ? 1 : 0)); +} + +#ifndef NO_GAMBLE +static int join_gamble(int ent, fileheader_t *fhdr, char *direct) { + ticket(currbid); + return FULLUPDATE; +} +static int hold_gamble(int ent, fileheader_t *fhdr, char *direct) { + char fn_ticket[128],fn_ticket_end[128],genbuf[128], + msg[256]="",yn[10]=""; + int i; + FILE *fp=NULL; + + if(!(currmode & MODE_BOARD)) return 0; + setbfile(fn_ticket, currboard, FN_TICKET); + setbfile(fn_ticket_end, currboard, FN_TICKET_END); + if(dashf(fn_ticket)) + { + getdata(b_lines - 1, 0, "已經有舉辦賭盤, " + "是否要 [停止下注]?(N/y):", yn, 3, LCECHO); + if(yn[0]!='y') return FULLUPDATE; + rename(fn_ticket, fn_ticket_end); + return FULLUPDATE; + } + + if(dashf(fn_ticket_end)) + { + getdata(b_lines - 1, 0, "已經有舉辦賭盤, " + "是否要 [開獎]?(N/y):", yn, 3, LCECHO); + if(yn[0]!='y') return FULLUPDATE; + openticket(currbid); + return FULLUPDATE; + } + getdata(b_lines - 2, 0, "要舉辦賭盤 (N/y):", yn, 3, LCECHO); + if(yn[0]!='y') return FULLUPDATE; + getdata(b_lines - 1, 0, "賭什麼? 請輸入主題 (輸入後編輯內容):", + msg, 20, DOECHO); + if(msg[0]==0 || + vedit(fn_ticket_end, NA, NULL)<0) + return FULLUPDATE; + + clear(); + showtitle("舉辦賭盤",BBSNAME); + setbfile(genbuf, currboard, FN_TICKET_ITEMS); + +// sprintf(genbuf, "%s/"FN_TICKET_ITEMS, direct); + + if(!(fp=fopen(genbuf,"w"))) return FULLUPDATE; + do + { + getdata(2, 0, "輸入彩票價格 (價格:10-10000):",yn,6, LCECHO); + i=atoi(yn); + } while( i<10 || i>10000); + fprintf(fp,"%d\n",i); + move(3,0); + sprintf(genbuf,"請到 %s 版 按'f'參與賭博!\n\n一張 %d Ptt幣, 這是%s的賭博\n", + currboard, + i, i<100 ? "小賭式" : i<500 ? "平民級": + i<1000 ?"貴族級" : i<5000 ?"富豪級" : "傾家蕩產"); + strcat(msg, genbuf); + prints("請依次輸入彩票名稱, 需提供2~8項. (未滿八項, 輸入直接按enter)\n"); + for(i=0; i<8; i++) + { + sprintf(yn, " %d)",i+1); + getdata(6+i, 0, yn, genbuf, 9, DOECHO); + if(!genbuf[0] && i>1) + break; + fprintf(fp,"%s\n",genbuf); + } + fclose(fp); + move(8+i,0); + prints("賭盤設定完成"); + sprintf(genbuf,"[公告] %s 版 開始賭博!", currboard); + post_msg(currboard, genbuf, msg, cuser.userid); + post_msg("Record", genbuf+7, msg, "[馬路探子]"); + /* Tim 控制CS, 以免正在玩的user把資料已經寫進來 */ + rename(fn_ticket_end, fn_ticket); // 設定完才把檔名改過來 + + return FULLUPDATE; +} +#endif + +static int cite_post(int ent, fileheader_t *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, 1); + b_man(); + return FULLUPDATE; +} + +int edit_title(int ent, fileheader_t *fhdr, char *direct) { + char genbuf[200]; + fileheader_t tmpfhdr = *fhdr; + int dirty = 0; + + if(currmode & MODE_BOARD || !strcmp(cuser.userid,fhdr->owner)) { + if(getdata(b_lines - 1, 0, "標題:", genbuf, TTLEN, DOECHO)) { + strcpy(tmpfhdr.title, genbuf); + dirty++; + } + } + + if(HAS_PERM(PERM_SYSOP)) { + 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(currmode & MODE_BOARD || !strcmp(cuser.userid,fhdr->owner)) { + getdata(b_lines-1, 0, "確定(Y/N)?[n] ", genbuf, 3, DOECHO); + if((genbuf[0] == 'y' || genbuf[0] == 'Y') && dirty) { + *fhdr = tmpfhdr; + substitute_record(direct, fhdr, sizeof(*fhdr), ent); +/* rocker.011018: 這裡應該改成用reference的方式取得原來的檔案 */ +#if 0 + if((currmode & MODE_SELECT)) { + int now; + + setbdir(genbuf, currboard); + now = getindex(genbuf, fhdr->filename, sizeof(fileheader_t)); + substitute_record(genbuf, fhdr, sizeof(*fhdr), now); + } +#else + if ((currmode & MODE_SELECT) && (fhdr->money & FHR_REFERENCE)) + { + fileheader_t hdr; + int num; + + num = fhdr->money & ~FHR_REFERENCE; + setbdir(genbuf, currboard); + get_record(genbuf, &hdr, sizeof (hdr), num); + + /* 再這裡要check一下原來的dir裡面是不是有被人動過... */ + if (strcmp (hdr.filename, fhdr->filename)) + num = getindex(genbuf, fhdr->filename, sizeof(fileheader_t)); + + substitute_record(genbuf, fhdr, sizeof(*fhdr), num); + } +#endif + touchdircache(currbid); + } + return FULLUPDATE; + } + return DONOTHING; +} + +extern unsigned int currstat; + +static int solve_post(int ent, fileheader_t * fhdr, char *direct){ + if (HAS_PERM(PERM_SYSOP)) { + fhdr->filemode ^= FILE_SOLVED; + substitute_record(direct, fhdr, sizeof(*fhdr), ent); + touchdircache(currbid); + return PART_REDRAW; + } + return DONOTHING; +} + +static int mark_post(int ent, fileheader_t *fhdr, char *direct) { + + if(!(currmode & MODE_BOARD)) return DONOTHING; + + fhdr->filemode ^= FILE_MARKED; + substitute_record(direct, fhdr, sizeof(*fhdr), ent); + + /* rocker.011018: 串接模式用reference增進效率 */ + if ((currmode & MODE_SELECT) && (fhdr->money & FHR_REFERENCE)) + { + fileheader_t hdr; + char genbuf[100]; + int num; + + num = fhdr->money & ~FHR_REFERENCE; + setbdir(genbuf, currboard); + get_record(genbuf, &hdr, sizeof (hdr), num); + + /* 再這裡要check一下原來的dir裡面是不是有被人動過... */ + if (strcmp (hdr.filename, fhdr->filename)) + num = getindex(genbuf, fhdr->filename, sizeof(fileheader_t)); + + substitute_record(genbuf, fhdr, sizeof(*fhdr), num); + } + touchdircache(currbid); + return PART_REDRAW; +} + +extern char *msg_sure_ny; + +int del_range(int ent, fileheader_t *fhdr, char *direct) { + char num1[8], num2[8]; + int inum1, inum2; + +/* rocker.011018: 串接模式下還是不允許刪除比較好 */ + if(currmode & MODE_SELECT) { + outmsg("請先回到正常模式後再進行刪除..."); + refresh(); + /*safe_sleep(1);*/ + return FULLUPDATE; + } + + if((currstat != READING) || (currmode & MODE_BOARD)) { + getdata(1, 0, "[設定刪除範圍] 起點:", num1, 5, DOECHO); + inum1 = atoi(num1); + if(inum1 <= 0) { + outmsg("起點有誤"); + refresh(); + /*safe_sleep(1);*/ + return FULLUPDATE; + } + getdata(1, 28, "終點:", num2, 5, DOECHO); + inum2 = atoi(num2); + if(inum2 < inum1) { + outmsg("終點有誤"); + refresh(); + /*safe_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_t); + char genbuf[100]; + fileheader_t 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_t), now, + cmpfilename); + i++; + } + } + close(fd); + } + } + + delete_range(direct, inum1, inum2); + fixkeep(direct, inum1); + + if(currmode & MODE_BOARD) + setbtotal(currbid); + + return DIRCHANGED; + } + return FULLUPDATE; + } + return DONOTHING; +} + +extern char *msg_del_ny; +extern char *msg_del_ok; + +static int del_post(int ent, fileheader_t *fhdr, char *direct) { + char genbuf[100]; + int not_owned; + boardheader_t *bp; + + bp = getbcache(currbid); + + 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) || + ((bp->brdattr & BRD_VOTEBOARD) && !HAS_PERM(PERM_SYSOP)) || + !strcmp(cuser.userid, STR_GUEST)) + return DONOTHING; + + getdata(1, 0, msg_del_ny, genbuf, 3, LCECHO); + if(genbuf[0] == 'y' || genbuf[0] == 'Y') { + strcpy(currfile, fhdr->filename); + + setbfile(genbuf,currboard,fhdr->filename); + if(!delete_file (direct, sizeof(fileheader_t), ent, cmpfilename)) { + + if(currmode & MODE_SELECT) + { + /* rocker.011018: 利用reference減低loading */ + fileheader_t hdr; + int num; + + num = fhdr->money & ~FHR_REFERENCE; + setbdir(genbuf, currboard); + get_record(genbuf, &hdr, sizeof (hdr), num); + + /* 再這裡要check一下原來的dir裡面是不是有被人動過... */ + if (strcmp (hdr.filename, fhdr->filename)) + { + num=getindex(genbuf,fhdr->filename,sizeof(fileheader_t)); + get_record(genbuf, &hdr, sizeof (hdr), num); + } + + /* rocker.011018: 這裡要還原被破壞的money */ + fhdr->money = hdr.money; + delete_file (genbuf, sizeof(fileheader_t), num, cmpfilename); + } + +#if 0 + { + setbdir(genbuf,currboard); + now=getindex(genbuf,fhdr->filename,sizeof(fileheader_t)); + delete_file (genbuf, sizeof(fileheader_t),now,cmpfilename); + } +#endif + cancelpost(fhdr, not_owned); + + setbtotal(currbid); + if (fhdr->money < 0) + fhdr->money = 0; + if (not_owned && strcmp(currboard, "Test")){ + deumoney(searchuser(fhdr->owner), -fhdr->money); + } + if(!not_owned && strcmp(currboard, "Test")) { + if(cuser.numposts) + cuser.numposts--; + move(b_lines - 1, 0); + clrtoeol(); + demoney(-fhdr->money); + passwd_update(usernum, &cuser); /* post 數 */ + prints("%s,您的文章減為 %d 篇,支付清潔費 %d 銀", msg_del_ok, + cuser.numposts,fhdr->money); + refresh(); + pressanykey(); + } + return DIRCHANGED; + } + } + return FULLUPDATE; +} + +static int view_postmoney(int ent, fileheader_t *fhdr, char *direct) { + move(b_lines - 1, 0); + clrtoeol(); + prints("這一篇文章值 %d 銀", fhdr->money); + refresh(); + pressanykey(); + return FULLUPDATE; +} + +#ifdef OUTJOBSPOOL +/* 看版備份 */ +static int tar_addqueue(int ent, fileheader_t *fhdr, char *direct) { + char email[60], qfn[80], ans[2]; + FILE *fp; + char bakboard, bakman; + clear(); + showtitle("看版備份", BBSNAME); + move(2, 0); + if( !((currmode & MODE_BOARD) || HAS_PERM(PERM_SYSOP)) ) { + move(5, 10); + outs("妳要是版主或是站長才能醬醬啊 -.-\"\""); + pressanykey(); + return FULLUPDATE; + } + + sprintf(qfn, BBSHOME "/jobspool/tarqueue.%s", currboard); + if( access(qfn, 0) == 0 ){ + outs("已經排定行程, 稍後會進行備份"); + pressanykey(); + return FULLUPDATE; + } + if( !getdata(4, 0, "請輸入目的信箱:", email, sizeof(email), DOECHO) ) + return FULLUPDATE; + + /* check email -.-"" */ + if( strstr(email, "@") == NULL || strstr(email, ".bbs@") != NULL ){ + move(6, 0); + outs("您指定的信箱不正確! "); + pressanykey(); + return FULLUPDATE; + } + + getdata(6, 0, "要備份看版內容嗎(Y/N)?[Y]", ans, 2, LCECHO); + bakboard = (ans[0] == 'n' || ans[0] =='N') ? 0 : 1; + getdata(7, 0, "要備份精華區內容嗎(Y/N)?[N]", ans, 2, LCECHO); + bakman = (ans[0] == 'y' || ans[0] =='Y') ? 1 : 0; + if( !bakboard && !bakman ){ + move(8, 0); + outs("可是我們只能備份看版或精華區的耶 ^^\"\"\""); + pressanykey(); + return FULLUPDATE; + } + + fp = fopen(qfn, "w"); + fprintf(fp, "%s\n", cuser.userid); + fprintf(fp, "%s\n", email); + fprintf(fp, "%d,%d\n", bakboard, bakman); + fclose(fp); + + move(10, 0); + outs("系統已經將您的備份排入行程, \n"); + outs("稍後將會在系統負荷較低的時候將資料寄給您~ :) "); + pressanykey(); + return FULLUPDATE; +} +#endif + +static int sequent_ent; +static int continue_flag; + +/* ----------------------------------------------------- */ +/* 依序讀新文章 */ +/* ----------------------------------------------------- */ +static int sequent_messages(fileheader_t *fptr) { + static int idc; + char genbuf[200]; + + if(fptr == NULL) + return (idc = 0); + + if(++idc < sequent_ent) + return 0; + + if(!brc_unread(fptr->filename,brc_num,brc_list)) + 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("\033[31;47m \033[31m(R)\033[30m回信 \033[31m(↓,n)" + "\033[30m下一封 \033[31m(←,q)\033[30m離開 \033[m"); + 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(int ent, fileheader_t *fhdr, char *direct) { + char buf[40]; + + clear(); + sequent_messages((fileheader_t *) NULL); + sequent_ent = ent; + continue_flag = 0; + setbdir(buf, currboard); + apply_record(buf, sequent_messages, sizeof(fileheader_t)); + return FULLUPDATE; +} + +extern char *fn_notes; +extern char *msg_cancel; +extern char *fn_board; + +/* ----------------------------------------------------- */ +/* 看板備忘錄、文摘、精華區 */ +/* ----------------------------------------------------- */ +int b_note_edit_bname(int bid) { + char buf[64]; + int aborted; + boardheader_t *fh=getbcache(bid); + + setbfile(buf, fh->brdname, fn_notes); + aborted = vedit(buf, NA, NULL); + if(aborted == -1) { + clear(); + outs(msg_cancel); + pressanykey(); + } else { + aborted = (fh->bupdate - time(0)) / 86400 + 1; + sprintf(buf,"%d", aborted > 0 ? aborted : 0); + getdata_buf(3, 0, "請設定有效期限(0 - 9999)天?", buf, 5, DOECHO); + aborted = atoi(buf); + fh->bupdate = aborted ? time(0) + aborted * 86400 : 0; + substitute_record(fn_board, fh, sizeof(boardheader_t), bid); + } + return 0; +} + +static int b_notes_edit() { + if(currmode & MODE_BOARD) { + b_note_edit_bname(currbid); + 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); + hbflreload(currbid); + return FULLUPDATE; + } + return 0; +} + +static int b_post_note() { + char buf[200], yn[3]; + + if(currmode & MODE_BOARD) { + setbfile(buf, currboard, FN_POST_NOTE ); + if(more(buf,NA) == -1) more("etc/"FN_POST_NOTE , NA); + getdata(b_lines - 2, 0, "是否要用自訂post注意事項?", yn, 3, LCECHO); + if(yn[0] == 'y') + vedit(buf, NA, NULL); + else + unlink(buf); + return FULLUPDATE; + } + return 0; +} + +static int b_application() { + char buf[200]; + + if(currmode & MODE_BOARD) { + setbfile(buf, currboard, FN_APPLICATION); + vedit(buf, NA, NULL); + 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_t *bp; + + if(currmode & MODE_BOARD) { + char genbuf[BTLEN]; + + bp = getbcache(currbid); + 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_t), currbid); + 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; +} + +extern char *fn_mandex; + +static int good_post(int ent, fileheader_t *fhdr, char *direct) { + char genbuf[200]; + char genbuf2[200]; + int delta = 0; + + if((currmode & MODE_DIGEST) || !(currmode & MODE_BOARD)) + return DONOTHING; + + if(fhdr->filemode & FILE_DIGEST) { + fhdr->filemode = (fhdr->filemode & ~FILE_DIGEST); + if(!strcmp(currboard,"Note") || !strcmp(currboard,"PttBug") || + !strcmp(currboard,"Artdsn") || !strcmp(currboard, "PttLaw")) { + deumoney(searchuser(fhdr->owner),-1000); + if(!(currmode & MODE_SELECT)) + fhdr->money -= 1000; + else + delta = -1000; + } + } else { + fileheader_t 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)) unlink (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; + if(!strcmp(currboard, "Note") || !strcmp(currboard, "PttBug") || + !strcmp(currboard,"Artdsn") || !strcmp(currboard, "PttLaw")) { + deumoney(searchuser(fhdr->owner), 1000); + if(!(currmode & MODE_SELECT)) fhdr->money += 1000; + else delta = 1000; + } + } + substitute_record(direct, fhdr, sizeof(*fhdr), ent); + touchdircache(currbid); +/* rocker.011018: 串接模式用reference增進效率 */ + if ((currmode & MODE_SELECT) && (fhdr->money & FHR_REFERENCE)) + { + fileheader_t hdr; + char genbuf[100]; + int num; + + num = fhdr->money & ~FHR_REFERENCE; + setbdir(genbuf, currboard); + get_record(genbuf, &hdr, sizeof (hdr), num); + + /* 再這裡要check一下原來的dir裡面是不是有被人動過... */ + if (strcmp (hdr.filename, fhdr->filename)) + { + num = getindex(genbuf, fhdr->filename, sizeof(fileheader_t)); + get_record(genbuf, &hdr, sizeof (hdr), num); + } + fhdr->money = hdr.money + delta; + + substitute_record(genbuf, fhdr, sizeof(*fhdr), num); + } +#if 0 + if(currmode & MODE_SELECT) { + int now; + char genbuf[100]; + + setbdir(genbuf, currboard); + now=getindex(genbuf, fhdr->filename, sizeof(fileheader_t)); + substitute_record(genbuf, fhdr, sizeof(*fhdr), now); + } +#endif + 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/f) 展讀備忘錄/參與賭盤 (?)(/) 找尋標題", + "(V/R) 投票/查詢投票結果 (^W) 我在哪裡可看到看板的分類", + "(x) 轉錄文章到其他看板 (=)/([]<>-+) 找尋首篇文章/主題式閱\讀", +#ifdef INTERNET_EMAIL + "(F) 文章寄回Internet郵箱 (U) 將文章 uuencode 後寄回郵箱", +#endif + "(E) 重編文章 (^H) 列出所有的 New Post(s)", + "\01板主命令", + "(G) 舉辦賭盤/停止下注/開獎(W/w/v) 編輯備忘錄/水桶名單/可看見名單", + "(M/o) 舉行投票/編私投票名單 (m/c/g) 保留文章/選錄精華/文摘", + "(D) 刪除一段範圍的文章 (T/B) 重編文章標題/重編看版標題", + "(i) 編輯申請入會表格 (t/^D) 標記文章/砍除標記的文章", + "(O) 編輯Post注意事項 (H) 看板隱藏/現身", + NULL +}; + +static int b_help() { + show_help(board_help); + return FULLUPDATE; +} + +/* ----------------------------------------------------- */ +/* 板主設定隱形/ 解隱形 */ +/* ----------------------------------------------------- */ +char board_hidden_status; +#ifdef BMCHS +extern char *fn_board; +static int change_hidden(int ent, fileheader_t *fhdr, char *direct) +{ + boardheader_t bh; + int bid; + char ans[4]; + + if( !((currmode & MODE_BOARD) || HAS_PERM(PERM_SYSOP)) || + currboard[0] == 0 || + (bid = getbnum(currboard)) < 0 || + get_record(fn_board, &bh, sizeof(bh), bid) == -1 ) + return DONOTHING; + + if( ((bh.brdattr & BRD_HIDE) && (bh.brdattr & BRD_POSTMASK)) ){ + getdata(1, 0, "目前板在隱形狀態, 要解隱形嘛(Y/N)?[N]", ans, 2, LCECHO); + if( ans[0] != 'y' && ans[0] != 'Y' ) + return FULLUPDATE; + getdata(2, 0, "再確認一次, 真的要把板板公開嘛 @____@(Y/N)?[N]", + ans, 2, LCECHO); + if( ans[0] != 'y' && ans[0] != 'Y' ) + return FULLUPDATE; + if( bh.brdattr & BRD_HIDE ) bh.brdattr -= BRD_HIDE; + if( bh.brdattr & BRD_POSTMASK ) bh.brdattr -= BRD_POSTMASK; + log_usies("OpenBoard", bh.brdname); + outs("君心今傳眾人,無處不聞弦歌。\n"); + board_hidden_status = 0; + hbflreload(bid); + } + else{ + getdata(1, 0, "目前板在現形狀態, 要隱形嘛(Y/N)?[N]", ans, 2, LCECHO); + if( ans[0] != 'y' && ans[0] != 'Y' ) + return FULLUPDATE; + bh.brdattr |= BRD_HIDE; + bh.brdattr |= BRD_POSTMASK; + log_usies("CloseBoard", bh.brdname); + outs("君心今已掩抑,惟盼善自珍重。\n"); + board_hidden_status = 1; + } + setup_man(&bh); + substitute_record(fn_board, &bh, sizeof(bh), bid); + reset_board(bid); + log_usies("SetBoard", bh.brdname); + pressanykey(); + return FULLUPDATE; +} +#endif + +/* ----------------------------------------------------- */ +/* 看板功能表 */ +/* ----------------------------------------------------- */ +struct onekey_t read_comms[] = { + {KEY_TAB, board_digest}, + {'C', board_etc}, + {'b', b_notes}, + {'c', cite_post}, + {'r', read_post}, + {'z', b_man}, + {'D', del_range}, + {'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}, + {'O', b_post_note}, + {'w', b_water_edit}, + {'v', visable_list_edit}, + {'i', b_application}, + {'o', can_vote_edit}, + {'x', cross_post}, + {'h', b_help}, +#ifndef NO_GAMBLE + {'f', join_gamble}, + {'G', hold_gamble}, +#endif + {'g', good_post}, + {'y', reply_post}, + {'d', del_post}, + {'m', mark_post}, + {'L', solve_post}, + {Ctrl('P'), do_post}, + {Ctrl('W'), whereami}, + {'Q', view_postmoney}, +#ifdef OUTJOBSPOOL + {'u', tar_addqueue}, +#endif +#ifdef BMCHS + {'H', change_hidden}, +#endif + {'\0', NULL} +}; + +time_t board_visit_time; + +int Read() { + int mode0 = currutmp->mode; + int stat0 = currstat, tmpbid=currutmp->brc_id; + char buf[40]; +#ifdef LOG_BOARD + time_t usetime = time(0); +#endif + + setutmpmode(READING); + set_board(); + + if(board_visit_time < board_note_time) { + setbfile(buf, currboard, fn_notes); + more(buf, NA); + pressanykey(); + } + currutmp->brc_id = currbid; + setbdir(buf, currboard); + curredit &= ~EDIT_MAIL; + i_read(READING, buf, readtitle, readdoent, read_comms, + currbid); +#ifdef LOG_BOARD + log_board(currboard, time(0) - usetime); +#endif + brc_update(); + + currutmp->brc_id =tmpbid; + currutmp->mode = mode0; + currstat = stat0; + return 0; +} + +void ReadSelect() { + int mode0 = currutmp->mode; + int stat0 = currstat; + char genbuf[200]; + + currstat = XMODE; + if(do_select(0, 0, genbuf) == NEWDIRECT) + Read(); + currutmp->brc_id=0; + currutmp->mode = mode0; + currstat = stat0; +} + +#ifdef LOG_BOARD +static void log_board(char *mode, time_t usetime) { + time_t now; + char buf[ 256 ]; + + if(usetime > 30) { + now = time(0); + sprintf(buf, "USE %-20.20s Stay: %5ld (%s) %s", + mode, usetime ,cuser.userid ,ctime(&now)); + log_file(FN_USEBOARD,buf); + } +} +#endif + +int Select() { + char genbuf[200]; + + setutmpmode(SELECT); + do_select(0, NULL, genbuf); + return 0; +} |