summaryrefslogtreecommitdiffstats
path: root/mbbsd
diff options
context:
space:
mode:
Diffstat (limited to 'mbbsd')
-rw-r--r--mbbsd/brc.c19
-rw-r--r--mbbsd/friend.c2
-rw-r--r--mbbsd/io.c35
-rw-r--r--mbbsd/mail.c6
-rw-r--r--mbbsd/mbbsd.c20
-rw-r--r--mbbsd/menu.c12
-rw-r--r--mbbsd/screen.c6
-rw-r--r--mbbsd/stuff.c40
-rw-r--r--mbbsd/talk.c309
-rw-r--r--mbbsd/user.c58
-rw-r--r--mbbsd/var.c15
11 files changed, 451 insertions, 71 deletions
diff --git a/mbbsd/brc.c b/mbbsd/brc.c
index 7ad5e30c..7ba1f40e 100644
--- a/mbbsd/brc.c
+++ b/mbbsd/brc.c
@@ -9,7 +9,7 @@
#define BRC_BLOCKSIZE 1024
-#if MAX_BOARD > 32767 || BRC_MAXSIZE > 32767
+#if MAX_BOARD > 65535 || BRC_MAXSIZE > 65535
#error Max number of boards or BRC_MAXSIZE cannot fit in unsighed short, \
please rewrite brc.c
#endif
@@ -109,13 +109,10 @@ brc_putrecord(char *ptr, char *endp, brcbid_t bid, brcnbrd_t num, const time_t *
{
char * tmp;
if (num > 0 && list[0] > brc_expire_time &&
- ptr + sizeof(brcbid_t) + sizeof(brcnbrd_t) <= endp) {
+ ptr + sizeof(brcbid_t) + sizeof(brcnbrd_t) < endp) {
if (num > BRC_MAXNUM)
num = BRC_MAXNUM;
- while (num > 0 && list[num - 1] < brc_expire_time)
- num--; /* don't write the times before brc_expire_time */
-
if (num == 0) return ptr;
*(brcbid_t*)ptr = bid; /* write in bid */
@@ -164,7 +161,6 @@ brc_insert_record(brcbid_t bid, brcnbrd_t num, time_t* list)
ptr = brc_findrecord_in(brc_buf, brc_buf + brc_size, bid, &tnum);
- /* FIXME: this loop is copied from brc_putrecord() */
while (num > 0 && list[num - 1] < brc_expire_time)
num--; /* don't write the times before brc_expire_time */
@@ -172,8 +168,9 @@ brc_insert_record(brcbid_t bid, brcnbrd_t num, time_t* list)
brc_size -= tnum;
/* put on the beginning */
- if (num && (new_size =
- sizeof(brcbid_t) + sizeof(brcnbrd_t) + num * sizeof(time_t))){
+ if (num){
+ new_size = sizeof(brcbid_t) + sizeof(brcnbrd_t)
+ + num * sizeof(time_t);
brc_size += new_size;
if (brc_size > brc_alloc && !brc_enlarge_buf())
brc_size = BRC_MAXSIZE;
@@ -191,7 +188,7 @@ brc_insert_record(brcbid_t bid, brcnbrd_t num, time_t* list)
int sindex = ptr - brc_buf;
new_size = sizeof(brcbid_t) + sizeof(brcnbrd_t)
+ num * sizeof(time_t);
- brc_size += new_size - (tmpp - ptr);
+ brc_size += new_size - len;
if (brc_size > brc_alloc) {
if (brc_enlarge_buf()) {
ptr = brc_buf + sindex;
@@ -206,7 +203,7 @@ brc_insert_record(brcbid_t bid, brcnbrd_t num, time_t* list)
brc_putrecord(ptr, brc_buf + brc_alloc, bid, num, list);
} else { /* deleting record */
memmove(ptr, tmpp, end_size);
- brc_size -= (tmpp - ptr);
+ brc_size -= len;
}
}
@@ -336,6 +333,8 @@ brc_initial_board(const char *boardname)
brc_update(); /* write back first */
currbid = getbnum(boardname);
+ if( currbid == 0 )
+ currbid = getbnum(DEFAULT_BOARD);
currboard = bcache[currbid - 1].brdname;
currbrdattr = bcache[currbid - 1].brdattr;
diff --git a/mbbsd/friend.c b/mbbsd/friend.c
index eea78bdc..92977969 100644
--- a/mbbsd/friend.c
+++ b/mbbsd/friend.c
@@ -312,7 +312,7 @@ friend_water(char *message, int type)
if ((tuid = searchuser(userid)) && tuid != usernum &&
(uentp = (userinfo_t *) search_ulist(tuid)) &&
isvisible_uid(tuid))
- my_write(uentp->pid, message, uentp->userid, 1, NULL);
+ my_write(uentp->pid, message, uentp->userid, WATERBALL_PREEDIT, NULL);
}
fclose(fp);
}
diff --git a/mbbsd/io.c b/mbbsd/io.c
index 78adddda..aee1d04a 100644
--- a/mbbsd/io.c
+++ b/mbbsd/io.c
@@ -223,7 +223,6 @@ igetch()
else // here is switch for default keys
switch (ch) {
case IAC:
- case '\n': /* filters */
continue;
#ifdef DEBUG
case Ctrl('Q'):{
@@ -275,7 +274,7 @@ igetch()
return (ch);
if (currutmp->msgs[0].pid &&
- WATERMODE(WATER_OFO) && wmofo == -1) {
+ WATERMODE(WATER_OFO) && wmofo == NOTREPLYING) {
int y, x, my_newfd;
screenline_t *screen0 = calloc(t_lines, sizeof(screenline_t));
memcpy(screen0, big_picture, t_lines * sizeof(screenline_t));
@@ -315,8 +314,25 @@ igetch()
i_newfd = 0;
show_call_in(0, 0);
watermode = 0;
- my_write(currutmp->msgs[0].pid, "水球丟過去 : ",
- currutmp->msgs[0].userid, 0, NULL);
+#ifndef PLAY_ANGEL
+ my_write(currutmp->msgs[0].pid, "水球丟過去: ",
+ currutmp->msgs[0].userid, WATERBALL_GENERAL, NULL);
+#else
+ switch (currutmp->msgs[0].msgmode) {
+ case MSGMODE_WRITE:
+ my_write(currutmp->msgs[0].pid, "水球丟過去: ",
+ currutmp->msgs[0].userid, WATERBALL_GENERAL, NULL);
+ break;
+ case MSGMODE_FROMANGEL:
+ my_write(currutmp->msgs[0].pid, "再問他一次: ",
+ currutmp->msgs[0].userid, WATERBALL_ANGEL, NULL);
+ break;
+ case MSGMODE_TOANGEL:
+ my_write(currutmp->msgs[0].pid, "回答小主人: ",
+ currutmp->msgs[0].userid, WATERBALL_ANSWER, NULL);
+ break;
+ }
+#endif
i_newfd = my_newfd;
/* 還原螢幕 */
@@ -327,7 +343,8 @@ igetch()
continue;
}
}
- return ch;
+ return ch;
+
case Ctrl('T'):
if (WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW)) {
if (watermode > 0) {
@@ -373,7 +390,13 @@ igetch()
continue;
}
}
- return ch;
+ return ch;
+
+ case Ctrl('J'): /* Ptt 把 \n 拿掉 */
+#ifdef PLAY_ANGEL
+ CallAngel();
+#endif
+ continue;
default:
return ch;
diff --git a/mbbsd/mail.c b/mbbsd/mail.c
index 731f37cf..b8da8226 100644
--- a/mbbsd/mail.c
+++ b/mbbsd/mail.c
@@ -779,7 +779,7 @@ mailtitle()
prints("[←]離開[↑↓]選擇[→]閱\讀信件 [R]回信 [x]轉達 "
"[y]群組回信 [O]站外信:%s [h]求助\n\033[7m"
"編號 日 期 作 者 信 件 標 題 \033[32m",
- HAS_PERM(PERM_NOOUTMAIL) ? "\033[31m關\033[m" : "開");
+ REJECT_OUTTAMAIL ? "\033[31m關\033[m" : "開");
buf[0] = 0;
if (mailsumlimit) {
snprintf(buf, sizeof(buf),
@@ -971,7 +971,7 @@ mail_edit(int ent, fileheader_t * fhdr, char *direct)
static int
mail_nooutmail(int ent, fileheader_t * fhdr, char *direct)
{
- cuser.userlevel ^= PERM_NOOUTMAIL;
+ cuser.uflag2 ^= REJ_OUTTAMAIL;
passwd_update(usernum, &cuser);
return TITLE_REDRAW;
@@ -1233,7 +1233,7 @@ mail_waterball(int ent, fileheader_t * fhdr, char *direct)
}
if (invalidaddr(address))
return -2;
- if( strstr(address, ".bbs") && HAS_PERM(PERM_NOOUTMAIL) ){
+ if( strstr(address, ".bbs") && REJECT_OUTTAMAIL ){
move(b_lines - 4, 0);
outs("\n您必須要打開接受站外信, 水球整理系統才能寄入結果\n"
"請麻煩到【郵件選單】按大寫 O改成接受站外信 (在右上角)\n"
diff --git a/mbbsd/mbbsd.c b/mbbsd/mbbsd.c
index 47b9fd4a..529f0931 100644
--- a/mbbsd/mbbsd.c
+++ b/mbbsd/mbbsd.c
@@ -241,6 +241,12 @@ void
show_call_in(int save, int which)
{
char buf[200];
+#ifdef PLAY_ANGEL
+ if (currutmp->msgs[which].msgmode == MSGMODE_TOANGEL)
+ snprintf(buf, sizeof(buf), "\033[1;37;46m★%s\033[37;45m %s \033[m",
+ currutmp->msgs[which].userid, currutmp->msgs[which].last_call_in);
+ else
+#endif
snprintf(buf, sizeof(buf), "\033[1;33;46m★%s\033[37;45m %s \033[m",
currutmp->msgs[which].userid, currutmp->msgs[which].last_call_in);
move(b_lines, 0);
@@ -284,7 +290,12 @@ add_history(msgque_t * msg)
add_history_water(&water[0], msg);
if (WATERMODE(WATER_NEW) || WATERMODE(WATER_OFO)) {
for (i = 0; i < 5 && swater[i]; i++)
- if (swater[i]->pid == msg->pid)
+ if (swater[i]->pid == msg->pid
+#ifdef PLAY_ANGEL
+ && swater[i]->msg[0].msgmode == msg->msgmode
+ /* When throwing waterball to angel directly */
+#endif
+ )
break;
if (i == 5) {
waterinit = 1;
@@ -766,6 +777,11 @@ setup_utmp(int mode)
#endif
if (enter_uflag & CLOAK_FLAG)
uinfo.invisible = YEA;
+
+ if (REJECT_QUESTION)
+ uinfo.angel = 1;
+ uinfo.angel |= ANGEL_STATUS() << 1;
+
getnewutmpent(&uinfo);
SHM->UTMPneedsort = 1;
if (!(cuser.numlogins % 20) && cuser.userlevel & PERM_BM)
@@ -982,7 +998,7 @@ do_aloha(char *hello)
userinfo_t *uentp;
if ((uentp = (userinfo_t *) search_ulist_userid(userid)) &&
isvisible(uentp, currutmp)) {
- my_write(uentp->pid, genbuf, uentp->userid, 2, NULL);
+ my_write(uentp->pid, genbuf, uentp->userid, WATERBALL_ALOHA, NULL);
}
}
fclose(fp);
diff --git a/mbbsd/menu.c b/mbbsd/menu.c
index 7e3ec37a..38a5801f 100644
--- a/mbbsd/menu.c
+++ b/mbbsd/menu.c
@@ -272,6 +272,9 @@ domenu(int cmdmode, char *cmdtitle, int cmd, commands_t cmdtable[])
while (++i <= total)
if (cmdtable[i].desc[1] == cmd)
break;
+ if (cmd == 'H' && i > total){
+ /* TODO: Add menu help */
+ }
}
if (i > total || !HAS_PERM(cmdtable[i].level))
@@ -344,6 +347,9 @@ static commands_t talklist[] = {
{t_talk, PERM_PAGE, "TTalk 找人聊聊"},
{t_chat, PERM_CHAT, "CChat 找家茶坊喫茶去"},
{t_display, 0, "DDisplay 顯示上幾次熱訊"},
+#ifdef PLAY_ANGEL
+ {t_changeangel, PERM_BASIC, "UAChange Angel 更換小天使"},
+#endif
{NULL, 0, NULL}
};
@@ -373,7 +379,7 @@ static commands_t namelist[] = {
static commands_t userlist[] = {
{u_info, PERM_LOGINOK, "IInfo 設定個人資料與密碼"},
{calendar, PERM_LOGINOK, "CCalendar 個人行事曆"},
- {u_editcalendar, PERM_LOGINOK, "CDEditCalendar 編輯個人行事曆"},
+ {u_editcalendar, PERM_LOGINOK, "CDEditCalendar 編輯個人行事曆"},
{u_loginview, PERM_LOGINOK, "LLogin View 選擇進站畫面"},
{u_ansi, 0, "AANSI 切換 ANSI \033[36m彩\033[35m色\033[37m/"
"\033[30;47m黑\033[1;37m白\033[m模示"},
@@ -384,9 +390,9 @@ static commands_t userlist[] = {
{u_editplan, PERM_LOGINOK, "QQueryEdit 編輯名片檔"},
{u_editsig, PERM_LOGINOK, "SSignature 編輯簽名檔"},
#if HAVE_FREECLOAK
- {u_cloak, PERM_LOGINOK, "KKCloak 隱身術"},
+ {u_cloak, PERM_LOGINOK, "KKCloak 隱身術"},
#else
- {u_cloak, PERM_CLOAK, "KKCloak 隱身術"},
+ {u_cloak, PERM_CLOAK, "KKCloak 隱身術"},
#endif
{u_register, PERM_BASIC, "RRegister 填寫《註冊申請單》"},
{u_list, PERM_SYSOP, "UUsers 列出註冊名單"},
diff --git a/mbbsd/screen.c b/mbbsd/screen.c
index dcfafe2e..04dcec40 100644
--- a/mbbsd/screen.c
+++ b/mbbsd/screen.c
@@ -394,7 +394,7 @@ outc(unsigned char ch)
}
int
-edit_outs(char *text)
+edit_outs(const char *text)
{
register int column = 0;
register char ch;
@@ -405,7 +405,7 @@ edit_outs(char *text)
}
void
-outs(char *str)
+outs(const char *str)
{
while (*str) {
outc(*str++);
@@ -414,7 +414,7 @@ outs(char *str)
/* Jaky */
void
-out_lines(char *str, int line)
+out_lines(const char *str, int line)
{
while (*str && line) {
outc(*str);
diff --git a/mbbsd/stuff.c b/mbbsd/stuff.c
index f59d8119..9e7e1c5a 100644
--- a/mbbsd/stuff.c
+++ b/mbbsd/stuff.c
@@ -424,7 +424,33 @@ vmsg_lines(const int lines, const char msg[])
return ch;
}
-char getans(const char *fmt,...)
+#ifdef PLAY_ANGEL
+void
+pressanykey_or_callangel(){
+ int ch;
+
+ outmsg("\033[37;45;1m \033[33m(h)\033[37m 呼叫小天使 "
+ "● 請按 \033[33m(Space/Return)\033[37m 繼續 ●"
+ " \033[33m(^T)\033[37m 存暫存檔 \033[m");
+ do {
+ ch = igetch();
+
+ if (ch == Ctrl('T')) {
+ capture_screen();
+ break;
+ }else if (ch == 'h' || ch == 'H'){
+ CallAngel();
+ break;
+ }
+ } while ((ch != ' ') && (ch != KEY_LEFT) && (ch != '\r') && (ch != '\n'));
+ move(b_lines, 0);
+ clrtoeol();
+ refresh();
+}
+#endif
+
+char
+getans(const char *fmt,...)
{
char msg[256];
char ans[5];
@@ -597,10 +623,12 @@ log_user(const char *fmt, ...)
"%s: %s %s", cuser.userid, msg, Cdate(&now));
}
-int log_file(char *fn, int flag, const char *fmt,...)
+int
+log_file(char *fn, int flag, const char *fmt,...)
{
- int fd;
- char msg[256], *realmsg;
+ int fd;
+ char msg[256];
+ const char *realmsg;
if( !(flag & LOG_VF) ){
realmsg = fmt;
}
@@ -638,7 +666,11 @@ show_help(char *helptext[])
else
prints(" %s\n", str);
}
+#ifdef PLAY_ANGEL
+ pressanykey_or_callangel();
+#else
pressanykey();
+#endif
}
#endif // _BBS_UTIL_C_
diff --git a/mbbsd/talk.c b/mbbsd/talk.c
index 6864faf9..e5936862 100644
--- a/mbbsd/talk.c
+++ b/mbbsd/talk.c
@@ -457,6 +457,11 @@ water_scr(water_t * tw, int which, char type)
move(0, 0);
prints(" ");
move(0, 0);
+#ifdef PLAY_ANGEL
+ if (tw->msg[0].msgmode == MSGMODE_TOANGEL)
+ prints("\033[0m回答小主人:");
+ else
+#endif
prints("\033[0m反擊 %s:", tw->userid);
clrtoeol();
move(0, strlen(tw->userid) + 6);
@@ -480,7 +485,7 @@ my_write2(void)
if (swater[0] == NULL)
return;
- wmofo = 0;
+ wmofo = REPLYING;
currstat0 = currstat;
c0 = currutmp->chatid[0];
mode0 = currutmp->mode;
@@ -551,12 +556,26 @@ my_write2(void)
move(0, 0);
prints("\033[m");
clrtoeol();
+#ifndef PLAY_ANGEL
snprintf(genbuf, sizeof(genbuf), "攻擊 %s:", tw->userid);
+ i = WATERBALL_CONFIRM;
+#else
+ if (tw->msg[0].msgmode == MSGMODE_WRITE) {
+ snprintf(genbuf, sizeof(genbuf), "攻擊 %s:", tw->userid);
+ i = WATERBALL_CONFIRM;
+ } else if (tw->msg[0].msgmode == MSGMODE_TOANGEL) {
+ strcpy(genbuf, "回答小主人:");
+ i = WATERBALL_CONFIRM_ANSWER;
+ } else { /* tw->msg[0].msgmode == MSGMODE_FROMANGEL */
+ strcpy(genbuf, "再問他一次:");
+ i = WATERBALL_CONFIRM_ANGEL;
+ }
+#endif
if (!oldgetdata(0, 0, genbuf, msg,
- 80 - strlen(tw->userid) - 6, DOECHO))
+ 80 - strlen(tw->userid) - 6, DOECHO))
break;
- if (my_write(tw->pid, msg, tw->userid, 4, tw->uin))
+ if (my_write(tw->pid, msg, tw->userid, i, tw->uin))
strncpy(tw->msg[5].last_call_in, t_last_write,
sizeof(tw->msg[5].last_call_in));
break;
@@ -566,7 +585,7 @@ my_write2(void)
currstat = currstat0;
currutmp->chatid[0] = c0;
currutmp->mode = mode0;
- if (wmofo == RECVINREPLYING){
+ if (wmofo == RECVINREPLYING) {
wmofo = NOTREPLYING;
write_request(0);
}
@@ -574,10 +593,22 @@ my_write2(void)
}
/*
- * 被呼叫的時機: 1. 丟群組水球 flag = 1 (pre-edit) 2. 回水球 flag = 0 3.
- * 上站aloha flag = 2 (pre-edit) 4. 廣播 flag = 3 if SYSOP, otherwise
- * flag = 1 (pre-edit) 5. 丟水球 flag = 0 6. my_write2 flag = 4
- * (pre-edit) but confirm
+ * 被呼叫的時機:
+ * 1. 丟群組水球 flag = WATERBALL_PREEDIT, 1 (pre-edit)
+ * 2. 回水球 flag = WATERBALL_GENERAL, 0
+ * 3. 上站aloha flag = WATERBALL_ALOHA, 2 (pre-edit)
+ * 4. 廣播 flag = WATERBALL_SYSOP, 3 if SYSOP
+ * flag = WATERBALL_PREEDIT, 1 otherwise
+ * 5. 丟水球 flag = WATERBALL_GENGRAL, 0
+ * 6. my_write2 flag = WATERBALL_CONFIRM, 4 (pre-edit but confirm)
+ * 7. (when defined PLAY_ANGEL)
+ * 呼叫小天使 flag = WATERBALL_ANGEL, 5 (id = "小天使")
+ * 8. (when defined PLAY_ANGEL)
+ * 回答小主人 flag = WATERBALL_ANSWER, 6 (隱藏 id)
+ * 9. (when defined PLAY_ANGEL)
+ * 呼叫小天使 flag = WATERBALL_CONFIRM_ANGEL, 7 (pre-edit)
+ * 10. (when defined PLAY_ANGEL)
+ * 回答小主人 flag = WATERBALL_CONFIRM_ANSWER, 8 (pre-edit)
*/
int
my_write(pid_t pid, char *prompt, char *id, int flag, userinfo_t * puin)
@@ -591,7 +622,7 @@ my_write(pid_t pid, char *prompt, char *id, int flag, userinfo_t * puin)
uin = (puin != NULL) ? puin : (userinfo_t *) search_ulist_pid(pid);
strlcpy(destid, id, sizeof(destid));
- if (!uin && !(flag == 0 && water_which->count > 0)) {
+ if (!uin && !(flag == WATERBALL_GENERAL && water_which->count > 0)) {
vmsg("糟糕! 對方已落跑了(不在站上)! ");
watermode = -1;
return 0;
@@ -602,7 +633,11 @@ my_write(pid_t pid, char *prompt, char *id, int flag, userinfo_t * puin)
ptime = localtime(&now);
- if (flag == 0) {
+ if (flag == WATERBALL_GENERAL
+#ifdef PLAY_ANGEL
+ || flag == WATERBALL_ANGEL || flag == WATERBALL_ANSWER
+#endif
+ ) {
/* 一般水球 */
watermode = 0;
if (!(len = getdata(0, 0, prompt, msg, 56, DOECHO))) {
@@ -626,8 +661,13 @@ my_write(pid_t pid, char *prompt, char *id, int flag, userinfo_t * puin)
}
strip_ansi(msg, msg, STRIP_ALL);
- if (uin && *uin->userid && (flag == 0 || flag == 4)) {
- snprintf(buf, sizeof(buf), "丟給 %s : %s [Y/n]?", uin->userid, msg);
+ if (uin && *uin->userid &&
+ (flag == WATERBALL_GENERAL || flag == WATERBALL_CONFIRM
+#ifdef PLAY_ANGEL
+ || flag == WATERBALL_ANGEL || flag == WATERBALL_ANSWER
+#endif
+ )) {
+ snprintf(buf, sizeof(buf), "丟給 %s : %s [Y/n]?", destid, msg);
getdata(0, 0, buf, genbuf, 3, LCECHO);
if (genbuf[0] == 'n') {
currutmp->chatid[0] = c0;
@@ -638,7 +678,11 @@ my_write(pid_t pid, char *prompt, char *id, int flag, userinfo_t * puin)
}
}
watermode = -1;
- if (!uin || !*uin->userid || strcasecmp(destid, uin->userid)) {
+ if (!uin || !*uin->userid || (strcasecmp(destid, uin->userid)
+#ifdef PLAY_ANGEL
+ && flag != WATERBALL_ANGEL && flag != WATERBALL_CONFIRM_ANGEL
+#endif
+ )) {
vmsg("糟糕! 對方已落跑了(不在站上)! ");
currutmp->chatid[0] = c0;
currutmp->mode = mode0;
@@ -646,7 +690,7 @@ my_write(pid_t pid, char *prompt, char *id, int flag, userinfo_t * puin)
return 0;
}
fri_stat = friend_stat(currutmp, uin);
- if (flag != 2) { /* aloha 的水球不用存下來 */
+ if (flag != WATERBALL_ALOHA) { /* aloha 的水球不用存下來 */
/* 存到自己的水球檔 */
if (!fp_writelog) {
sethomefile(genbuf, cuser.userid, fn_writelog);
@@ -654,24 +698,37 @@ my_write(pid_t pid, char *prompt, char *id, int flag, userinfo_t * puin)
}
if (fp_writelog) {
fprintf(fp_writelog, "To %s: %s [%s]\n",
- uin->userid, msg, Cdatelite(&now));
- snprintf(t_last_write, 66, "To %s: %s", uin->userid, msg);
+ destid, msg, Cdatelite(&now));
+ snprintf(t_last_write, 66, "To %s: %s", destid, msg);
}
}
- if (flag == 3 && uin->msgcount) {
+ if (flag == WATERBALL_SYSOP && uin->msgcount) {
/* 不懂 */
uin->destuip = currutmp - &SHM->uinfo[0];
uin->sig = 2;
if (uin->pid > 0)
kill(uin->pid, SIGUSR1);
- } else if (flag != 2 &&
+ } else if ((flag != WATERBALL_ALOHA &&
+#ifdef PLAY_ANGEL
+ flag != WATERBALL_ANGEL &&
+ flag != WATERBALL_ANSWER &&
+ flag != WATERBALL_CONFIRM_ANGEL &&
+ flag != WATERBALL_CONFIRM_ANSWER &&
+ /* Angel accept or not is checked outside.
+ * Avoiding new users don't know what pager is. */
+#endif
!HAS_PERM(PERM_SYSOP) &&
(uin->pager == 3 ||
uin->pager == 2 ||
(uin->pager == 4 &&
!(fri_stat & HFM))))
+#ifdef PLAY_ANGEL
+ || ((flag == WATERBALL_ANGEL || flag == WATERBALL_CONFIRM_ANGEL)
+ && (uin->angel & 1))
+#endif
+ ) {
outmsg("\033[1;33;41m糟糕! 對方防水了! \033[37m~>_<~\033[m");
- else {
+ } else {
int write_pos = uin->msgcount; /* try to avoid race */
if ( write_pos < (MAX_MSGS - 1) ) { /* race here */
unsigned char pager0 = uin->pager;
@@ -679,12 +736,34 @@ my_write(pid_t pid, char *prompt, char *id, int flag, userinfo_t * puin)
uin->msgcount = write_pos + 1;
uin->pager = 2;
uin->msgs[write_pos].pid = currpid;
- strlcpy(uin->msgs[write_pos].userid, cuser.userid,
+#ifdef PLAY_ANGEL
+ if (flag == WATERBALL_ANSWER || flag == WATERBALL_CONFIRM_ANSWER)
+ strlcpy(uin->msgs[write_pos].userid, "小天使",
sizeof(uin->msgs[write_pos].userid));
+ else
+#endif
+ strlcpy(uin->msgs[write_pos].userid, cuser.userid,
+ sizeof(uin->msgs[write_pos].userid));
strlcpy(uin->msgs[write_pos].last_call_in, msg,
sizeof(uin->msgs[write_pos].last_call_in));
+#ifndef PLAY_ANGEL
+ uin->msgs[write_pos].msgmode = MSGMODE_WRITE;
+#else
+ switch (flag) {
+ case WATERBALL_ANGEL:
+ case WATERBALL_CONFIRM_ANGEL:
+ uin->msgs[write_pos].msgmode = MSGMODE_TOANGEL;
+ break;
+ case WATERBALL_ANSWER:
+ case WATERBALL_CONFIRM_ANSWER:
+ uin->msgs[write_pos].msgmode = MSGMODE_FROMANGEL;
+ break;
+ default:
+ uin->msgs[write_pos].msgmode = MSGMODE_WRITE;
+ }
+#endif
uin->pager = pager0;
- } else if (flag != 2)
+ } else if (flag != WATERBALL_ALOHA)
outmsg("\033[1;33;41m糟糕! 對方不行了! (收到太多水球) \033[37m@_@\033[m");
if (uin->msgcount >= 1 &&
@@ -693,12 +772,21 @@ my_write(pid_t pid, char *prompt, char *id, int flag, userinfo_t * puin)
#else
(uin->pid <= 0 || kill(uin->pid, SIGUSR2) == -1)
#endif
- && flag != 2)
+ && flag != WATERBALL_ALOHA)
outmsg("\033[1;33;41m糟糕! 沒打中! \033[37m~>_<~\033[m");
- else if (uin->msgcount == 1 && flag != 2)
+ else if (uin->msgcount == 1 && flag != WATERBALL_ALOHA)
outmsg("\033[1;33;44m水球砸過去了! \033[37m*^o^*\033[m");
- else if (uin->msgcount > 1 && uin->msgcount < MAX_MSGS && flag != 2)
+ else if (uin->msgcount > 1 && uin->msgcount < MAX_MSGS &&
+ flag != WATERBALL_ALOHA)
outmsg("\033[1;33;44m再補上一粒! \033[37m*^o^*\033[m");
+
+#if defined(NOKILLWATERBALL) && defined(PLAY_ANGEL)
+ /* Questioning and answering should better deliver immediately. */
+ if ((flag == WATERBALL_ANGEL || flag == WATERBALL_ANSWER ||
+ flag == WATERBALL_CONFIRM_ANGEL ||
+ flag == WATERBALL_CONFIRM_ANSWER) && uin->pid)
+ kill(uin->pid, SIGUSR2);
+#endif
}
clrtoeol();
@@ -770,8 +858,9 @@ t_display_new(void)
}
}
for (i = 0; i < water_which->count; i++) {
- int a = (water_which->top - i - 1 + MAX_REVIEW) % MAX_REVIEW, len = 75 - strlen(water_which->msg[a].last_call_in)
- - strlen(water_which->msg[a].userid);
+ int a = (water_which->top - i - 1 + MAX_REVIEW) % MAX_REVIEW;
+ int len = 75 - strlen(water_which->msg[a].last_call_in)
+ - strlen(water_which->msg[a].userid);
if (len < 0)
len = 0;
@@ -1429,7 +1518,11 @@ t_showhelp()
outs("(Y) 顯示正在看什麼板\n");
#endif
}
+#ifdef PLAY_ANGEL
+ pressanykey_or_callangel();
+#else
pressanykey();
+#endif
}
/*
@@ -1849,10 +1942,18 @@ draw_pickup(int drawall, pickup_t * pickup, int pickup_way,
int
call_in(userinfo_t * uentp, int fri_stat)
{
+#ifdef PLAY_ANGLE
+ static int CallInAngelWarning = 1;
+ if( CallInAngelWarning && ! strcasecmp(uentp->userid, cuser.myangel) ){
+ outmsg("直接丟水球給小天使是會被知道 ID 的喔!");
+ CallInAngelWarning = 0;
+ }
+#endif
+
if (iswritable_stat(uentp, fri_stat)) {
char genbuf[60];
snprintf(genbuf, sizeof(genbuf), "Call-In %s :", uentp->userid);
- my_write(uentp->pid, genbuf, uentp->userid, 0, NULL);
+ my_write(uentp->pid, genbuf, uentp->userid, WATERBALL_GENERAL, NULL);
return 1;
}
return 0;
@@ -2171,7 +2272,7 @@ userlist(void)
uentp = SHM->sorted[SHM->currsorted][0][i];
if (uentp->pid && kill(uentp->pid, 0) != -1)
my_write(uentp->pid, genbuf,
- uentp->userid, 1, NULL);
+ uentp->userid, WATERBALL_PREEDIT, NULL);
if (i % 100 == 0)
sleep(1);
}
@@ -2191,8 +2292,8 @@ userlist(void)
uentp->pager != 3 &&
(uentp->pager != 4 || frstate & HFM) &&
!(frstate & IRH)) {
- my_write(uentp->pid, genbuf,
- uentp->userid, 1, NULL);
+ my_write(uentp->pid, genbuf, uentp->userid,
+ WATERBALL_PREEDIT, NULL);
}
}
}
@@ -2626,6 +2727,7 @@ talkreply(void)
strlcpy(currutmp->msgs[0].userid, uip->userid, sizeof(currutmp->msgs[0].userid));
strlcpy(currutmp->msgs[0].last_call_in, "呼叫、呼叫,聽到請回答 (Ctrl-R)",
sizeof(currutmp->msgs[0].last_call_in));
+ currutmp->msgs[0].msgmode = MSGMODE_TALK;
prints("對方來自 [%s],共上站 %d 次,文章 %d 篇\n",
uip->from, xuser.numlogins, xuser.numposts);
showplans(uip->userid);
@@ -2705,3 +2807,150 @@ talkreply(void)
* ""); } if (++linecnt < 3){ strcat(uentry, "│"); outs(uentry); } else{
* outs(uentry); linecnt = 0; clrtoeol(); move(++lineno, 0); } return 0; }
*/
+
+#ifdef PLAY_ANGEL
+/* 小天使小主人處理函式 */
+int
+t_changeangel(){
+ char buf[4];
+ if( cuser.myangel[0] == 0 ) return 0;
+ getdata(b_lines - 1, 0,
+ "更換小天使後就無法換回了喔! 是否要更換小天使? [y/N]",
+ buf, 3, LCECHO);
+ if( buf[0] == 'y' || buf[0] == 'Y' ){
+ cuser.myangel[0] = 0;
+ outs("小天使更新完成,下次呼叫時會選出新的小天使");
+ }
+ return XEASY;
+}
+
+static int
+FindAngel(void){
+ int nAngel;
+ int i, j;
+ int choose;
+ int trial = 0;
+ int mask;
+
+ if (cuser.sex < 6) /* 正常性別 */
+ mask = 1 | (2 << (cuser.sex & 1));
+ else
+ mask = 7;
+
+ do{
+ nAngel = 0;
+ j = SHM->currsorted;
+ for (i = 0; i < SHM->UTMPnumber; ++i)
+ if ((SHM->sorted[j][0][i]->userlevel & PERM_ANGEL)
+ && (SHM->sorted[j][0][j]->angel & mask) == 0)
+ ++nAngel;
+
+ if (nAngel == 0)
+ return 0;
+
+ choose = rand() % nAngel + 1;
+ j = SHM->currsorted;
+ for (i = 0; i < SHM->UTMPnumber && choose; ++i)
+ if ((SHM->sorted[j][0][i]->userlevel & PERM_ANGEL)
+ && (SHM->sorted[j][0][j]->angel & mask) == 0)
+ --choose;
+
+ if (choose == 0 && SHM->sorted[j][0][i - 1]->uid != currutmp->uid){
+ strlcpy(cuser.myangel, SHM->sorted[j][0][i - 1]->userid, IDLEN + 1);
+ return 1;
+ }
+ }while(++trial < 5);
+ return 0;
+}
+
+static void
+NoAngelFound(const char* msg){
+ move(b_lines, 0);
+ outs(msg);
+ if (currutmp->mode != EDITING)
+ outs(",請先在新手板上尋找答案或按 Ctrl-P 發問");
+ clrtoeol();
+ refresh();
+ sleep(1);
+ if (currutmp->mode != EDITING){
+ char old_board[IDLEN + 1] = "";
+ if (currboard)
+ strlcpy(old_board, currboard, IDLEN + 1);
+
+ brc_initial_board("PttNewHand");
+ Read();
+
+ if (old_board[0])
+ brc_initial_board(old_board);
+ }
+ return;
+}
+
+static void
+TalkToAngel(){
+ userinfo_t* uent;
+
+ if (cuser.myangel[0] == 0 && ! FindAngel()){
+ NoAngelFound("現在沒有小天使在線上");
+ return;
+ }
+
+ uent = search_ulist_userid(cuser.myangel);
+ if (uent == 0 || (uent->angel & 1)){
+ NoAngelFound("您的小天使現在不在線上");
+ return;
+ }
+
+ /* 這段話或許可以在小天使回答問題時 show 出來
+ move(b_lines - 1, 0);
+ outs("現在你的id受到保密,回答你問題的小天使並不知道你是誰 \n"
+ "你可以選擇不向對方透露自己身份來保護自己 ");
+ */
+
+ my_write(uent->pid, "問小天使: ", "小天使", WATERBALL_ANGEL, uent);
+ return;
+}
+
+void
+CallAngel(){
+ static int entered = 0;
+ screenline_t *screen0;
+ int x, y;
+
+ if (entered)
+ return;
+ entered = 1;
+
+ screen0 = calloc(t_lines, sizeof(screenline_t));
+ getyx(&y, &x);
+ memcpy(screen0, big_picture, t_lines * sizeof(screenline_t));
+
+ TalkToAngel();
+
+ memcpy(big_picture, screen0, t_lines * sizeof(screenline_t));
+ move(y, x);
+ free(screen0);
+ redoscr();
+
+ entered = 0;
+}
+
+void
+SwitchBeingAngel(){
+ cuser.uflag2 ^= REJ_QUESTION;
+ currutmp->angel ^= 1;
+}
+
+void
+SwitchAngelSex(int newmode){
+ ANGEL_SET(newmode);
+ currutmp->angel = (currutmp->angel & ~0x6) | ((newmode & 3) << 1);
+}
+
+int
+t_switchangel(){
+ SwitchBeingAngel();
+ outs(REJECT_QUESTION ? "休息一會兒" : "開放小主人問問題");
+ return XEASY;
+}
+#endif
diff --git a/mbbsd/user.c b/mbbsd/user.c
index 9227c381..f73a26be 100644
--- a/mbbsd/user.c
+++ b/mbbsd/user.c
@@ -89,6 +89,11 @@ user_display(userec_t * u, int real)
get_num_records(genbuf, sizeof(fileheader_t)),
u->exmailbox, u->mobile,
u->month, u->day, u->year % 100, u->mychicken.name);
+#ifdef PLAY_ANGEL
+ if (real)
+ prints(" 小 天 使: %s\n",
+ u->myangel[0] ? u->myangel : "無");
+#endif
prints(" 註冊日期: %s", ctime(&u->firstlogin));
prints(" 前次光臨: %s", ctime(&u->lastlogin));
prints(" 前次點歌: %s", ctime(&u->lastsong));
@@ -217,7 +222,11 @@ violate_law(userec_t * u, int unum)
static void Customize(void)
{
char done = 0, mindbuf[5];
+ int key;
char *wm[3] = {"一般", "進階", "未來"};
+#ifdef PLAY_ANGEL
+ char *am[4] = {"男女皆可", "限女生", "限男生", "暫不接受新的小主人"};
+#endif
showtitle("個人化設定", "個人化設定");
memcpy(mindbuf, &currutmp->mind, 4);
@@ -228,14 +237,23 @@ static void Customize(void)
move(4, 0);
prints("%-30s%10s\n", "A. 水球模式",
wm[(cuser.uflag2 & WATER_MASK)]);
- prints("%-30s%10s\n", "B. 接受站外信",
- ((cuser.userlevel & PERM_NOOUTMAIL) ? "否" : "是"));
+ prints("%-30s%10s\n", "B. 接受站外信", REJECT_OUTTAMAIL ? "否" : "是");
prints("%-30s%10s\n", "C. 新板自動進我的最愛",
((cuser.uflag2 & FAVNEW_FLAG) ? "是" : "否"));
prints("%-30s%10s\n", "D. 目前的心情", mindbuf);
prints("%-30s%10s\n", "E. 高亮度顯示我的最愛",
((cuser.uflag2 & FAVNOHILIGHT) ? "否" : "是"));
- switch(getkey("請按 [A-E] 切換設定,按 [Return] 結束:")){
+#ifdef PLAY_ANGEL
+ if( HAS_PERM(PERM_ANGEL) ){
+ prints("%-30s%10s\n", "F. 開放小主人詢問",
+ (REJECT_QUESTION ? "否" : "是"));
+ prints("%-30s%10s\n", "G. 接受的小主人性別", am[ANGEL_STATUS()]);
+ key = getkey("請按 [A-G] 切換設定,按 [Return] 結束:");
+ }else
+#endif
+ key = getkey("請按 [A-e] 切換設定,按 [Return] 結束:");
+
+ switch (key) {
case 'a':{
int currentset = cuser.uflag2 & WATER_MASK;
currentset = (currentset + 1) % 3;
@@ -245,7 +263,7 @@ static void Customize(void)
}
break;
case 'b':
- cuser.userlevel ^= PERM_NOOUTMAIL;
+ cuser.uflag2 ^= REJ_OUTTAMAIL;
break;
case 'c':
cuser.uflag2 ^= FAVNEW_FLAG;
@@ -266,6 +284,23 @@ static void Customize(void)
case 'e':
cuser.uflag2 ^= FAVNOHILIGHT;
break;
+
+#ifdef PLAY_ANGEL
+ case 'f':
+ if( HAS_PERM(PERM_ANGEL) ){
+ SwitchBeingAngel();
+ break;
+ }
+ done = 1;
+ break;
+
+ case 'g':
+ if( HAS_PERM(PERM_ANGEL) ){
+ SwitchAngelSex(ANGEL_STATUS() + 1);
+ break;
+ }
+#endif
+
default:
done = 1;
}
@@ -374,6 +409,21 @@ uinfo_query(userec_t * u, int real, int unum)
i++;
break;
}
+
+#ifdef PLAY_ANGEL
+ if (real)
+ while (1) {
+ getdata_str(i, 0, "小天使:", buf, IDLEN + 1, DOECHO,
+ x.myangel);
+ if(buf[0] == 0 || (getuser(buf) &&
+ (xuser.userlevel & PERM_ANGEL))){
+ strlcpy(x.myangel, buf, IDLEN + 1);
+ ++i;
+ break;
+ }
+ }
+#endif
+
if (real) {
int l;
if (HAS_PERM(PERM_BBSADM)) {
diff --git a/mbbsd/var.c b/mbbsd/var.c
index 3ff019f0..c499663b 100644
--- a/mbbsd/var.c
+++ b/mbbsd/var.c
@@ -21,7 +21,11 @@ char *str_permid[] = {
"BBSADM", /* PERM_POSTMARK */
"不列入排行榜", /* PERM_NOTOP */
"違法通緝中", /* PERM_VIOLATELAW */
- "不接受站外的信", /* PERM_ */
+#ifdef PLAY_ANGEL
+ "可擔任小天使", /* PERM_ANGEL */
+#else
+ "未使用",
+#endif
"不允許\認證碼註冊", /* PERM_NOREGCODE */
"視覺站長", /* PERM_VIEWSYSOP */
"觀察使用者行蹤", /* PERM_LOGUSER */
@@ -332,13 +336,14 @@ int automargins = 1;
time_t now;
int KEY_ESC_arg;
int watermode = -1;
-int wmofo = -1;
+int wmofo = NOTREPLYING;
/*
* WATERMODE(WATER_ORIG) | WATERMODE(WATER_NEW):
* ????????????????????
- * Ptt 水球回顧 e = -1
- * 沒在回水球 = 0 在回上一顆水球 (Ctrl-R) > 0 在回前 n 顆水球 (Ctrl-R
- * Ctrl-R)
+ * Ptt 水球回顧 (FIXME: guessed by scw)
+ * watermode = -1 沒在回水球
+ * = 0 在回上一顆水球 (Ctrl-R)
+ * > 0 在回前 n 顆水球 (Ctrl-R Ctrl-R)
*
* WATERMODE(WATER_OFO) by in2
* wmofo = NOTREPLYING 沒在回水球