summaryrefslogtreecommitdiffstats
path: root/mbbsd/talk.c
diff options
context:
space:
mode:
Diffstat (limited to 'mbbsd/talk.c')
-rw-r--r--mbbsd/talk.c2663
1 files changed, 2663 insertions, 0 deletions
diff --git a/mbbsd/talk.c b/mbbsd/talk.c
new file mode 100644
index 00000000..3012b2d2
--- /dev/null
+++ b/mbbsd/talk.c
@@ -0,0 +1,2663 @@
+/* $Id: talk.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+
+#define QCAST int (*)(const void *, const void *)
+
+extern userinfo_t *currutmp;
+extern char *ModeTypeTable[MAX_MODES];
+extern char *fn_overrides;
+extern int usernum;
+extern char *msg_sure_ny;
+extern char *msg_cancel;
+extern unsigned int currstat;
+extern char *fn_writelog;
+extern FILE *fp_writelog;
+extern pid_t currpid;
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern int t_lines, t_columns; /* Screen size / width */
+extern char *fn_talklog;
+extern char currauthor[IDLEN + 2];
+extern char *msg_usr_left;
+extern char *msg_uid;
+extern char *BBSName;
+extern int p_lines; /* a Page of Screen line numbers: tlines-4 */
+extern char fromhost[];
+extern char *err_uid;
+extern int talkrequest;
+extern char *msg_shortulist;
+extern char *msg_nobody;
+extern boardheader_t *bcache;
+extern int curr_idle_timeout;
+extern userec_t cuser;
+extern userec_t xuser;
+
+
+static char *IdleTypeTable[] = {
+ "偶在花呆啦", "情人來電", "覓食中", "拜見周公", "假死狀態", "我在思考"
+};
+static char *sig_des[] = {
+ "鬥雞", "聊天", "", "下棋", "象棋", "暗棋"
+};
+
+#define MAX_SHOW_MODE 3
+#define M_INT 15 /* monitor mode update interval */
+#define P_INT 20 /* interval to check for page req. in
+ * talk/chat */
+#define BOARDFRI 1
+
+typedef struct talkwin_t {
+ int curcol, curln;
+ int sline, eline;
+} talkwin_t;
+
+typedef struct pickup_t {
+ userinfo_t *ui;
+ time_t idle;
+ int friend;
+} pickup_t;
+
+extern int bind( /* int,struct sockaddr *, int */ );
+extern char *getuserid();
+extern struct utmpfile_t *utmpshm;
+extern int watermode;
+extern water_t water[6], *swater[5], *water_which;
+extern char *friend_file[8], water_usies;
+
+/* 記錄 friend 的 user number */
+//#define PICKUP_WAYS 7 //關掉女士優先
+#define PICKUP_WAYS 6
+
+static int pickup_way = 0;
+static char *fcolor[11] = {
+ "", "\033[36m", "\033[32m", "\033[1;32m",
+ "\033[33m", "\033[1;33m", "\033[1;37m", "\033[1;37m",
+ "\033[31m", "\033[1;35m", "\033[1;36m"
+};
+static char save_page_requestor[40];
+static char page_requestor[40];
+static char description[30];
+static FILE *flog;
+
+
+char *modestring(userinfo_t * uentp, int simple) {
+ static char modestr[40];
+ static char *notonline = "不在站上";
+ register int mode = uentp->mode;
+ register char *word;
+ int fri_stat;
+
+/* for debugging */
+ if (mode >= MAX_MODES)
+ {
+ syslog(LOG_WARNING, "what!? mode = %d", mode);
+ word = ModeTypeTable[mode % MAX_MODES];
+ }
+ else
+ word = ModeTypeTable[mode];
+ fri_stat = friend_stat(currutmp, uentp);
+ if (!(HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_SEECLOAK)) &&
+ (
+ (uentp->invisible || (fri_stat & HRM)) &&
+ !((fri_stat & HFM) && (fri_stat & HRM))
+ )
+ )
+ return notonline;
+ else if (mode == EDITING)
+ {
+ sprintf(modestr, "E:%s",
+ ModeTypeTable[uentp->destuid < EDITING ? uentp->destuid :
+ EDITING]);
+ word = modestr;
+ }
+ else if (!mode && *uentp->chatid == 1)
+ {
+ if (!simple)
+ sprintf(modestr, "回應 %s", getuserid(uentp->destuid));
+ else
+ sprintf(modestr, "回應呼叫");
+ }
+ else if (!mode && *uentp->chatid == 2)
+ if (uentp->msgcount < 10)
+ {
+ char *cnum[10] =
+ {"", "一", "兩", "三", "四", "五", "六", "七",
+ "八", "九"};
+ sprintf(modestr, "中%s顆水球", cnum[uentp->msgcount]);
+ }
+ else
+ sprintf(modestr, "不行了 @_@");
+ else if (!mode && *uentp->chatid == 3)
+ sprintf(modestr, "水球準備中");
+ else if (!mode)
+ return (uentp->destuid == 6) ? uentp->chatid :
+ IdleTypeTable[(0 <= uentp->destuid && uentp->destuid < 6) ?
+ uentp->destuid : 0];
+ else if (simple)
+ return word;
+ else if (uentp->in_chat && mode == CHATING)
+ sprintf(modestr, "%s (%s)", word, uentp->chatid);
+ else if (mode == TALK)
+ {
+ if (!isvisible_uid(uentp->destuid))/* Leeym 對方(紫色)隱形 */
+ sprintf(modestr, "%s", "交談 空氣");/* Leeym 大家自己發揮吧! */
+ else
+ sprintf(modestr, "%s %s", word, getuserid(uentp->destuid));
+ }
+ else if (mode == M_FIVE)
+ {
+ if (!isvisible_uid(uentp->destuid))
+ sprintf(modestr, "%s", "五子棋 空氣");
+ else
+ sprintf(modestr, "%s %s", word, getuserid(uentp->destuid));
+ }
+ else if (mode == CHC)
+ {
+ if (isvisible_uid(uentp->destuid))
+ sprintf(modestr, "%s", "下象棋");
+ else
+ sprintf(modestr, "下象棋 %s", getuserid(uentp->destuid));
+ }
+ else if (mode != PAGE && mode != TQUERY)
+ return word;
+ else
+ sprintf(modestr, "%s %s", word, getuserid(uentp->destuid));
+
+ return (modestr);
+}
+
+int set_friend_bit(userinfo_t * me, userinfo_t * ui) {
+ int unum, *myfriends, hit=0, n;
+
+/* 判斷對方是否為我的朋友 ? */
+ unum = ui->uid;
+ myfriends = me->friend;
+ while ((n = *myfriends++))
+ {
+ if (unum == n)
+ {
+ hit = IFH;
+ break;
+ }
+ }
+
+/* 判斷我是否為對方的朋友 ? */
+ myfriends = ui->friend;
+ while ((unum = *myfriends++))
+ {
+ if (unum == me->uid)
+ {
+ hit |= HFM;
+ break;
+ }
+ }
+
+/* 判斷對方是否為我的仇人 ? */
+
+ unum = ui->uid;
+ myfriends = me->reject;
+ while ((n = *myfriends++))
+ {
+ if (unum == n)
+ {
+ hit |= IRH;
+ break;
+ }
+ }
+
+/* 判斷我是否為對方的仇人 ? */
+ myfriends = ui->reject;
+ while ((unum = *myfriends++))
+ {
+ if (unum == me->uid)
+ {
+ hit |= HRM;
+ break;
+ }
+ }
+ return hit;
+}
+int reverse_friend_stat(int stat)
+{
+ int stat1=0;
+ if(stat & IFH)
+ stat1 |=HFM;
+ if(stat & IRH)
+ stat1 |=HRM;
+ if(stat & HFM)
+ stat1 |=IFH;
+ if(stat & HRM)
+ stat1 |=IRH;
+ if(stat & IBH)
+ stat1 |=IBH;
+ return stat1;
+}
+
+int login_friend_online(){
+ userinfo_t *uentp;
+ int i, stat, stat1;
+ int offset=(int) (currutmp - &utmpshm->uinfo[0]);
+ for (i=0;i<utmpshm->number && currutmp->friendtotal<MAX_FRIEND; i++)
+ {
+ uentp = (utmpshm->sorted[utmpshm->currsorted][0][i]);
+ if(uentp && uentp->uid && (stat=set_friend_bit(currutmp,uentp)))
+ {
+ stat1=reverse_friend_stat(stat);
+ stat <<= 24;
+ stat |= (int) (uentp - &utmpshm->uinfo[0]);
+ currutmp->friend_online[currutmp->friendtotal++]=stat;
+ if(uentp!=currutmp && uentp->friendtotal<MAX_FRIEND)
+ {
+ stat1 <<= 24;
+ stat1 |= offset;
+ uentp->friend_online[uentp->friendtotal++]=stat1;
+ }
+ }
+ }
+ return 0;
+}
+
+int logout_friend_online(){
+ int i, j, k;
+ int offset=(int) (currutmp - &utmpshm->uinfo[0]);
+ userinfo_t *ui;
+ while(currutmp->friendtotal)
+ {
+ i = currutmp->friendtotal-1;
+ j = (currutmp->friend_online[i] & 0xFFFFFF);
+ currutmp->friend_online[i]=0;
+ ui = &utmpshm->uinfo[j];
+ if(ui->pid && ui!=currutmp)
+ {
+ for(k=0; k<ui->friendtotal &&
+ (int)(ui->friend_online[k] & 0xFFFFFF) !=offset; k++);
+ if(k<ui->friendtotal)
+ {
+ ui->friendtotal--;
+ ui->friend_online[k]=ui->friend_online[ui->friendtotal];
+ ui->friend_online[ui->friendtotal]=0;
+ }
+ }
+ currutmp->friendtotal--;
+ currutmp->friend_online[currutmp->friendtotal]=0;
+ }
+ return 0;
+}
+
+
+int friend_stat(userinfo_t *me, userinfo_t * ui)
+{
+ int i, j, hit=0;
+/* 看板好友 */
+ if (me->brc_id && ui->brc_id == me->brc_id)
+ {
+ hit = IBH;
+ }
+ for(i=0;me->friend_online[i];i++)
+ {
+ j = (me->friend_online[i] & 0xFFFFFF);
+ if(ui == &utmpshm->uinfo[j])
+ {
+ hit |= me->friend_online[i] >>24;
+ break;
+ }
+ }
+ if (PERM_HIDE(ui))
+ return hit & ST_FRIEND;
+ return hit;
+}
+
+int isvisible_stat(userinfo_t * me, userinfo_t * uentp, int fri_stat) {
+ if (uentp->userid[0] == 0)
+ return 0;
+
+ if (PERM_HIDE(uentp) && !(PERM_HIDE(me)))/* 對方紫色隱形而你沒有 */
+ return 0;
+ else if ((me->userlevel & PERM_SYSOP) ||
+ ((fri_stat & HRM) && (fri_stat & HFM))) /* 站長看的見任何人 */
+ return 1;
+
+ if (uentp->invisible && !(me->userlevel & PERM_SEECLOAK)) return 0;
+
+ return (fri_stat & HRM) ? 0 : 1;
+}
+
+int isvisible(userinfo_t * me, userinfo_t * uentp) {
+ return isvisible_stat(currutmp, uentp, friend_stat(me, uentp));
+}
+
+int isvisible_uid(int tuid){
+ userinfo_t *uentp;
+
+ if(!tuid || !(uentp = search_ulist(tuid)))
+ return 1;
+ return isvisible(currutmp, uentp);
+}
+
+/* 真實動作 */
+static void my_kick(userinfo_t * uentp) {
+ char genbuf[200];
+
+ getdata(1, 0, msg_sure_ny, genbuf, 4, LCECHO);
+ clrtoeol();
+ if (genbuf[0] == 'y')
+ {
+ sprintf(genbuf, "%s (%s)", uentp->userid, uentp->username);
+ log_usies("KICK ", genbuf);
+ if((uentp->pid <= 0 || kill(uentp->pid, SIGHUP) == -1) && (errno == ESRCH))
+ purge_utmp(uentp);
+ outs("踢出去囉");
+ }
+ else
+ outs(msg_cancel);
+ pressanykey();
+}
+
+static void chicken_query(char *userid) {
+ char buf[100];
+
+ if (getuser(userid))
+ {
+ if (xuser.mychicken.name[0])
+ {
+ time_diff(&(xuser.mychicken));
+ if (!isdeadth(&(xuser.mychicken)))
+ {
+ show_chicken_data(&(xuser.mychicken), NULL);
+ sprintf(buf, "\n\n以上是 %s 的寵物資料..", userid);
+ outs(buf);
+ }
+ }
+ else
+ {
+ move(1, 0);
+ clrtobot();
+ sprintf(buf, "\n\n%s 並沒有養寵物..", userid);
+ outs(buf);
+ }
+ pressanykey();
+ }
+}
+
+int my_query(char *uident) {
+ userec_t muser;
+ int tuid, i, fri_stat=0;
+ unsigned long int j;
+ userinfo_t *uentp;
+ static const char *money[10] =
+ {"債台高築", "赤貧", "清寒", "普通", "小康",
+ "小富", "中富", "大富翁", "富可敵國", "比爾蓋\天"},
+ *sex[8] =
+ {MSG_BIG_BOY, MSG_BIG_GIRL,
+ MSG_LITTLE_BOY, MSG_LITTLE_GIRL,
+ MSG_MAN, MSG_WOMAN, MSG_PLANT, MSG_MIME};
+
+
+ if ((tuid = getuser(uident)))
+ {
+ memcpy(&muser, &xuser, sizeof(muser));
+ move(1, 0);
+ clrtobot();
+ move(1, 0);
+ setutmpmode(TQUERY);
+ currutmp->destuid = tuid;
+
+ j = muser.money;
+ for (i = 0; i < 10 && j > 10; i++)
+ j /= 10;
+ prints("《ID暱稱》%s(%s)%*s《經濟狀況》%s\n",
+ muser.userid,
+ muser.username,
+ 26 - strlen(muser.userid) - strlen(muser.username), "",
+ money[i]);
+ prints("《上站次數》%d次", muser.numlogins);
+ move(2, 40);
+ prints("《文章篇數》%d篇\n", muser.numposts);
+
+ if((uentp = (userinfo_t *) search_ulist(tuid)))
+ fri_stat=friend_stat(currutmp, uentp);
+ prints("\033[1;33m《目前動態》%-28.28s\033[m",
+ (uentp && isvisible_stat(currutmp, uentp, fri_stat)) ?
+ modestring(uentp, 0) : "不在站上");
+
+ outs(((uentp && uentp->mailalert) || load_mailalert(muser.userid))
+ ? "《私人信箱》有新進信件還沒看\n" :
+ "《私人信箱》所有信件都看過了\n");
+ prints("《上次上站》%-28.28s《上次故鄉》%s\n",
+ Cdate(&muser.lastlogin),
+ (muser.lasthost[0] ? muser.lasthost : "(不詳)"));
+ if ((uentp && fri_stat&HFM) || HAS_PERM(PERM_SYSOP))
+ prints("《 性 別 》%-28.28s《私有財產》%ld 銀兩\n",
+ sex[muser.sex % 8],
+ muser.money);
+ prints("《五子棋戰績》%3d 勝 %3d 敗 %3d 和 "
+ "《象棋戰績》%3d 勝 %3d 敗 %3d 和",
+ muser.five_win, muser.five_lose, muser.five_tie,
+ muser.chc_win, muser.chc_lose, muser.chc_tie);
+ showplans(uident);
+ pressanykey();
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+}
+
+static char t_last_write[200] = "";
+
+void water_scr(water_t **currwater, int which, char type)
+{
+ if( type == 1 ){
+ int i;
+ int colors[] = {33, 37, 33, 37, 33};
+ move(8 + which, 28);prints(" ");
+ move(8 + which, 28);
+ prints("\033[1;37;45m %-14s \033[0m", currwater[which]->userid);
+ for( i = 0 ; i < 5 ; ++i ){
+ move(16 + i, 4);
+ prints(" ");
+ move(16 + i, 4);
+ if( currwater[which]->msg[ (currwater[which]->top-i+4) % 5 ].last_call_in[0] != 0 )
+ prints("\033[0m \033[1;%d;44m★%-64s\033[0m \n",
+ colors[i],
+ currwater[which]->msg[ (currwater[which]->top-i+4) % 5 ].last_call_in);
+ else
+ prints("\033[0m \n");
+ }
+ move(0, 0);prints(" ");
+ move(0, 0);
+ prints("\033[0m反擊 %s:", currwater[which]->userid);
+ clrtoeol();
+ move(0, strlen(currwater[which]->userid) + 6);
+ }
+ else{
+ move(8 + which, 28);
+ prints("123456789012345678901234567890");
+ // refresh();
+ move(8 + which, 28);
+ prints("\033[1;37;44m %-13s \033[0m", currwater[which]->userid);
+ // refresh();
+ }
+}
+
+void my_write2(void)
+{
+ int i, ch, currstat0, currwater_usies;
+ char genbuf[256], msg[80], done = 0, c0, which;
+ water_t *tw, *currwater[5];
+ unsigned char mode0;
+
+ watermode = 0;
+ currstat0 = currstat;
+ c0 = currutmp->chatid[0];
+ mode0 = currutmp->mode;
+ currutmp->mode = 0;
+ currutmp->chatid[0] = 3;
+ currstat = XMODE;
+
+ // init screen
+ memcpy(currwater, swater, sizeof(water_t*) * 5);
+ currwater_usies = water_usies;
+ move(7, 28);
+ prints("\033[1;33;46m ↑ 水球反擊對象 ↓\033[0m");
+ for( i = 0 ; i < 5 ; ++i )
+ if( currwater[i] == NULL || currwater[i]->pid == 0 )
+ break;
+ else
+ water_scr(currwater, i, 0);
+ move(15, 4);
+ prints("\033[0m \033[1;35m◇\033[1;36m────────────────"
+ "─────────────────\033[1;35m◇\033[0m ");
+ move(22, 4);
+ prints(" \033[1;35m◇\033[1;36m────────────────"
+ "─────────────────\033[1;35m◇\033[0m ");
+ move(21, 4);prints(" ");
+ move(21, 4);
+ prints("\033[0m \033[1;37;46m%-66s\033[0m \n", t_last_write);
+ water_scr(currwater, 0, 1);
+ refresh();
+
+ which = 0;
+ do{
+ switch( (ch = igetkey()) ){
+ case Ctrl('T'):
+ case KEY_UP:
+ if( currwater_usies != 1 ){
+ water_scr(currwater, which, 0);
+ which = (which - 1 + currwater_usies) % currwater_usies;
+ water_scr(currwater, which, 1);
+ refresh();
+ }
+ break;
+
+ case KEY_DOWN:
+ case Ctrl('R'):
+ if( currwater_usies != 1 ){
+ water_scr(currwater, which, 0);
+ which = (which + 1 + currwater_usies) % currwater_usies;
+ water_scr(currwater, which, 1);
+ refresh();
+ }
+ break;
+
+ case KEY_LEFT:
+ done = 1;
+ break;
+
+ default:
+ done = 1;
+ watermode = 1;
+ tw = currwater[(int)which];
+
+ if( ch != '\r' && ch != '\n' ){
+ msg[0] = ch, msg[1] = 0;
+ }
+ else
+ msg[0] = 0;
+ move(0, 0);prints("\033[m"); clrtoeol();
+ refresh();
+ sprintf(genbuf, "攻擊 %s:", tw->userid);
+ if( !oldgetdata(0, 0, genbuf, msg,
+ 80-strlen(tw->userid)-6, DOECHO) )
+ break;
+
+ my_write(tw->pid, msg, tw->userid, 4);
+ break;
+ }
+ } while( !done );
+
+ watermode = -1;
+ currstat = currstat0;
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+}
+
+/*
+ 被呼叫的時機:
+ 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
+*/
+int my_write(pid_t pid, char *prompt, char *id, int flag) {
+ int len, currstat0 = currstat, fri_stat;
+ char msg[80], destid[IDLEN + 1];
+ char genbuf[200], buf[200], c0 = currutmp->chatid[0];
+ unsigned char mode0 = currutmp->mode;
+ time_t now;
+ struct tm *ptime;
+ userinfo_t *uin;
+ uin = (userinfo_t *)search_ulist_pid(pid);
+ strcpy(destid, id);
+
+ if(!uin && !(flag == 0 && water_which->count> 0)) {
+ outmsg("\033[1;33;41m糟糕! 對方已落跑了(不在站上)! \033[37m~>_<~\033[m");
+ clrtoeol();
+ refresh();
+ watermode = -1;
+ return 0;
+ }
+ currutmp->mode = 0;
+ currutmp->chatid[0] = 3;
+ currstat = XMODE;
+
+ time(&now);
+ ptime = localtime(&now);
+
+ if(flag == 0) {
+ /* 一般水球 */
+ watermode = 0;
+ if(!(len = getdata(0, 0, prompt, msg, 56, DOECHO))) {
+ outmsg("\033[1;33;42m算了! 放你一馬...\033[m");
+ clrtoeol();
+ refresh();
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+ currstat = currstat0;
+ watermode = -1;
+ return 0;
+ }
+
+ if(watermode > 0) {
+ int i;
+
+ i = (water_which->top- watermode + MAX_REVIEW) % MAX_REVIEW;
+ uin = (userinfo_t *)search_ulist_pid(water_which->msg[i].pid);
+ strcpy(destid, water_which->msg[i].userid);
+ }
+ } else {
+ /* pre-edit 的水球 */
+ strcpy(msg, prompt);
+ len = strlen(msg);
+ }
+
+ watermode = -1;
+ strip_ansi(msg, msg, 0);
+ if(uin && *uin->userid && (flag == 0 || flag == 4)) {
+ sprintf(buf, "丟給 %s : %s [Y/n]?", uin->userid, msg);
+ getdata(0, 0, buf, genbuf, 3, LCECHO);
+ if(genbuf[0] == 'n') {
+ outmsg("\033[1;33;42m算了! 放你一馬...\033[m");
+ clrtoeol();
+ refresh();
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+ currstat = currstat0;
+ watermode = -1;
+ return 0;
+ }
+ }
+
+ if(!uin || !*uin->userid || strcasecmp(destid, uin->userid)) {
+ outmsg("\033[1;33;41m糟糕! 對方已落跑了(不在站上)! \033[37m~>_<~\033[m");
+ clrtoeol();
+ refresh();
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+ currstat = currstat0;
+ return 0;
+ }
+
+ fri_stat=friend_stat(currutmp, uin);
+ time(&now);
+ if(flag != 2) { /* aloha 的水球不用存下來 */
+ /* 存到自己的水球檔 */
+ if(!fp_writelog)
+ {
+ sethomefile(genbuf, cuser.userid, fn_writelog);
+ fp_writelog = fopen(genbuf, "a");
+ }
+ 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);
+ }
+ }
+
+ if(flag == 3 && uin->msgcount) {
+ /* 不懂 */
+ uin->destuip = currutmp - &utmpshm->uinfo[0];
+ uin->sig = 2;
+ if(uin->pid > 0) kill(uin->pid, SIGUSR1);
+ } else if(flag != 2 &&
+ !HAS_PERM(PERM_SYSOP) &&
+ (uin->pager == 3 ||
+ uin->pager == 2 ||
+ (uin->pager == 4 &&
+ !(fri_stat & HFM))))
+ outmsg("\033[1;33;41m糟糕! 對方防水了! \033[37m~>_<~\033[m");
+ else {
+ if(uin->msgcount < MAX_MSGS) {
+ unsigned char pager0 = uin->pager;
+
+ uin->pager = 2;
+ uin->msgs[uin->msgcount].pid = currpid;
+ strcpy(uin->msgs[uin->msgcount].userid, cuser.userid);
+ strcpy(uin->msgs[uin->msgcount++].last_call_in, msg);
+ uin->pager = pager0;
+ } else if (flag != 2)
+ outmsg("\033[1;33;41m糟糕! 對方不行了! (收到太多水球) \033[37m@_@\033[m");
+
+ if(uin->msgcount == 1 && (uin->pid <= 0 || kill(uin->pid, SIGUSR2) == -1) && flag != 2)
+ outmsg("\033[1;33;41m糟糕! 沒打中! \033[37m~>_<~\033[m");
+ else if(uin->msgcount == 1 && flag != 2)
+ outmsg("\033[1;33;44m水球砸過去了! \033[37m*^o^*\033[m");
+ else if(uin->msgcount > 1 && uin->msgcount < MAX_MSGS && flag != 2)
+ outmsg("\033[1;33;44m再補上一粒! \033[37m*^o^*\033[m");
+ }
+
+ clrtoeol();
+ refresh();
+
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+ currstat = currstat0;
+ return 1;
+}
+void t_display_new() {
+ static int t_display_new_flag=0;
+ int i, off=2;
+ if (t_display_new_flag)
+ return;
+ else
+ t_display_new_flag = 1;
+
+ if( WATERMODE(WATER_ORIG) )
+ water_which = &water[0];
+ else
+ off =3;
+
+ if (water[0].count && watermode > 0){
+ move(1, 0);
+ outs("───────水─球─回─顧───");
+ outs(WATERMODE(WATER_ORIG) ?
+ "──────用[Ctrl-R Ctrl-T]鍵切換─────" :
+ "用[Ctrl-R Ctrl-T Ctrl-E Ctrl-W ]鍵切換────");
+ if( WATERMODE(WATER_NEW) ){
+ move(2, 0);
+ clrtoeol();
+ for (i = 0; i<6 ; i++){
+ if(i>0)
+ prints("%s%-13.13s\033[m",
+ swater[i-1]==water_which?"\033[1;33;47m ":
+ " ",
+ swater[i-1] ? swater[i-1]->userid:"");
+ else
+ prints("%s 全部 \033[m",
+ water_which==&water[0]?"\033[1;33;45m ":
+ " ");
+ }
+ }
+
+ 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);
+ if(len<0) len=0;
+
+ move(i + (WATERMODE(WATER_ORIG)?2:3), 0);
+ clrtoeol();
+ if (watermode - 1 != i)
+ prints("\033[1;33;46m %s \033[37;45m %s \033[m%*s",
+ water_which->msg[a].userid,
+ water_which->msg[a].last_call_in, len,
+ "");
+ else
+ prints("\033[1;44m>\033[1;33;47m%s "
+ "\033[37;45m %s \033[m%*s",
+ water_which->msg[a].userid,
+ water_which->msg[a].last_call_in,
+ len,"");
+ }
+
+ if (t_last_write[0]){
+ move(i + off, 0);
+ clrtoeol();
+ prints(t_last_write);
+ i++;
+ }
+ move(i + off, 0);
+ outs("──────────────────────"
+ "─────────────────");
+ if( WATERMODE(WATER_NEW))
+ while( i++ <= water[0].count ) {
+ move(i + off, 0);
+ clrtoeol();
+ }
+ }
+
+ t_display_new_flag = 0;
+}
+#if 0
+void t_display_new() {
+ int i, which=water_which;
+ char buf[200];
+
+ if (t_display_new_flag)
+ return;
+ else
+ t_display_new_flag = 1;
+
+ if (oldmsg_count && watermode > 0)
+ {
+ move(1, 0);
+ outs(
+ "───────水─球─回─顧─────────"
+ "用[Ctrl-R Ctrl-T]鍵切換─────");
+ move(2, 0);
+ prints(" |");
+ for (i = 0; i<5 && water[i].pid != 0; i++)
+ prints(" %s%13.13s \033[m|",which==i?"\033[1;33m":"",
+ water[i].userid);
+
+ for( i = 0 ; i < 5 &&
+ water[which].msg[ (water[which].msgtop-i+4) % 5 ][0] != 0; ++i ){
+ move(3 + i, 0);
+ if (watermode - 1 != i)
+ sprintf(buf, "\033[1;33;46m %s \033[37;45m %s \033[m",
+ water[which].userid,
+ water[which].msg[ (water[which].msgtop-i+4) % 5 ]);
+ else
+ sprintf(buf, "\033[1;44m>\033[1;33;47m%s \033[37;45m %s \033[m",
+ water[which].userid,
+ water[which].msg[ (water[which].msgtop-i+4) % 5 ]);
+ }
+ /*
+ for (i = 0; i < oldmsg_count; i++)
+ {
+ int a = (water[water_which].top - i - 1 + MAX_REVIEW) % MAX_REVIEW;
+
+ move(i + 3, 0);
+ clrtoeol();
+ if (watermode - 1 != i)
+ sprintf(buf, "\033[1;33;46m %s \033[37;45m %s \033[m",
+ oldmsg[a].userid, oldmsg[a].last_call_in);
+ else
+ sprintf(buf, "\033[1;44m>\033[1;33;47m%s "
+ "\033[37;45m %s \033[m",
+ oldmsg[a].userid, oldmsg[a].last_call_in);
+ outs(buf);
+ }
+*/
+ if (t_last_write[0])
+ {
+ move(i + 3, 0);
+ clrtoeol();
+ outs(t_last_write);
+ i++;
+ }
+ move(i + 3, 0);
+ outs("───────────────────────"
+ "─────────────────");
+ }
+ t_display_new_flag = 0;
+}
+#endif
+
+int t_display() {
+ char genbuf[200], ans[4];
+ if(fp_writelog)
+ { fclose(fp_writelog); fp_writelog=NULL;}
+ setuserfile(genbuf, fn_writelog);
+ if (more(genbuf, YEA) != -1)
+ {
+ getdata(b_lines - 1, 0, "清除(C) 移至備忘錄(M) 保留(R) (C/M/R)?[R]",
+ ans, 3, LCECHO);
+ if (*ans == 'm')
+ {
+ fileheader_t mymail;
+ char title[128], buf[80];
+
+ sethomepath(buf, cuser.userid);
+ stampfile(buf, &mymail);
+
+ mymail.savemode = 'H'; /* hold-mail flag */
+ mymail.filemode = FILE_READ;
+ strcpy(mymail.owner, "[備.忘.錄]");
+ strcpy(mymail.title, "熱線\033[37;41m記錄\033[m");
+ sethomedir(title, cuser.userid);
+ Rename(genbuf, buf);
+ append_record(title, &mymail, sizeof(mymail));
+ }
+ else if (*ans == 'c')
+ unlink(genbuf);
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+}
+
+static void do_talk_nextline(talkwin_t * twin) {
+ twin->curcol = 0;
+ if (twin->curln < twin->eline)
+ ++(twin->curln);
+ else
+ region_scroll_up(twin->sline, twin->eline);
+ move(twin->curln, twin->curcol);
+}
+
+static void do_talk_char(talkwin_t * twin, int ch) {
+ extern screenline_t *big_picture;
+ screenline_t *line;
+ int i;
+ char ch0, buf[81];
+
+ if (isprint2(ch))
+ {
+ ch0 = big_picture[twin->curln].data[twin->curcol];
+ if (big_picture[twin->curln].len < 79)
+ move(twin->curln, twin->curcol);
+ else
+ do_talk_nextline(twin);
+ outc(ch);
+ ++(twin->curcol);
+ line = big_picture + twin->curln;
+ if (twin->curcol < line->len)
+ { /* insert */
+ ++(line->len);
+ memcpy(buf, line->data + twin->curcol, 80);
+ save_cursor();
+ do_move(twin->curcol, twin->curln);
+ ochar(line->data[twin->curcol] = ch0);
+ for (i = twin->curcol + 1; i < line->len; i++)
+ ochar(line->data[i] = buf[i - twin->curcol - 1]);
+ restore_cursor();
+ }
+ line->data[line->len] = 0;
+ return;
+ }
+
+ switch (ch)
+ {
+ case Ctrl('H'):
+ case '\177':
+ if (twin->curcol == 0)
+ return;
+ line = big_picture + twin->curln;
+ --(twin->curcol);
+ if (twin->curcol < line->len)
+ {
+ --(line->len);
+ save_cursor();
+ do_move(twin->curcol, twin->curln);
+ for (i = twin->curcol; i < line->len; i++)
+ ochar(line->data[i] = line->data[i + 1]);
+ line->data[i] = 0;
+ ochar(' ');
+ restore_cursor();
+ }
+ move(twin->curln, twin->curcol);
+ return;
+ case Ctrl('D'):
+ line = big_picture + twin->curln;
+ if (twin->curcol < line->len)
+ {
+ --(line->len);
+ save_cursor();
+ do_move(twin->curcol, twin->curln);
+ for (i = twin->curcol; i < line->len; i++)
+ ochar(line->data[i] = line->data[i + 1]);
+ line->data[i] = 0;
+ ochar(' ');
+ restore_cursor();
+ }
+ return;
+ case Ctrl('G'):
+ bell();
+ return;
+ case Ctrl('B'):
+ if (twin->curcol > 0)
+ {
+ --(twin->curcol);
+ move(twin->curln, twin->curcol);
+ }
+ return;
+ case Ctrl('F'):
+ if (twin->curcol < 79)
+ {
+ ++(twin->curcol);
+ move(twin->curln, twin->curcol);
+ }
+ return;
+ case KEY_TAB:
+ twin->curcol += 8;
+ if (twin->curcol > 80)
+ twin->curcol = 80;
+ move(twin->curln, twin->curcol);
+ return;
+ case Ctrl('A'):
+ twin->curcol = 0;
+ move(twin->curln, twin->curcol);
+ return;
+ case Ctrl('K'):
+ clrtoeol();
+ return;
+ case Ctrl('Y'):
+ twin->curcol = 0;
+ move(twin->curln, twin->curcol);
+ clrtoeol();
+ return;
+ case Ctrl('E'):
+ twin->curcol = big_picture[twin->curln].len;
+ move(twin->curln, twin->curcol);
+ return;
+ case Ctrl('M'):
+ case Ctrl('J'):
+ line = big_picture + twin->curln;
+ strncpy(buf, line->data, line->len);
+ buf[line->len] = 0;
+ do_talk_nextline(twin);
+ break;
+ case Ctrl('P'):
+ line = big_picture + twin->curln;
+ strncpy(buf, line->data, line->len);
+ buf[line->len] = 0;
+ if (twin->curln > twin->sline)
+ {
+ --(twin->curln);
+ move(twin->curln, twin->curcol);
+ }
+ break;
+ case Ctrl('N'):
+ line = big_picture + twin->curln;
+ strncpy(buf, line->data, line->len);
+ buf[line->len] = 0;
+ if (twin->curln < twin->eline)
+ {
+ ++(twin->curln);
+ move(twin->curln, twin->curcol);
+ }
+ break;
+ }
+ trim(buf);
+ if (*buf)
+ fprintf(flog, "%s%s: %s%s\n",
+ (twin->eline == b_lines - 1) ? "\033[1;35m" : "",
+ (twin->eline == b_lines - 1) ?
+ getuserid(currutmp->destuid) : cuser.userid, buf,
+ (ch == Ctrl('P')) ? "\033[37;45m(Up)\033[m" : "\033[m");
+}
+
+static void do_talk(int fd) {
+ struct talkwin_t mywin, itswin;
+ char mid_line[128], data[200];
+ int i, datac, ch;
+ int im_leaving = 0;
+ FILE *log;
+ struct tm *ptime;
+ time_t now;
+ char genbuf[200], fpath[100];
+
+ time(&now);
+ ptime = localtime(&now);
+
+ sethomepath(fpath, cuser.userid);
+ strcpy(fpath, tempnam(fpath, "talk_"));
+ flog = fopen(fpath, "w");
+
+ setuserfile(genbuf, fn_talklog);
+
+ if ((log = fopen(genbuf, "w")))
+ fprintf(log, "[%d/%d %d:%02d] & %s\n",
+ ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour,
+ ptime->tm_min, save_page_requestor);
+ setutmpmode(TALK);
+
+ ch = 58 - strlen(save_page_requestor);
+ sprintf(genbuf, "%s【%s", cuser.userid, cuser.username);
+ i = ch - strlen(genbuf);
+ if (i >= 0)
+ i = (i >> 1) + 1;
+ else
+ {
+ genbuf[ch] = '\0';
+ i = 1;
+ }
+ memset(data, ' ', i);
+ data[i] = '\0';
+
+ sprintf(mid_line, "\033[1;46;37m 談天說地 \033[45m%s%s】"
+ " 與 %s%s\033[0m", data, genbuf, save_page_requestor, data);
+
+ memset(&mywin, 0, sizeof(mywin));
+ memset(&itswin, 0, sizeof(itswin));
+
+ i = b_lines >> 1;
+ mywin.eline = i - 1;
+ itswin.curln = itswin.sline = i + 1;
+ itswin.eline = b_lines - 1;
+
+ clear();
+ move(i, 0);
+ outs(mid_line);
+ move(0, 0);
+
+ add_io(fd, 0);
+
+ while (1)
+ {
+ ch = igetkey();
+ if (ch == I_OTHERDATA)
+ {
+ datac = recv(fd, data, sizeof(data), 0);
+ if (datac <= 0)
+ break;
+ for (i = 0; i < datac; i++)
+ do_talk_char(&itswin, data[i]);
+ }
+ else
+ {
+ if (ch == Ctrl('C'))
+ {
+ if (im_leaving)
+ break;
+ move(b_lines, 0);
+ clrtoeol();
+ outs("再按一次 Ctrl-C 就正式中止談話囉!");
+ im_leaving = 1;
+ continue;
+ }
+ if (im_leaving)
+ {
+ move(b_lines, 0);
+ clrtoeol();
+ im_leaving = 0;
+ }
+ switch (ch)
+ {
+ case KEY_LEFT: /* 把2byte的鍵改為一byte */
+ ch = Ctrl('B');
+ break;
+ case KEY_RIGHT:
+ ch = Ctrl('F');
+ break;
+ case KEY_UP:
+ ch = Ctrl('P');
+ break;
+ case KEY_DOWN:
+ ch = Ctrl('N');
+ break;
+ }
+ data[0] = (char) ch;
+ if (send(fd, data, 1, 0) != 1)
+ break;
+ if (log)
+ fprintf(log, "%c", (ch == Ctrl('M')) ? '\n' : (char) *data);
+ do_talk_char(&mywin, *data);
+ }
+ }
+ if (log)
+ fclose(log);
+
+ add_io(0, 0);
+ close(fd);
+
+ if (flog)
+ {
+ char ans[4];
+ extern screenline_t *big_picture;
+ extern unsigned char scr_lns;
+ int i;
+
+ time(&now);
+ fprintf(flog, "\n\033[33;44m離別畫面 [%s] ... \033[m\n",
+ Cdatelite(&now));
+ for (i = 0; i < scr_lns; i++)
+ fprintf(flog, "%.*s\n", big_picture[i].len, big_picture[i].data);
+ fclose(flog);
+ more(fpath, NA);
+ getdata(b_lines - 1, 0, "清除(C) 移至備忘錄(M). (C/M)?[C]",
+ ans, 4, LCECHO);
+ if (*ans == 'm')
+ {
+ fileheader_t mymail;
+ char title[128];
+
+ sethomepath(genbuf, cuser.userid);
+ stampfile(genbuf, &mymail);
+ mymail.savemode = 'H'; /* hold-mail flag */
+ mymail.filemode = FILE_READ;
+ strcpy(mymail.owner, "[備.忘.錄]");
+ sprintf(mymail.title, "對話記錄 \033[1;36m(%s)\033[m",
+ getuserid(currutmp->destuid));
+ sethomedir(title, cuser.userid);
+ Rename(fpath, genbuf);
+ append_record(title, &mymail, sizeof(mymail));
+ }
+ else
+ unlink(fpath);
+ flog = 0;
+ }
+ setutmpmode(XINFO);
+}
+
+#define lockreturn(unmode, state) if(lockutmpmode(unmode, state)) return
+
+static void my_talk(userinfo_t * uin, int fri_stat) {
+ int sock, msgsock, length, ch, error = 0;
+ struct sockaddr_in server;
+ pid_t pid;
+ char c;
+ char genbuf[4];
+
+ unsigned char mode0 = currutmp->mode;
+
+ ch = uin->mode;
+ strcpy(currauthor, uin->userid);
+
+ if (ch == EDITING || ch == TALK || ch == CHATING || ch == PAGE ||
+ ch == MAILALL || ch == MONITOR || ch == M_FIVE || ch == CHC ||
+ (!ch && (uin->chatid[0] == 1 || uin->chatid[0] == 3)) ||
+ uin->lockmode == M_FIVE || uin->lockmode == CHC)
+ {
+ outs("人家在忙啦");
+ }
+ else if (!HAS_PERM(PERM_SYSOP) &&
+ (
+ ((fri_stat& HRM) && !(fri_stat& HFM)) ||
+ ((!uin->pager) && !(fri_stat & HFM))
+ )
+ )
+ {
+ outs("對方關掉呼叫器了");
+ }
+ else if (!HAS_PERM(PERM_SYSOP) &&
+ (
+ ((fri_stat & HRM) && !(fri_stat& HFM)) ||
+ uin->pager == 2
+ )
+ )
+ {
+ outs("對方拔掉呼叫器了");
+ }
+ else if (!HAS_PERM(PERM_SYSOP) &&
+ !(fri_stat & HFM) && uin->pager == 4)
+ {
+ outs("對方只接受好友的呼叫");
+ }
+ else if (!(pid = uin->pid) /*|| (kill(pid, 0) == -1) */ )
+ {
+// resetutmpent();
+ outs(msg_usr_left);
+ }
+ else
+ {
+ showplans(uin->userid);
+ getdata(2, 0, "要和他(她) (T)談天(F)下五子棋(P)鬥寵物"
+ "(C)下象棋(D)下暗棋(N)沒事找錯人了?[N] ", genbuf, 4, LCECHO);
+ switch (*genbuf)
+ {
+ case 'y':
+ case 't':
+ uin->sig = SIG_TALK;
+ break;
+ case 'f':
+ lockreturn(M_FIVE, LOCK_THIS);
+ uin->sig = SIG_GOMO;
+ break;
+ case 'c':
+ lockreturn(CHC, LOCK_THIS);
+ uin->sig = SIG_CHC;
+ break;
+ case 'd':
+ uin->sig = SIG_DARK;
+ break;
+ case 'p':
+ reload_chicken();
+ getuser(uin->userid);
+ if (uin->lockmode == CHICKEN || currutmp->lockmode == CHICKEN)
+ error = 1;
+ if (!cuser.mychicken.name[0] || !xuser.mychicken.name[0])
+ error = 2;
+ if (error)
+ {
+ outmsg(error == 2 ? "並非兩人都養寵物" :
+ "有一方的寵物正在使用中");
+ bell();
+ refresh();
+ sleep(1);
+ return;
+ }
+ uin->sig = SIG_PK;
+ break;
+ default:
+ return;
+ }
+
+ uin->turn = 1;
+ currutmp->turn = 0;
+ strcpy(uin->mateid, currutmp->userid);
+ strcpy(currutmp->mateid, uin->userid);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ perror("sock err");
+ unlockutmpmode();
+ return;
+ }
+ server.sin_family = PF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+ server.sin_port = 0;
+ if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0)
+ {
+ close(sock);
+ perror("bind err");
+ unlockutmpmode();
+ return;
+ }
+ length = sizeof(server);
+ if (getsockname(sock, (struct sockaddr *) &server, &length) < 0)
+ {
+ close(sock);
+ perror("sock name err");
+ unlockutmpmode();
+ return;
+ }
+ currutmp->sockactive = YEA;
+ currutmp->sockaddr = server.sin_port;
+ currutmp->destuid = uin->uid;
+ setutmpmode(PAGE);
+ uin->destuip = currutmp - &utmpshm->uinfo[0];
+ if(pid > 0) kill(pid, SIGUSR1);
+ clear();
+ prints("正呼叫 %s.....\n鍵入 Ctrl-D 中止....", uin->userid);
+
+ listen(sock, 1);
+ add_io(sock, 5);
+ while (1)
+ {
+ ch = igetch();
+ if (ch == I_TIMEOUT)
+ {
+ ch = uin->mode;
+ if (!ch && uin->chatid[0] == 1 &&
+ uin->destuip == currutmp - &utmpshm->uinfo[0])
+ {
+ bell();
+ outmsg("對方回應中...");
+ refresh();
+ }
+ else if (ch == EDITING || ch == TALK || ch == CHATING ||
+ ch == PAGE || ch == MAILALL || ch == MONITOR ||
+ ch == M_FIVE || ch == CHC ||
+ (!ch && (uin->chatid[0] == 1 ||
+ uin->chatid[0] == 3)))
+ {
+ add_io(0, 0);
+ close(sock);
+ currutmp->sockactive = currutmp->destuid = 0;
+ outmsg("人家在忙啦");
+ pressanykey();
+ unlockutmpmode();
+ return;
+ }
+ else
+ {
+#ifdef linux
+ add_io(sock, 20); /* added for linux... achen */
+#endif
+ move(0, 0);
+ outs("再");
+ bell();
+
+ uin->destuip = currutmp - &utmpshm->uinfo[0];
+ if(pid <= 0 || kill(pid, SIGUSR1) == -1)
+ {
+#ifdef linux
+ add_io(sock, 20); /* added 4 linux... achen */
+#endif
+ outmsg(msg_usr_left);
+ refresh();
+ pressanykey();
+ unlockutmpmode();
+ return;
+ }
+ continue;
+ }
+ }
+
+ if (ch == I_OTHERDATA)
+ break;
+
+ if (ch == '\004')
+ {
+ add_io(0, 0);
+ close(sock);
+ currutmp->sockactive = currutmp->destuid = 0;
+ unlockutmpmode();
+ return;
+ }
+ }
+
+ msgsock = accept(sock, (struct sockaddr *) 0, (int *) 0);
+ if (msgsock == -1)
+ {
+ perror("accept");
+ unlockutmpmode();
+ return;
+ }
+ add_io(0, 0);
+ close(sock);
+ currutmp->sockactive = NA;
+ read(msgsock, &c, sizeof c);
+
+ if (c == 'y')
+ {
+ sprintf(save_page_requestor, "%s (%s)",
+ uin->userid, uin->username);
+ /* gomo */
+ switch (uin->sig)
+ {
+ case SIG_DARK:
+ main_dark(msgsock, uin);
+ break;
+ case SIG_PK:
+ chickenpk(msgsock);
+ break;
+ case SIG_GOMO:
+ gomoku(msgsock);
+ break;
+ case SIG_CHC:
+ chc(msgsock);
+ break;
+ case SIG_TALK:
+ default:
+ do_talk(msgsock);
+ }
+ }
+ else
+ {
+ move(9, 9);
+ outs("【回音】 ");
+ switch (c)
+ {
+ case 'a':
+ outs("我現在很忙,請等一會兒再 call 我,好嗎?");
+ break;
+ case 'b':
+ prints("對不起,我有事情不能跟你 %s....", sig_des[uin->sig]);
+ break;
+ case 'd':
+ outs("我要離站囉..下次再聊吧..........");
+ break;
+ case 'c':
+ outs("請不要吵我好嗎?");
+ break;
+ case 'e':
+ outs("找我有事嗎?請先來信唷....");
+ break;
+ case 'f':
+ {
+ char msgbuf[60];
+
+ read(msgsock, msgbuf, 60);
+ prints("對不起,我現在不能跟你 %s,因為\n", sig_des[uin->sig]);
+ move(10, 18);
+ outs(msgbuf);
+ }
+ break;
+ case '1':
+ prints("%s?先拿100銀兩來..", sig_des[uin->sig]);
+ break;
+ case '2':
+ prints("%s?先拿1000銀兩來..", sig_des[uin->sig]);
+ break;
+ default:
+ prints("我現在不想 %s 啦.....:)", sig_des[uin->sig]);
+ }
+ close(msgsock);
+ }
+ }
+ currutmp->mode = mode0;
+ currutmp->destuid = 0;
+ unlockutmpmode();
+ pressanykey();
+}
+
+/* 選單式聊天介面 */
+#define US_PICKUP 1234
+#define US_RESORT 1233
+#define US_ACTION 1232
+#define US_REDRAW 1231
+
+static void t_showhelp() {
+ clear();
+
+ outs("\033[36m【 休閒聊天使用說明 】\033[m\n\n"
+ "(←)(e) 結束離開 (h) 看使用說明\n"
+ "(↑)/(↓)(n) 上下移動 (TAB) 切換排序方式\n"
+ "(PgUp)(^B) 上頁選單 ( )(PgDn)(^F) 下頁選單\n"
+ "(Hm)/($)(Ed) 首/尾 (S) "
+ "來源/好友描述/戰績 切換\n"
+ "(m) 寄信 (q/c) "
+ "查詢網友/寵物\n"
+ "(r) 閱\讀信件 (l) 看上次熱訊\n"
+ "(f) 全部/好友列表 (數字) 跳至該使用者\n"
+ "(p) 切換呼叫器 (g/i) 給錢/切換心情\n"
+ "(a/d/o) 好友 增加/刪除/修改 (/)(s) 網友ID/暱稱搜尋");
+
+ if (HAS_PERM(PERM_PAGE))
+ {
+ outs("\n\n\033[36m【 交談專用鍵 】\033[m\n\n"
+ "(→)(t)(Enter) 跟他/她聊天\n"
+ "(w) 熱線 Call in\n"
+ "(b) 對好友廣播 (一定要在好友列表中)\n"
+ "(^R) 即時回應 (有人 Call in 你時)");
+ }
+
+ if (HAS_PERM(PERM_SYSOP))
+ {
+ outs("\n\n\033[36m【 站長專用鍵 】\033[m\n\n");
+ if (HAS_PERM(PERM_SYSOP))
+ outs("(u)/(H) 設定使用者資料/切換隱形模式\n");
+ outs("(R)/(K) 查詢使用者的真實姓名/把壞蛋踢出去\n");
+ }
+ pressanykey();
+}
+
+static int listcuent(userinfo_t * uentp) {
+ if((!uentp->invisible || HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_SEECLOAK)))
+ AddNameList(uentp->userid);
+ return 0;
+}
+
+static void creat_list() {
+ CreateNameList();
+ apply_ulist(listcuent);
+}
+
+static int search_pickup(int num, int actor, pickup_t pklist[]) {
+ char genbuf[IDLEN + 2];
+
+ move(1, 0);
+ creat_list();
+ namecomplete(msg_uid, genbuf);
+ if (genbuf[0])
+ {
+ int n = (num + 1) % actor;
+ while (n != num)
+ {
+ if (!strcasecmp(pklist[n].ui->userid, genbuf))
+ return n;
+ if (++n >= actor)
+ n = 0;
+ }
+ }
+ return -1;
+}
+
+/* Kaede show friend description */
+static char *friend_descript(char *uident) {
+ static char *space_buf = " ";
+ static char desc_buf[80];
+ char fpath[80], name[IDLEN + 2], *desc, *ptr;
+ int len, flag;
+ FILE *fp;
+ char genbuf[200];
+
+ setuserfile(fpath, friend_file[0]);
+
+ if ((fp = fopen(fpath, "r")))
+ {
+ sprintf(name, "%s ", uident);
+ len = strlen(name);
+ desc = genbuf + 13;
+
+ while ((flag = (int) fgets(genbuf, STRLEN, fp)))
+ {
+ if (!memcmp(genbuf, name, len))
+ {
+ if ((ptr = strchr(desc, '\n')))
+ ptr[0] = '\0';
+ if (desc)
+ break;
+ }
+ }
+ fclose(fp);
+ if (desc && flag)
+ strcpy(desc_buf, desc);
+ else
+ return space_buf;
+
+ return desc_buf;
+ }
+ else
+ return space_buf;
+}
+
+static char *descript(int show_mode, userinfo_t * uentp, time_t diff,
+ fromcache_t * fcache) {
+ switch (show_mode)
+ {
+ case 1:
+ return friend_descript(uentp->userid);
+ case 0:
+ return (((uentp->pager != 2 && uentp->pager != 3 && diff) ||
+ HAS_PERM(PERM_SYSOP)) ?
+#ifdef WHERE
+ uentp->from_alias ? fcache->replace[uentp->from_alias] :
+ uentp->from
+#else
+ uentp->from
+#endif
+ : "*");
+ case 2:
+ sprintf(description, "%3d/%3d/%3d", uentp->five_win,
+ uentp->five_lose, uentp->five_tie);
+ description[20] = 0;
+ return description;
+ default:
+ syslog(LOG_WARNING, "damn!!! what's wrong?? show_mode = %d",
+ show_mode);
+ return "";
+ }
+}
+
+static int pickup_user_cmp(time_t now, int sortedway, int cmp_fri,
+ pickup_t pklist[], int *bfriends_number, int *ifh_number,
+ int *hfm_number,int *irh_number, char *keyword)
+{
+ int i, fri_stat, is_friend, count=0, diff;
+ userinfo_t *uentp;
+ for (i=0;i<utmpshm->number;i++)
+ {
+ uentp = (utmpshm->sorted[utmpshm->currsorted][sortedway][i]);
+ if (!uentp || !uentp->pid) continue;
+ fri_stat = friend_stat(currutmp, uentp);
+ if(uentp->uid==currutmp->uid)
+ fri_stat = fri_stat|IFH|HFM;
+ is_friend = (fri_stat & IRH) && !(fri_stat & IFH) ? 0 :
+ fri_stat & ST_FRIEND;
+ if (!isvisible_stat(currutmp, uentp, fri_stat) ||
+ ((cmp_fri==1 && !is_friend) ||
+ (cmp_fri==-1 && is_friend)) ||
+ (keyword[0] && !strcasestr(uentp->username,keyword))
+ ) continue;
+ if (bfriends_number && fri_stat & IBH) (*bfriends_number)++;
+ if (ifh_number && fri_stat & IFH) (*ifh_number)++;
+ if (hfm_number && fri_stat & HFM) (*hfm_number)++;
+ if (irh_number && fri_stat & IRH) (*irh_number)++;
+#ifdef SHOW_IDLE_TIME
+ diff = now - uentp->lastact;
+#ifdef DOTIMEOUT
+ /* prevent fault /dev mount from kicking out users */
+ if ((diff > curr_idle_timeout + 10) &&
+ (diff < 60 * 60 * 24 * 5))
+ {
+ if ((uentp->pid <= 0 || kill(uentp->pid, SIGHUP) == -1) &&
+ (errno == ESRCH))
+ purge_utmp(uentp);
+ continue;
+ }
+#endif
+ pklist[count].idle = diff;
+#endif
+ pklist[count].friend = fri_stat;
+ pklist[count].ui = uentp;
+ count++;
+ }
+ return count;
+}
+
+static int cmputmpfriend(const void *i, const void *j)
+{
+ if((((pickup_t*)j)->friend&ST_FRIEND)==(((pickup_t*)i)->friend&ST_FRIEND))
+ return strcasecmp( ((pickup_t*)i)->ui->userid,
+ ((pickup_t*)j)->ui->userid);
+ else
+ return (((pickup_t*)j)->friend&ST_FRIEND) -
+ (((pickup_t*)i)->friend&ST_FRIEND);
+}
+
+static void pickup_user() {
+ static int real_name = 0;
+ static int show_mode = 0;
+ static int show_uid = 0;
+ static int show_board = 0;
+ static int show_pid = 0;
+ static int num = 0;
+ char genbuf[200];
+
+#ifdef WHERE
+ extern struct fromcache_t *fcache;
+#endif
+
+ register userinfo_t *uentp;
+ register pid_t pid0 = 0; /* Ptt 定位 */
+ register int id0 = 0; /* US_PICKUP時的游標用 */
+ register int state = US_PICKUP, ch;
+ register int actor = 0, head, foot;
+ int fri_stat, bfriends_number, ifh_number, irh_number, hfm_number;
+ int savemode = currstat;
+ int i, sortedway; /* 只是loop有用到 */
+ time_t diff, freshtime;
+ pickup_t pklist[USHM_SIZE]; /* parameter Ptt註 */
+/* num : 現在的游標位 */
+/* foot: 此頁的腳腳 */
+ char buf[20],keyword[13]=""; /* actor:共有多少user */
+ char pagerchar[5] = "* -Wf";
+ char *msg_pickup_way[PICKUP_WAYS] =
+ {
+ "嗨! 朋友",
+ "網友代號",
+ "網友動態",
+ "發呆時間",
+ "來自何方",
+ "五子棋 ",
+// "女士優先"
+ };
+ char *MODE_STRING[MAX_SHOW_MODE] =
+ {
+ "故鄉",
+ "好友描述",
+ "五子棋戰績"
+ };
+ char
+ *Mind[] =
+ {" ",
+ "^-^", "^_^", "Q_Q", "@_@", "/_\\", "=_=", "-_-", "-.-", ">_<",
+ "-_+", "!_!", "o_o", "z_Z", "O_O", "O.O", "$_$", "^*^", "O_<",
+ "喜!", "怒!", "哀!", "樂!", ":) ", ":( ", ":~ ", ":q ", ":O ",
+ ":D ", ":p ", ";) ", ":> ", ";> ", ":< ", ":)~", ":D~", ">< ",
+ "^^;", "^^|", "哭;", NULL};
+
+ while (1)
+ {
+ if (utmpshm->uptime > freshtime || state == US_PICKUP ||
+ state ==US_RESORT)
+ {
+ state = US_PICKUP;
+ time(&freshtime);
+ ifh_number=hfm_number=irh_number=bfriends_number = actor = ch = 0;
+ if(pickup_way==0)
+ sortedway=0;
+ else
+ sortedway=pickup_way-1;
+
+ //qsort(pklist,actor,sizeof(pickup_t),cmputmpfriend);
+ if(pickup_way==0 || (cuser.uflag & FRIEND_FLAG))
+ {
+ actor=pickup_user_cmp(freshtime, sortedway, 1,
+ pklist, &bfriends_number, &ifh_number, &hfm_number,
+ NULL,keyword);
+ if(sortedway==0)
+ qsort(pklist,actor,sizeof(pickup_t),cmputmpfriend);
+ if(!(cuser.uflag & FRIEND_FLAG))
+ actor=pickup_user_cmp(freshtime, sortedway, -1,
+ pklist+actor, NULL, NULL, NULL, &irh_number,
+ keyword);
+ }
+ else
+ {
+ actor=pickup_user_cmp(freshtime, sortedway, 0,
+ pklist, &bfriends_number, &ifh_number, &hfm_number,
+ &irh_number, keyword);
+ }
+
+
+ if (!actor)
+ {
+ if(keyword[0])
+ {
+ mprints(b_lines-1,0,
+ "搜尋不到任何人 !!");
+ keyword[0]=0;
+ pressanykey();
+ continue;
+ }
+ getdata(b_lines - 1, 0,
+ "你的朋友還沒上站,要看看一般網友嗎(Y/N)?[Y]",
+ genbuf, 4, LCECHO);
+ if (genbuf[0] != 'n')
+ {
+ cuser.uflag &= ~FRIEND_FLAG;
+ continue;
+ }
+ return;
+ }
+ }
+ if (state >= US_ACTION)
+ {
+ showtitle((cuser.uflag & FRIEND_FLAG) ? "好友列表" : "休閒聊天",
+ BBSName);
+ prints(" 排序:[%s] 上站人數:%-4d\033[1;32m我的朋友:%-3d"
+ "\033[33m與我為友:%-3d\033[36m板友:%-4d\033[31m壞人:"
+ "%-2d\033[m\n"
+ "\033[7m %s P%c代號 %-17s%-17s%-13s%-10s\033[m\n",
+ msg_pickup_way[pickup_way], actor, ifh_number,
+ hfm_number, bfriends_number, irh_number,
+ show_uid ? "UID" : "No.",
+ (HAS_PERM(PERM_SEECLOAK) || HAS_PERM(PERM_SYSOP)) ? 'C' : ' ',
+ real_name ? "姓名" : "暱稱",
+ MODE_STRING[show_mode],
+ show_board ? "Board" : "動態",
+ show_pid ? " PID" : "備註 發呆"
+ );
+ }
+ else
+ {
+ move(3, 0);
+ clrtobot();
+ }
+ if (pid0)
+ for (ch = 0; ch < actor; ch++)
+ {
+ if (pid0 == (pklist[ch].ui)->pid &&
+ id0 == 256 * pklist[ch].ui->userid[0] +
+ pklist[ch].ui->userid[1])
+ {
+ num = ch;
+ }
+ }
+ if (num < 0)
+ num = 0;
+ else if (num >= actor)
+ num = actor - 1;
+ head = (num / p_lines) * p_lines;
+ foot = head + p_lines;
+ if (foot > actor)
+ foot = actor;
+ for (ch = head; ch < foot; ch++)
+ {
+ uentp = pklist[ch].ui;
+
+ if (!uentp->pid)
+ {
+ prints("%5d < 離站中..>\n",ch);
+ continue;
+ }
+#ifdef SHOW_IDLE_TIME
+ diff = pklist[ch].idle;
+ if (diff > 59990) diff = 59990; /* Doma: 以免一大串的發呆時間 */
+ if (diff > 0)
+ sprintf(buf, "%3ld'%02ld", diff / 60, diff % 60);
+ else
+ buf[0] = '\0';
+#else
+ buf[0] = '\0';
+#endif
+ i = pklist[ch].friend;
+#ifdef SHOWPID
+ if (show_pid)
+ sprintf(buf, "%6d", uentp->pid);
+#endif
+ if (PERM_HIDE(uentp))
+ state = 9;
+ else if(currutmp == uentp)
+ state =10;
+ else if(i & IRH && !(i & IFH))
+ state = 8;
+ else
+ state =(i&ST_FRIEND)>>2;
+ diff = uentp->pager & !(i&HRM);
+ prints("%5d %c%c%s%-13s%-17.16s\033[m%-17.16s%-13.13s"
+ "\33[33m%-4.4s\33[m%s\n",
+#ifdef SHOWUID
+ show_uid ? uentp->uid :
+#endif
+ (ch + 1),
+ (i & HRM) ? 'X' :
+ pagerchar[uentp->pager % 5],
+ (uentp->invisible ? ')' : ' '),
+ fcolor[state],
+ /* %s */
+ uentp->userid,
+
+ /* %-13s 暱稱 */
+#ifdef REALINFO
+ real_name ? uentp->realname :
+#endif
+ uentp->username,
+ /* %-17.16s 故鄉 */
+ descript(show_mode, uentp, diff, fcache),
+
+ /* %-17.16s 看板 */
+#ifdef SHOWBOARD
+ show_board ? (uentp->brc_id == 0 ? "" :
+ bcache[uentp->brc_id - 1].brdname) :
+#endif
+ /* %-13.13s */
+ modestring(uentp, 0),
+ /* %4s 備註 */
+ ((uentp->userlevel & PERM_VIOLATELAW) ? "通緝" :
+ (uentp->birth ? "壽星" :
+ Mind[uentp->mind])),
+ /* %s 發呆 */
+ buf);
+ }
+ if (state == US_PICKUP)
+ continue;
+
+ move(b_lines, 0);
+ outs("\033[31;47m(TAB/f)\033[30m排序/好友 \033[31m(t)\033[30m聊天 "
+ "\033[31m(a/d/o)\033[30m交友 \033[31m(q)\033[30m查詢 "
+ "\033[31m(w)\033[30m水球 \033[31m(m)\033[30m寄信 \033[31m(h)"
+ "\033[30m線上輔助 \033[m");
+ state = 0;
+ while (!state)
+ {
+ ch = cursor_key(num + 3 - head, 0);
+ if (ch == KEY_RIGHT || ch == '\n' || ch == '\r')
+ ch = 't';
+
+ switch (ch)
+ {
+ case KEY_LEFT:
+ case 'e':
+ case 'E':
+ if(!keyword[0]) return;
+ keyword[0]=0;
+ state = US_PICKUP;
+ break;
+
+ case KEY_TAB:
+ pickup_way = (pickup_way + 1) % PICKUP_WAYS;
+ state = US_RESORT;
+ num = 0;
+ break;
+
+ case KEY_DOWN:
+ case 'n':
+ case 'j':
+ if (++num < actor)
+ {
+ if (num >= foot)
+ state = US_REDRAW;
+ break;
+ }
+ case '0':
+ case KEY_HOME:
+ num = 0;
+ if (head)
+ state = US_REDRAW;
+ break;
+ case 'H':
+ if (HAS_PERM(PERM_SYSOP))
+ {
+ currutmp->userlevel ^= PERM_DENYPOST;
+ state = US_REDRAW;
+ }
+ break;
+ case 'D':
+ if (HAS_PERM(PERM_SYSOP))
+ {
+ char buf[100];
+
+ sprintf(buf, "代號 [%s]:", currutmp->userid);
+ if (!getdata(1, 0, buf, currutmp->userid, IDLEN + 1,
+ DOECHO))
+ strcpy(currutmp->userid, cuser.userid);
+ state = US_REDRAW;
+ }
+ break;
+ case 'F':
+ if (HAS_PERM(PERM_SYSOP))
+ {
+ char buf[100];
+
+ sprintf(buf, "故鄉 [%s]:", currutmp->from);
+ if (!getdata(1, 0, buf, currutmp->from, 17, DOECHO))
+ strncpy(currutmp->from, fromhost, 23);
+ state = US_REDRAW;
+ }
+ break;
+ case 'C':
+#if !HAVE_FREECLOAK
+ if (HAS_PERM(PERM_CLOAK))
+#endif
+ {
+ currutmp->invisible ^= 1;
+ state = US_REDRAW;
+ }
+ break;
+ case ' ':
+ case KEY_PGDN:
+ case Ctrl('F'):
+ if (foot < actor)
+ {
+ num += p_lines;
+ state = US_REDRAW;
+ break;
+ }
+ if (head)
+ num = 0;
+ state = US_PICKUP;
+ break;
+ case KEY_UP:
+ case 'k':
+ if (--num < head)
+ {
+ if (num < 0)
+ {
+ num = actor - 1;
+ if (actor == foot)
+ break;
+ }
+ state = US_REDRAW;
+ }
+ break;
+ case KEY_PGUP:
+ case Ctrl('B'):
+ case 'P':
+ if (head)
+ {
+ num -= p_lines;
+ state = US_REDRAW;
+ break;
+ }
+
+ case KEY_END:
+ case '$':
+ num = actor - 1;
+ if (foot < actor)
+ state = US_REDRAW;
+ break;
+
+ case '/':
+ getdata_buf(b_lines-1,0,"請輸入暱稱關鍵字:",keyword, 12,
+ DOECHO);
+ state = US_PICKUP;
+ break;
+ case 's':
+ if ((i = search_pickup(num, actor, pklist)) >= 0)
+ num = i;
+ state = US_ACTION;
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ { /* Thor: 可以打數字跳到該人 */
+ int tmp;
+ if ((tmp = search_num(ch, actor - 1)) >= 0)
+ num = tmp;
+ state = US_REDRAW;
+ }
+ break;
+#ifdef REALINFO
+ case 'R': /* 顯示真實姓名 */
+ if (HAS_PERM(PERM_SYSOP))
+ real_name ^= 1;
+ state = US_PICKUP;
+ break;
+#endif
+#ifdef SHOWUID
+ case 'U':
+ if (HAS_PERM(PERM_SYSOP))
+ show_uid ^= 1;
+ state = US_PICKUP;
+ break;
+#endif
+#ifdef SHOWBOARD
+ case 'Y':
+ if (HAS_PERM(PERM_SYSOP))
+ show_board ^= 1;
+ state = US_PICKUP;
+ break;
+#endif
+#ifdef SHOWPID
+ case '#':
+ if (HAS_PERM(PERM_SYSOP))
+ show_pid ^= 1;
+ state = US_PICKUP;
+ break;
+#endif
+
+ case 'b': /* broadcast */
+ if (cuser.uflag & FRIEND_FLAG || HAS_PERM(PERM_SYSOP))
+ {
+ int actor_pos = actor;
+ char ans[4];
+
+ state = US_PICKUP;
+ if (!getdata(0, 0, "廣播訊息:", genbuf, 60, DOECHO))
+ break;
+ if (getdata(0, 0, "確定廣播? [Y]", ans, 4, LCECHO) &&
+ *ans == 'n')
+ break;
+ while (actor_pos)
+ {
+ uentp = pklist[--actor_pos].ui;
+ fri_stat = pklist[actor_pos].friend;
+ if (uentp->pid &&
+ currpid != uentp->pid &&
+ uentp->pid > 0 && kill(uentp->pid, 0) != -1 &&
+ (HAS_PERM(PERM_SYSOP) ||
+ (uentp->pager != 3 &&
+ (uentp->pager != 4 || fri_stat & HFM))))
+ my_write(uentp->pid, genbuf, uentp->userid, HAS_PERM(PERM_SYSOP) ? 3 : 1);
+ }
+ }
+ break;
+ case 'S': /* 顯示好友描述 */
+ show_mode = (++show_mode) % MAX_SHOW_MODE;
+ state = US_PICKUP;
+ break;
+ case 'u': /* 線上修改資料 */
+ case 'K': /* 把壞蛋踢出去 */
+ if (!HAS_PERM(PERM_ACCOUNTS))
+ continue;
+ state = US_ACTION;
+ break;
+ case 'i':
+ state = US_ACTION;
+ break;
+ case Ctrl('S'):
+ state = US_ACTION;
+ break;
+ case 't':
+ case 'w':
+ if (!(cuser.userlevel & PERM_LOGINOK))
+ continue;
+ state = US_ACTION;
+ break;
+ case 'a':
+ case 'd':
+ case 'o':
+ case 'f':
+ case 'g':
+ if (!HAS_PERM(PERM_LOGINOK))
+ /* 註冊才有 Friend */
+ break;
+ if (ch == 'f')
+ {
+ cuser.uflag ^= FRIEND_FLAG;
+ state = US_PICKUP;
+ break;
+ }
+ state = US_ACTION;
+ break;
+ case 'q':
+ case 'c':
+ case 'm':
+ case 'r':
+ case 'l':
+ /* guest 只能 query */
+ if (!cuser.userlevel && ch != 'q' && ch != 'l')
+ break;
+ case 'h':
+ state = US_ACTION;
+ break;
+ case 'p':
+ if (HAS_PERM(PERM_BASIC))
+ {
+ t_pager();
+ state = US_REDRAW;
+ }
+ break;
+ case 'W':
+ {
+ int tmp;
+ char *wm[3] = {"一般", "進階", "未來"};
+ tmp = cuser.uflag2 & WATER_MASK;
+ cuser.uflag2 -= tmp;
+ tmp = (tmp + 1) % 3;
+ cuser.uflag2 |= tmp;
+ prints("切換到 %s 水球模式", wm[tmp]);
+ refresh();
+ sleep(1);
+ state = US_REDRAW;
+ }
+ default: /* refresh screen */
+ state = US_REDRAW;
+ }
+ }
+
+ if (state != US_ACTION)
+ {
+ pid0 = 0;
+ continue;
+ }
+
+ /* Ptt decide cur */
+ uentp = pklist[num].ui;
+ fri_stat = friend_stat(currutmp, uentp);
+ pid0 = uentp->pid;
+ id0 = 256 * uentp->userid[0] + uentp->userid[1];
+
+ if (ch == 'w')
+ {
+ if ((uentp->pid != currpid) &&
+ (HAS_PERM(PERM_SYSOP) ||
+ (uentp->pager != 3 &&
+ (fri_stat & HFM || uentp->pager != 4))))
+ {
+ cursor_show(num + 3 - head, 0);
+ sprintf(genbuf, "Call-In %s :", uentp->userid);
+ my_write(uentp->pid, genbuf, uentp->userid, 0);
+ }
+ }
+ else if (ch == 'l')
+ { /* Thor: 看 Last call in */
+ t_display();
+ }
+ else
+ {
+ switch (ch)
+ {
+ case 'r':
+ m_read();
+ break;
+ case 'g': /* give money */
+ move(b_lines - 2, 0);
+ if (strcmp(uentp->userid, cuser.userid))
+ {
+ sprintf(genbuf, "要給 %s 多少錢呢? ", uentp->userid);
+ outs(genbuf);
+ if (getdata(b_lines - 1, 0, "[銀行轉帳]:", genbuf, 7,
+ LCECHO))
+ {
+ clrtoeol();
+ if ((ch = atoi(genbuf)) <= 0)
+ break;
+ reload_money();
+ if (ch > cuser.money)
+ outs("\033[41m 現金不足~~\033[m");
+ else
+ {
+ deumoney(uentp->uid, ch);
+ sprintf(genbuf, "\033[44m 嗯..還剩下 %d 錢.."
+ "\033[m", demoney(-1*ch));
+ outs(genbuf);
+ sprintf(genbuf, "%s\t給%s\t%d\t%s", cuser.userid,
+ uentp->userid, ch,
+ ctime(&currutmp->lastact));
+ log_file(FN_MONEY, genbuf);
+ mail_redenvelop(cuser.userid, uentp->userid, ch, 'Y');
+ }
+ }
+ else
+ {
+ clrtoeol();
+ outs("\033[41m 交易取消! \033[m");
+ }
+ }
+ else
+ outs("\033[33m 自己給自己? 耍笨..\033[m");
+ refresh();
+ sleep(1);
+ break;
+#ifdef SHOWMIND
+ case 'i':
+ move(3,0);
+ clrtobot();
+ for (i = 1; Mind[i]!=NULL; i++)
+ {
+ move(5+(i-1)/7,((i-1)%7)*10);
+ prints("%2d: %s",i,Mind[i]);
+ }
+ getdata(b_lines - 1, 0, "你現在的心情 0:無 q不變 [q]:",
+ genbuf, 3, LCECHO);
+ if (genbuf[0] && genbuf[0] != 'q')
+ currutmp->mind=atoi(genbuf)%i;
+ state = US_REDRAW;
+ break;
+#endif
+ case 'a':
+ friend_add(uentp->userid, FRIEND_OVERRIDE);
+ friend_load();
+ state = US_PICKUP;
+ break;
+ case 'd':
+ friend_delete(uentp->userid, FRIEND_OVERRIDE);
+ friend_load();
+ state = US_PICKUP;
+ break;
+ case 'o':
+ t_override();
+ state = US_PICKUP;
+ break;
+ case 'K':
+ if (uentp->pid > 0 && kill(uentp->pid, 0) != -1)
+ {
+ move(1, 0);
+ clrtobot();
+ move(2, 0);
+ my_kick(uentp);
+ state = US_PICKUP;
+ }
+ break;
+ case 'm':
+ stand_title("寄 信");
+ prints("[寄信] 收信人:%s", uentp->userid);
+ my_send(uentp->userid);
+ break;
+ case 'q':
+ strcpy(currauthor, uentp->userid);
+ my_query(uentp->userid);
+ break;
+ case 'c':
+ chicken_query(uentp->userid);
+ break;
+ case 'u': /* Thor: 可線上查看及修改使用者 */
+ {
+ int id;
+ userec_t muser;
+
+ strcpy(currauthor, uentp->userid);
+ stand_title("使用者設定");
+ move(1, 0);
+ if ((id = getuser(uentp->userid)))
+ {
+ memcpy(&muser, &xuser, sizeof(muser));
+ user_display(&muser, 1);
+ uinfo_query(&muser, 1, id);
+ }
+ }
+ break;
+
+ case 'h': /* Thor: 看 Help */
+ t_showhelp();
+ break;
+
+ case 't':
+ if (uentp->pid != currpid &&
+ (strcmp(uentp->userid, cuser.userid)))
+ {
+ move(1, 0);
+ clrtobot();
+ move(3, 0);
+ my_talk(uentp, fri_stat);
+ state = US_PICKUP;
+ }
+ break;
+ }
+ }
+ setutmpmode(savemode);
+ }
+}
+
+int t_users() {
+ int destuid0 = currutmp->destuid;
+ int mode0 = currutmp->mode;
+ int stat0 = currstat;
+
+ setutmpmode(LUSERS);
+ pickup_user();
+ currutmp->mode = mode0;
+ currutmp->destuid = destuid0;
+ currstat = stat0;
+ return 0;
+}
+
+int t_pager() {
+ currutmp->pager = (currutmp->pager + 1) % 5;
+ return 0;
+}
+
+int t_idle() {
+ int destuid0 = currutmp->destuid;
+ int mode0 = currutmp->mode;
+ int stat0 = currstat;
+ char genbuf[20];
+ char buf[80], passbuf[PASSLEN];
+
+ setutmpmode(IDLE);
+ getdata(b_lines - 1, 0, "理由:[0]發呆 (1)接電話 (2)覓食 (3)打瞌睡 "
+ "(4)裝死 (5)羅丹 (6)其他 (Q)沒事?", genbuf, 3, DOECHO);
+ if (genbuf[0] == 'q' || genbuf[0] == 'Q')
+ {
+ currutmp->mode = mode0;
+ currstat = stat0;
+ return 0;
+ }
+ else if (genbuf[0] >= '1' && genbuf[0] <= '6')
+ currutmp->destuid = genbuf[0] - '0';
+ else
+ currutmp->destuid = 0;
+
+ if (currutmp->destuid == 6)
+ if (!cuser.userlevel ||
+ !getdata(b_lines - 1, 0, "發呆的理由:", currutmp->chatid, 11,
+ DOECHO))
+ currutmp->destuid = 0;
+ do
+ {
+ move(b_lines - 2, 0);
+ clrtoeol();
+ sprintf(buf, "(鎖定螢幕)發呆原因: %s", (currutmp->destuid != 6) ?
+ IdleTypeTable[currutmp->destuid] : currutmp->chatid);
+ outs(buf);
+ refresh();
+ getdata(b_lines - 1, 0, MSG_PASSWD, passbuf, PASSLEN, NOECHO);
+ passbuf[8] = '\0';
+ }
+ while (!checkpasswd(cuser.passwd, passbuf) &&
+ strcmp(STR_GUEST, cuser.userid));
+
+ currutmp->mode = mode0;
+ currutmp->destuid = destuid0;
+ currstat = stat0;
+
+ return 0;
+}
+
+int t_qchicken() {
+ char uident[STRLEN];
+
+ stand_title("查詢寵物");
+ usercomplete(msg_uid, uident);
+ if (uident[0])
+ chicken_query(uident);
+ return 0;
+}
+
+int t_query() {
+ char uident[STRLEN];
+
+ stand_title("查詢網友");
+ usercomplete(msg_uid, uident);
+ if (uident[0])
+ my_query(uident);
+ return 0;
+}
+
+int t_talk() {
+ char uident[16];
+ int tuid, unum, ucount;
+ userinfo_t *uentp;
+ char genbuf[4];
+/*
+ if (count_ulist() <= 1)
+ {
+ outs("目前線上只有您一人,快邀請朋友來光臨【" BBSNAME "】吧!");
+ return XEASY;
+ }
+*/
+ stand_title("打開話匣子");
+ creat_list();
+ namecomplete(msg_uid, uident);
+ if (uident[0] == '\0')
+ return 0;
+
+ move(3, 0);
+ if (!(tuid = searchuser(uident)) || tuid == usernum)
+ {
+ outs(err_uid);
+ pressanykey();
+ return 0;
+ }
+
+/* multi-login check */
+ unum = 1;
+ while ((ucount = count_logins(tuid, 0)) > 1)
+ {
+ outs("(0) 不想 talk 了...\n");
+ count_logins(tuid, 1);
+ getdata(1, 33, "請選擇一個聊天對象 [0]:", genbuf, 4, DOECHO);
+ unum = atoi(genbuf);
+ if (unum == 0)
+ return 0;
+ move(3, 0);
+ clrtobot();
+ if (unum > 0 && unum <= ucount)
+ break;
+ }
+
+ if ((uentp = (userinfo_t *) search_ulistn(tuid, unum)))
+ my_talk(uentp, friend_stat(currutmp, uentp));
+
+ return 0;
+}
+
+/* 有人來串門子了,回應呼叫器 */
+static userinfo_t *uip;
+void talkreply() {
+ struct hostent *h;
+ char buf[4];
+ struct sockaddr_in sin;
+ char genbuf[200];
+ int a, sig = currutmp->sig;
+
+ talkrequest = NA;
+ uip = &utmpshm->uinfo[currutmp->destuip];
+ sprintf(page_requestor, "%s (%s)", uip->userid, uip->username);
+ currutmp->destuid = uip->uid;
+ currstat = XMODE; /* 避免出現動畫 */
+
+ clear();
+
+ prints("\n\n");
+ prints(" (Y) 讓我們 %s 吧!"
+ " (A) 我現在很忙,請等一會兒再 call 我\n", sig_des[sig]);
+ prints(" (N) 我現在不想 %s"
+ " (B) 對不起,我有事情不能跟你 %s\n",
+ sig_des[sig], sig_des[sig]);
+ prints(" (C) 請不要吵我好嗎?"
+ " (D) 我要離站囉..下次再聊吧.......\n");
+ prints(" (E) 有事嗎?請先來信"
+ " (F) \033[1;33m我自己輸入理由好了...\033[m\n");
+ prints(" (1) %s?先拿100銀兩來"
+ " (2) %s?先拿1000銀兩來..\n\n", sig_des[sig], sig_des[sig]);
+
+ getuser(uip->userid);
+ currutmp->msgs[0].pid = uip->pid;
+ strcpy(currutmp->msgs[0].userid, uip->userid);
+ strcpy(currutmp->msgs[0].last_call_in, "呼叫、呼叫,聽到請回答 (Ctrl-R)");
+ prints("對方來自 [%s],共上站 %d 次,文章 %d 篇\n",
+ uip->from, xuser.numlogins, xuser.numposts);
+ showplans(uip->userid);
+ show_last_call_in(0);
+
+ sprintf(genbuf, "你想跟 %s %s啊?請選擇(Y/N/A/B/C/D/E/F/1/2)[N] ",
+ page_requestor, sig_des[sig]);
+ getdata(0, 0, genbuf, buf, 4, LCECHO);
+
+ if (uip->mode != PAGE)
+ {
+ sprintf(genbuf, "%s已停止呼叫,按Enter繼續...", page_requestor);
+ getdata(0, 0, genbuf, buf, 4, LCECHO);
+ return;
+ }
+ currutmp->msgcount = 0;
+ strcpy(save_page_requestor, page_requestor);
+ memset(page_requestor, 0, sizeof(page_requestor));
+ if (!(h = gethostbyname("localhost")))
+ {
+ perror("gethostbyname");
+ return;
+ }
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = h->h_addrtype;
+ memcpy(&sin.sin_addr, h->h_addr, h->h_length);
+ sin.sin_port = uip->sockaddr;
+ a = socket(sin.sin_family, SOCK_STREAM, 0);
+ if ((connect(a, (struct sockaddr *) &sin, sizeof(sin))))
+ {
+ perror("connect err");
+ return;
+ }
+ if (!buf[0] || !strchr("yabcdef12", buf[0]))
+ buf[0] = 'n';
+ write(a, buf, 1);
+ if (buf[0] == 'f' || buf[0] == 'F')
+ {
+ if (!getdata(b_lines, 0, "不能的原因:", genbuf, 60, DOECHO))
+ strcpy(genbuf, "不告訴你咧 !! ^o^");
+ write(a, genbuf, 60);
+ }
+ uip->destuip = currutmp - &utmpshm->uinfo[0];
+ if (buf[0] == 'y')
+ switch (sig)
+ {
+ case SIG_DARK:
+ main_dark(a, uip);
+ break;
+ case SIG_PK:
+ chickenpk(a);
+ break;
+ case SIG_GOMO:
+ gomoku(a);
+ break;
+ case SIG_CHC:
+ chc(a);
+ break;
+ case SIG_TALK:
+ default:
+ do_talk(a);
+ }
+ else
+ close(a);
+ clear();
+}
+
+/* 網友動態簡表 */
+/* not used
+static int shortulist(userinfo_t * uentp) {
+ static int lineno, fullactive, linecnt;
+ static int moreactive, page, num;
+ char uentry[50];
+ int state;
+
+ if (!lineno)
+ {
+ lineno = 3;
+ page = moreactive ? (page + p_lines * 3) : 0;
+ linecnt = num = moreactive = 0;
+ move(1, 70);
+ prints("Page: %d", page / (p_lines) / 3 + 1);
+ move(lineno, 0);
+ }
+
+ if (uentp == NULL)
+ {
+ int finaltally;
+
+ clrtoeol();
+ move(++lineno, 0);
+ clrtobot();
+ finaltally = fullactive;
+ lineno = fullactive = 0;
+ return finaltally;
+ }
+ if ((!HAS_PERM(PERM_SYSOP) &&
+ !HAS_PERM(PERM_SEECLOAK) &&
+ uentp->invisible) ||
+ ((friend_stat(currutmp, uentp) & HRM) &&
+ !HAS_PERM(PERM_SYSOP)))
+ {
+ if (lineno >= b_lines)
+ return 0;
+ if (num++ < page)
+ return 0;
+ memset(uentry, ' ', 25);
+ uentry[25] = '\0';
+ }
+ else
+ {
+ fullactive++;
+ if (lineno >= b_lines)
+ {
+ moreactive = 1;
+ return 0;
+ }
+ if (num++ < page)
+ return 0;
+
+ state = (currutmp == uentp) ? 10 :
+ (friend_stat(currutmp,uentp)&ST_FRIEND)>>2;
+
+ if (PERM_HIDE(uentp))
+ state = 9;
+
+ sprintf(uentry, "%s%-13s%c%-10s%s ", fcolor[state],
+ uentp->userid, uentp->invisible ? '#' : ' ',
+ modestring(uentp, 1), state ? "\033[0m" : "");
+ }
+ if (++linecnt < 3)
+ {
+ strcat(uentry, "│");
+ outs(uentry);
+ }
+ else
+ {
+ outs(uentry);
+ linecnt = 0;
+ clrtoeol();
+ move(++lineno, 0);
+ }
+ return 0;
+}
+*/