精華區beta SetupBBS 關於我們 聯絡資訊
/*-------------------------------------------------------*/ /* talk.c ( NTHU CS MapleBBS Ver 2.36 ) */ /*-------------------------------------------------------*/ /* target : talk/quety/friend routines */ /* create : 95/03/29 */ /* update : 95/12/15 */ /*-------------------------------------------------------*/ #define _MODES_C_ #include "bbs.h" #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <sys/ipc.h> #include <sys/shm.h> #ifdef lint #include <sys/uio.h> #endif #define M_INT 15 /* monitor mode update interval */ #define P_INT 20 /* interval to check for page req. in * talk/chat */ #define IRH 1 #define HRM 2 struct talk_win { int curcol, curln; int sline, eline; }; typedef struct { user_info *ui; linkuser_info *lui; time_t idle; usint friend; } pickup; extern int bind( /* int,struct sockaddr *, int */ ); extern bad_user(char* name); extern char* getuserid(); extern struct UTMPFILE *utmpshm; extern char watermode,no_oldmsg,oldmsg_count; extern msgque oldmsg[MAX_REVIEW]; extern char *friend_file[8]; /* Ptt 各種特別名單的補述 extern char *friend_desc[8] ;*/ /* Ptt 各種特別名單的中文敘述 static char *friend_list[8] = {"好友名單", "壞人名單","上線通知","新文章通知","其它特別名單", */ /* -------------------------- */ /* 記錄 friend 的 user number */ /* -------------------------- */ #define PICKUP_WAYS 5 int pickup_way = 0; int friendcount; int friends_number; int override_number; int rejected_number; char *fcolor[7] = {"", "", "", "", "", "", ""}; char *talk_uent_buf; char save_page_requestor[40]; char page_requestor[40]; static FILE* flog; void friend_load(); int is_rejected(user_info *ui); char * modestring(uentp, simple) user_info *uentp; int simple; { static char modestr[40]; static char *notonline="不在站上"; register int mode = uentp->mode; register char *word; word = ModeTypeTable[mode]; if (!(HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_SEECLOAK)) && (uentp->invisible || (is_rejected(uentp) & HRM))) return (notonline); /* woju */ 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, "不行了 @_@", uentp->msgcount); 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 (is_hidden(getuserid(uentp->destuid))) /* Leeym 對方(紫色)隱形 */ sprintf(modestr, "%s", "交談 空氣");/* Leeym 大家自己發揮吧! */ else sprintf(modestr, "%s %s", word, getuserid(uentp->destuid)); } else if (mode != PAGE && mode != QUERY) return (word); else sprintf(modestr, "%s %s", word, getuserid(uentp->destuid)); return (modestr); } int cmpuids(uid, urec) int uid; user_info *urec; { return (uid == urec->uid); } int /* Leeym 從 FireBird 移植改寫過來的 */ is_hidden(user) char *user; { int tuid; user_info *uentp; if ((!(tuid = getuser(user))) || (!(uentp = (user_info *) search_ulist(cmpuids, tuid))) || ((!uentp->invisible|| HAS_PERM(PERM_SYSOP)||HAS_PERM(PERM_SEECLOAK)) && (((!PERM_HIDE(uentp) && !PERM_HIDE(currutmp)) || PERM_HIDE(currutmp)) && !(is_rejected(uentp) & HRM && !(is_friend(uentp) & 2))))) return 0; /* 交談 xxx */ else return 1; /* 自言自語 */ } /* woju */ int cmppids(pid, urec) pid_t pid; user_info *urec; { return (pid == urec->pid); } static int cmpunums(unum, up) int unum; user_info *up; { if (up->pid) return (unum == up->destuid); return 0; } /* ------------------------------------- */ /* routines for Talk->Friend */ /* ------------------------------------- */ static int can_override(userid, whoasks) char *userid; char *whoasks; { char buf[STRLEN]; sethomefile(buf, userid, fn_overrides); return belong(buf, whoasks); } int is_friend(ui) user_info *ui; { register ushort unum, hit, *myfriends; /* 判斷對方是否為我的朋友 ? */ unum = ui->uid; myfriends = currutmp->friend; while (hit = *myfriends++) { if (unum == hit) { hit = 1; friends_number++; break; } } /* 判斷我是否為對方的朋友 ? */ myfriends = ui->friend; while (unum = *myfriends++) { if (unum == usernum) { override_number++; hit |= 2; break; } } return hit; } static int be_rejected(userid) char *userid; { char buf[STRLEN]; sethomefile(buf, userid, fn_reject); return belong(buf, cuser.userid); } /* 被拒絕 */ int is_rejected(ui) user_info *ui; { register ushort unum, hit, *myrejects; if (PERM_HIDE(ui)) return 0; /* 判斷對方是否為我的仇人 ? */ unum = ui->uid; myrejects = currutmp->reject; while (hit = *myrejects++) { if (unum == hit) { hit = 1; rejected_number++; break; } } /* 判斷我是否為對方的仇人 ? */ myrejects = ui->reject; while (unum = *myrejects++) { if (unum == usernum) { if (hit & IRH) --rejected_number; hit |= 2; break; } } return hit; } /* ------------------------------------- */ /* 真實動作 */ /* ------------------------------------- */ static void my_kick(uentp) user_info *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 ((kill(uentp->pid, SIGHUP) == -1) && (errno == ESRCH)) memset(uentp, 0, sizeof(user_info)); /* purge_utmp(uentp); */ outs("踢出去囉"); } else outs(msg_cancel); pressanykey(); } my_query(uident) char *uident; { extern char currmaildir[]; char fpath[80]; int tuid,i; unsigned long int j; user_info *uentp; char *money[10] = {"債台高築","赤貧","清寒","普通","小康", "小富","中富","大富翁","富可敵國","比爾蓋\天"}; if (tuid = getuser(uident)) { move(1, 0); clrtobot(); move(2, 0); setutmpmode(QUERY); currutmp->destuid = tuid; j = xuser.money; for(i=0;i<10 && j>10;i++) j /= 10; prints("%s(%s) 共上站 %d 次,發表過 %d 篇文章\n", xuser.userid, xuser.username, xuser.numlogins, xuser.numposts); prints("最近(%s)從[%s]上站", Cdate(&xuser.lastlogin), (xuser.lasthost[0] ? xuser.lasthost : "(不詳)")); /* Query 時可同時看其友誼描述或惡行 */ friend_query(uident, FRIEND_OVERRIDE); friend_query(uident, FRIEND_REJECT); #if defined(REALINFO) && defined(QUERY_REALNAMES) if (HAS_PERM(PERM_SYSOP)) prints("真實姓名: %s\n", xuser.realname); #endif #if 0 prints("電子郵件信箱地址: %s \n", xuser.email); #endif uentp = (user_info *) search_ulist(cmpuids, tuid); if (uentp && !PERM_HIDE(currutmp) && PERM_HIDE(uentp)) prints("\n[目前動態:%s] ", "不在站上"); else prints("\n[目前動態:%s] ", uentp ? modestring(uentp, 0) : "不在站上"); sethomedir(currmaildir, xuser.userid); outs(chkmail(1) ? "有新進信件還沒看" : "所有信件都看過了"); sethomedir(currmaildir, cuser.userid); chkmail(1); if (can_override(xuser.userid, cuser.userid) || HAS_PERM(PERM_SYSOP) || !strcmp(xuser.userid, cuser.userid) ) { char *sex[8] = { MSG_BIG_BOY, MSG_BIG_GIRL, MSG_LITTLE_BOY, MSG_LITTLE_GIRL, MSG_MAN, MSG_WOMAN, MSG_PLANT, MSG_MIME }; prints(",性別:%s\n身上有 %ld 銀兩,",sex[xuser.sex%8],xuser.money); } else outs("\n"); prints("經濟狀況 %s",money[i]); if (HAS_PERM(PERM_SYSOP) || !strcmp(xuser.userid, cuser.userid)) prints(",真實姓名: %s", xuser.realname); prints("\n"); showplans(uident); pressanykey(); return FULLUPDATE; } return DONOTHING; /* currutmp->destuid = 0; */ } int my_write(pid, hint) pid_t pid; char *hint; { int len; char msg[80]; /*struct stat st; */ FILE *fp; struct tm *ptime; time_t now; char genbuf[200]; user_info *uin ; extern msgque oldmsg[MAX_REVIEW]; int a ; /* woju */ uschar mode0 = currutmp->mode; char c0 = currutmp->chatid[0]; int currstat0 = currstat; if(watermode) { a = (no_oldmsg - watermode + MAX_REVIEW )%MAX_REVIEW; uin = (user_info*)search_ulist(cmppids, oldmsg[a].last_pid); watermode = 0; } else { uin = (user_info*)search_ulist(cmppids, pid); } if (( !oldmsg_count || !isprint2(*hint)) && !uin ) { outmsg("糟糕! 對方已落跑了(不在站上)! ~>_<~"); clrtoeol(); refresh(); sleep(1); return 0; } currutmp->mode = 0; currutmp->chatid[0] = 3; currstat = XMODE; time(&now); ptime = localtime(&now); if (isprint2(*hint)) { char inputbuf[4]; if (!(len = getdata(0, 0, hint, msg, 65, DOECHO))) { outmsg("算了! 放你一馬..."); clrtoeol(); refresh(); sleep(1); currutmp->chatid[0] = c0; currutmp->mode = mode0; currstat = currstat0; watermode = 0; return 0; } /* Ptt */ if(watermode) { a = (no_oldmsg - watermode + MAX_REVIEW )%MAX_REVIEW; uin = (user_info*)search_ulist(cmppids, oldmsg[a].last_pid); watermode = 0; } strip_ansi(msg,msg,0); if (!uin || !*uin->userid /* watermode ? strcmp(uin->userid, oldmsg[a].last_userid) : strcmp(uin->userid, currutmp->msgs[0].last_userid) */ ) { outmsg("糟糕! 對方已落跑了(不在站上)! ~>_<~"); clrtoeol(); refresh(); if (*hint) sleep(1); currutmp->chatid[0] = c0; currutmp->mode = mode0; currstat = currstat0; return 0; } sprintf(genbuf, "丟%s水球:%.40s....?[Y] ", uin->userid, msg); getdata(0, 0, genbuf, inputbuf, 3, LCECHO); genbuf[0] = '\0'; if (inputbuf[0] == 'n') { currutmp->chatid[0] = c0; currutmp->mode = mode0; currstat = currstat0; return 0; } if (!uin || !*uin->userid) { outmsg("糟糕! 對方已落跑了(不在站上)! ~>_<~"); clrtoeol(); refresh(); if (isprint2(*hint)) sleep(1); currutmp->chatid[0] = c0; currutmp->mode = mode0; currstat = currstat0; return 0; } } else { strcpy(msg, hint + 1); strip_ansi(msg,msg,0); len = strlen(msg); } now = time(0); if (*hint != 1) { sethomefile(genbuf, uin->userid, fn_writelog); if (fp = fopen(genbuf, "a")) { fprintf(fp, "★ %s %s %s [%s]\n", cuser.userid, (*hint == 2) ? "廣播" : "", msg, Cdatelite(&now)); fclose(fp); } sethomefile(genbuf, cuser.userid, fn_writelog); if (fp = fopen(genbuf, "a")) { fprintf(fp, "To %s: %s [%s]\n", uin->userid, msg, Cdatelite(&now)); fclose(fp); } } if (*hint == 2 && uin->msgcount) { uin->destuip = currutmp; uin->sig = 2; kill(uin->pid, SIGUSR1); } else if (*hint != 1 && !HAS_PERM(PERM_SYSOP) && ( uin->pager == 3 || uin->pager == 2 || (uin->pager == 4 && !(is_friend(uin) & 2)) )) outmsg("糟糕! 對方防水了! ~>_<~"); else { if (uin->msgcount < MAXMSGS) { uin->msgs[uin->msgcount].last_pid = currpid; strcpy(uin->msgs[uin->msgcount].last_userid, cuser.userid); strcpy(uin->msgs[uin->msgcount++].last_call_in, msg); } else if (*hint != 1) outmsg("糟糕! 對方不行了! (收到太多水球) @_@"); if (uin->msgcount == 1 && kill(uin->pid, SIGUSR2) == -1 && *hint != 1) outmsg("糟糕! 沒打中! ~>_<~"); else if (uin->msgcount == 1 && *hint != 1) outmsg("水球砸過去了! *^o^Y"); else if (uin->msgcount > 1 && uin->msgcount < MAXMSGS && *hint != 1) outmsg("再補上一粒! *^o^Y"); } clrtoeol(); refresh(); if (isprint2(*hint)) sleep(1); currutmp->chatid[0] = c0; currutmp->mode = mode0; currstat = currstat0; return 1; } static char t_display_new_flag =0; void t_display_new() { int i; char buf[100]; if(t_display_new_flag) return; else t_display_new_flag = 1; if(oldmsg_count && watermode) { move(1,0); outs( "───────水─球─回─顧─────────────用[TAB]鍵切換──────"); for(i=0 ; i < oldmsg_count ;i++) { int a = (no_oldmsg - i - 1 + MAX_REVIEW )%MAX_REVIEW; move(i+2,0); clrtoeol(); if(watermode-1 != i) sprintf(buf," %s %s ", oldmsg[a].last_userid,oldmsg[a].last_call_in); else sprintf(buf,">%s %s ", oldmsg[a].last_userid,oldmsg[a].last_call_in); outs(buf); } move(i+2,0); outs( "────────────────────────────────────────"); } t_display_new_flag =0; } /* Thor: for ask last call-in message */ int t_display() { char genbuf[200],ans[4]; 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 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, "熱線記錄"); sethomedir(title, cuser.userid); append_record(title, &mymail, sizeof(mymail)); Rename(genbuf, buf); } else if (*ans == 'c') { unlink(genbuf); } return FULLUPDATE; } return DONOTHING; } /* ----------------------------------------------------- */ static int dotalkuent(uentp) user_info *uentp; { char buf[STRLEN]; char mch; if (HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_SEECLOAK) || !uentp->invisible) { switch (uentp->mode) { case CLASS: mch = 'S'; break; case TALK: mch = 'T'; break; case CHATING: mch = 'C'; break; case READNEW: case READING: mch = 'R'; break; case POSTING: mch = 'P'; break; case SMAIL: case RMAIL: case MAIL: mch = 'M'; break; case EDITING: mch = 'E'; break; default: mch = '-'; } sprintf(buf, "%s%s(%c), ", uentp->invisible ? "*" : "", uentp->userid, mch); strcpy(talk_uent_buf, buf); talk_uent_buf += strlen(buf); } return 0; } static void do_talk_nextline(twin) struct talk_win *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(twin, ch) struct talk_win *twin; int ch; { extern int dumb_term; extern screenline* big_picture; screenline* line; int i; char ch0; char 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 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; if (dumb_term) outc('\n'); 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) ? "" : "", (twin->eline == b_lines - 1) ? getuserid(currutmp->destuid) : cuser.userid, buf, (ch == Ctrl('P')) ? "(Up)" : ""); } static void do_talk_string(twin, str) struct talk_win *twin; char *str; { while (*str) { do_talk_char(twin, *str++); } } static void dotalkuserlist(twin) struct talk_win *twin; { char bigbuf[MAXACTIVE * 20]; int savecolumns; do_talk_string(twin, "*** 上線網友 ***\n"); savecolumns = (t_columns > STRLEN ? t_columns : 0); talk_uent_buf = bigbuf; if (apply_ulist(dotalkuent) == -1) { strcpy(bigbuf, "沒有任何使用者上線\n"); } strcpy(talk_uent_buf, "\n"); do_talk_string(twin, bigbuf); if (savecolumns) t_columns = savecolumns; } char *talk_help = "== On-line Help! ==\n" " ^O 此線上說明畫面 " " ^W 哇哇哇地哭 :~(\n" " ^U 列出線上使用者 " " ^Y YA~! Y^o^Y\n" " ^P 切換Pager " " ^A 哈哈哈哈... :D\n" " ^G 嗶!(睡著了嗎?) " " ^K 佛山無影腳~~~!\n" " ^C/^D 掰掰了... " " ^Z zzzzz.........\n"; char *talk_wawa = "嗚哇哇哇哇啊啊啊啊啊~~~!!!\n ~~~>_<~~~\n"; char *talk_yaya = "YAYAYA~~~!!!\n Y*^o^*Y\n"; char *talk_haha = "哇哈哈哈哈哈......!!!\n :DDD\n"; char *talk_kick = "看我佛山無影腳~~~!!!\n >:D\n"; char *talk_zzz = "-_- . . z Z Z\n"; static do_talk(fd) int fd; { struct talk_win mywin, itswin; char mid_line[128], data[200], ans[4]; int i, ch, datac; int im_leaving = 0; FILE *log; struct tm *ptime; time_t now; FILE* fp; char genbuf[200], fpath[100]; int phone_mode = 0; char* pstr; extern char* phone_char(); time(&now); ptime = localtime(&now); sethomepath(fpath, cuser.userid); strcpy(fpath, tempnam(fpath, "talk_")); flog = fopen(fpath, "w"); setuserfile(genbuf, fn_talklog); /* Kaede */ if (!is_watched(cuser.userid)) log = NULL; else if (log = fopen(genbuf, "a+")) 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, " 談天說地 %s%s】 與 %s%s", 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; } if (ch == KEY_LEFT) ch = Ctrl('B'); else if (ch == KEY_RIGHT) ch = Ctrl('F'); else if (ch == KEY_UP) ch = Ctrl('P'); else if (ch == KEY_DOWN) ch = Ctrl('N'); if (phone_mode && (pstr = phone_char(ch)) || isprint2(ch) || ch == Ctrl('H') || ch == '\177' || ch == Ctrl('G') || ch == Ctrl('M') || ch == Ctrl('J') || ch == Ctrl('F') || ch == Ctrl('B') || ch == Ctrl('D') || ch == Ctrl('A') || ch == Ctrl('E') || ch == Ctrl('K') || ch == Ctrl('Y') || ch == Ctrl('P') || ch == Ctrl('N')) { if (phone_mode && pstr) data[0] = (char)pstr[0]; else 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 (phone_mode && pstr) { data[0] = (char) pstr[1]; if (send(fd, data, 1, 0) != 1) break; if (log) fprintf(log, "%c", (ch == Ctrl('M'))? '\n' : (char) *data); do_talk_char(&mywin, *data); } } else if (ch == KEY_ESC) switch (KEY_ESC_arg) { case 'p': phone_mode ^= 1; break; case 'a': send(fd, talk_haha, strlen(talk_haha), 0); do_talk_string(&mywin, talk_haha); break; case 'k': send(fd, talk_kick, strlen(talk_kick), 0); do_talk_string(&mywin, talk_kick); break; case 'w': send(fd, talk_wawa, strlen(talk_wawa), 0); do_talk_string(&mywin, talk_wawa); break; case 'y': send(fd, talk_yaya, strlen(talk_yaya), 0); do_talk_string(&mywin, talk_yaya); break; case 'z': send(fd, talk_zzz, strlen(talk_zzz), 0); do_talk_string(&mywin, talk_zzz); break; case 'c': capture_screen(); break; case 'n': { extern screenline* big_picture; screenline* screen0 = calloc(t_lines, sizeof(screenline)); int y, x; memcpy(screen0, big_picture, t_lines * sizeof(screenline)); add_io(0, 0); getyx(&y, &x); edit_note(); move(y, x); memcpy(big_picture, screen0, t_lines * sizeof(screenline)); free(screen0); redoscr(); add_io(fd, 0); } break; } else if (ch == Ctrl('U')) { extern screenline* big_picture; screenline* screen0 = calloc(t_lines, sizeof(screenline)); int y, x; memcpy(screen0, big_picture, t_lines * sizeof(screenline)); add_io(0, 0); getyx(&y, &x); t_users(); move(y, x); memcpy(big_picture, screen0, t_lines * sizeof(screenline)); free(screen0); redoscr(); add_io(fd, 0); } else if (ch == Ctrl('I')) { extern screenline* big_picture; screenline* screen0 = calloc(t_lines, sizeof(screenline)); int y, x; memcpy(screen0, big_picture, t_lines * sizeof(screenline)); add_io(0, 0); getyx(&y, &x); t_idle(); move(y, x); memcpy(big_picture, screen0, t_lines * sizeof(screenline)); free(screen0); redoscr(); add_io(fd, 0); } else if (ch == Ctrl('R') && currutmp->msgs[0].last_pid) { extern screenline* big_picture; screenline* screen0 = calloc(t_lines, sizeof(screenline)); int y, x; memcpy(screen0, big_picture, t_lines * sizeof(screenline)); add_io(0, 0); getyx(&y, &x); show_last_call_in(); my_write(currutmp->msgs[0].last_pid, "水球丟回去:"); move(y, x); memcpy(big_picture, screen0, t_lines * sizeof(screenline)); free(screen0); redoscr(); add_io(fd, 0); } } } if (log) fclose(log); add_io(0, 0); close(fd); if (flog) { char ans[4]; extern screenline *big_picture; extern uschar scr_lns; int i; time(&now); fprintf(flog, "\n離別畫面 [%s] ... \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 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, "對話記錄 (%s)", getuserid(currutmp->destuid)); sethomedir(title, cuser.userid); append_record(title, &mymail, sizeof(mymail)); Rename(fpath, genbuf); } else unlink(fpath); flog = 0; } setutmpmode(XINFO); } static void my_talk(uin) user_info *uin; { int sock, msgsock, length, ch; struct sockaddr_in server; pid_t pid; char c; char genbuf[4]; uschar mode0 = currutmp->mode; ch = uin->mode; strcpy(currauthor, uin->userid); if (ch == EDITING || ch == TALK || ch == CHATING || ch == PAGE || ch == MAILALL || ch == MONITOR || !ch && (uin->chatid[0] == 1 || uin->chatid[0] == 3)) { outs("人家在忙啦"); } else if (!HAS_PERM(PERM_SYSOP) && (be_rejected(uin->userid) || (!uin->pager && !can_override(uin->userid, cuser.userid)))) { outs("對方關掉呼叫器了"); } else if (!HAS_PERM(PERM_SYSOP) && be_rejected(uin->userid) || uin->pager == 2) { outs("對方拔掉呼叫器了"); } else if (!HAS_PERM(PERM_SYSOP) && !(is_friend(uin) & 2) && 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, "確定要和他/她談天嗎(Y/N)?[N] ", genbuf, 4, LCECHO); if (*genbuf != 'y') return; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("sock err"); 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"); return; } length = sizeof server; if (getsockname(sock, (struct sockaddr *) & server, &length) < 0) { close(sock); perror("sock name err"); return; } currutmp->sockactive = YEA; currutmp->sockaddr = server.sin_port; currutmp->destuid = uin->uid; setutmpmode(PAGE); uin->destuip = currutmp; 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) { bell(); outmsg("對方回應中..."); refresh(); } else if (ch == EDITING || ch == TALK || ch == CHATING || ch == PAGE || ch == MAILALL || ch == MONITOR || !ch && (uin->chatid[0] == 1 || uin->chatid[0] == 3)) { add_io(0, 0); close(sock); currutmp->sockactive = currutmp->destuid = 0; outmsg("人家在忙啦"); pressanykey(); return; } else { #ifdef LINUX add_io(sock, 20); /* added 4 linux... achen */ #endif move(0, 0); outs("再"); bell(); uin->destuip = currutmp; if (kill(pid, SIGUSR1) == -1) { #ifdef LINUX add_io(sock, 20); /* added 4 linux... achen */ #endif outmsg(msg_usr_left); refresh(); sleep(1); pressanykey(); return; } continue; } } if (ch == I_OTHERDATA) break; if (ch == '\004') { add_io(0, 0); close(sock); currutmp->sockactive = currutmp->destuid = 0; return; } } msgsock = accept(sock, (struct sockaddr *) 0, (int *) 0); if (msgsock == -1) { perror("accept"); return; } add_io(0, 0); close(sock); currutmp->sockactive = NA; /* currutmp->destuid = 0 ; */ read(msgsock, &c, sizeof c); if (c == 'y') { sprintf(save_page_requestor, "%s (%s)", uin->userid, uin->username); do_talk(msgsock); } else { move(9, 9); outs("【回音】 "); switch (c) { case 'a': outs("我現在很忙,請等一會兒再 call 我,好嗎?"); break; case 'b': outs("對不起,我有事情不能跟你 talk...."); break; case 'd': outs("我要離站囉..下次再聊吧.........."); break; case 'c': outs("請不要吵我好嗎?"); break; case 'e': outs("找我有事嗎?請先來信唷...."); break; case 'f': { char msgbuf[60]; read(msgsock, msgbuf, 60); outs("對不起,我現在不能跟你 talk,因為\n"); move(10,18); outs(msgbuf); } break; default: outs("我現在不想 talk 啦.....:)"); } close(msgsock); } } currutmp->mode = mode0; currutmp->destuid = 0; pressanykey(); } /* ------------------------------------- */ /* 選單式聊天介面 */ /* ------------------------------------- */ #define US_PICKUP 1234 #define US_RESORT 1233 #define US_ACTION 1232 #define US_REDRAW 1231 static void t_showhelp() { clear(); outs("【 休閒聊天使用說明 】\n\n\ (←)(e) 結束離開 (h) 看使用說明\n\ (↑)/(↓)(n) 上下移動 (TAB) 切換排序方式\n\ (PgUp)(^B) 上頁選單 ( )(PgDn)(^F) 下頁選單\n\ (Hm)/($)(Ed) 首/尾 (s) 來源/好友描述 切換\n\ (m) 寄信 (q)(/) 查詢網友/找尋網友\n\ (r) 閱\讀信件 (l) 看上次熱訊\n\ (f) 全部/好友列表 (數字) 跳至該使用者\n\ (p/N) 即時切換呼叫器/更改暱稱\n\ (a/d/o) 好友名單之增加/刪除/修改"); if (HAS_PERM(PERM_PAGE)) { outs("\n\n【 交談專用鍵 】\n\n\ (→)(t)(Enter) 跟他/她聊天\n\ (w) 熱線 Call in\n\ (b) 對好友廣播 (一定要在好友列表中)\n\ (^R) 即時回應 (有人 Call in 你時)"); } if (HAS_PERM(PERM_SYSOP)) { outs("\n\n【 站長專用鍵 】\n\n"); if (HAS_PERM(PERM_SYSOP)) outs("(u)/(H) 設定使用者資料/切換隱形模式\n"); outs("(R)/(K) 查詢使用者的真實姓名/把壞蛋踢出去\n"); } pressanykey(); } static int search_pickup(num, actor, pklist) int num; int actor; pickup pklist[]; { char genbuf[IDLEN + 2]; getdata(b_lines - 1, 0, "請輸入使用者姓名:", genbuf, IDLEN + 1, DOECHO); move(b_lines - 1, 0); clrtoeol(); if (genbuf[0]) { int n = (num + 1) % actor; str_lower(genbuf, genbuf); while (n != num) { if (strstr_lower(pklist[n].ui->userid, genbuf)) return n; if (++n >= actor) n = 0; } } return -1; } static int pickup_cmp(i, j) pickup *i, *j; { switch (pickup_way) { case 0: { register int friend; if (friend = j->friend - i->friend) return friend; } case 1: return strcasecmp(i->ui->userid, j->ui->userid); case 2: return (i->ui->mode - j->ui->mode); case 3: return (i->idle - j->idle); case 4: return strcasecmp(i->ui->from, j->ui->from); case 5: return strcasecmp(i->lui->userid, j->lui->userid); } } static char * /* Kaede show friend description */ friend_descript(uident) 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 void pickup_user() { static int real_name = 0; static int show_friend = 0; static int show_uid = 0; static int show_tty = 0; static int show_pid = 0; static int num = 0; char genbuf[200]; #ifdef WHERE extern struct FROMCACHE *fcache; #endif register user_info *uentp; register linkuser_info *luentp; register pid_t pid0=0; /* Ptt 定位 */ register int id0; /* US_PICKUP時的游標用 */ register int state = US_PICKUP, hate, ch; register int actor, head, foot; int badman; int savemode = currstat; time_t diff, freshtime; pickup pklist[USHM_SIZE]; /* parameter Ptt註 */ /* num : 現在的游標位 */ struct stat ttystat; /* foot: 此頁的腳腳 */ char buf[20]; /* actor:共有多少user */ char pagerchar[4] = "* o "; char *msg_pickup_way[PICKUP_WAYS] = { "嗨!朋友", "網友代號", "網友動態", "發呆時間", "來自何方", "PTT聯盟" }; extern struct LINKUSER *luser; /* Ptt 週年慶 -> broadcast to get time */ time_t bc_time; struct tm *bc_tm; resolve_luser(); #ifdef WHERE resolve_fcache(); #endif while (1) { if (state == US_PICKUP) { freshtime = 0; } if(pickup_way == 5 && luser->uptime < luser->touchtime) pickup_way = 0; if (pickup_way !=5 && utmpshm->uptime > freshtime) { time(&freshtime); friends_number = override_number = rejected_number = actor = ch = 0; while (ch < USHM_SIZE) { uentp = &(utmpshm->uinfo[ch++]); if (uentp->pid) { if (((is_rejected(uentp) & HRM) && !HAS_PERM(PERM_SYSOP)) || (uentp->invisible && !(HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_SEECLOAK)))) continue; /* Thor: can't see anyone who rejects you. */ if (uentp->userid[0] == 0) continue; /* Ptt's bug */ if (!PERM_HIDE(currutmp) && PERM_HIDE(uentp)) continue; head = is_friend(uentp) ; if ( (cuser.uflag & FRIEND_FLAG) && (!head || is_rejected(uentp)) ) continue; #ifdef SHOW_IDLE_TIME strcpy(buf, uentp->tty); if (stat(buf, &ttystat)) { diff = 0; } else { diff = freshtime - ttystat.st_atime; #ifdef DOTIMEOUT /* prevent fault /dev mount from kicking out users */ if ((diff > IDLE_TIMEOUT) && (diff < 60 * 60 * 24 * 5)) { if ((kill(uentp->pid, SIGHUP) == -1) && (errno == ESRCH)) memset(uentp, 0, sizeof(user_info)); continue; } #endif } pklist[actor].idle = diff; #endif pklist[actor].friend = head; pklist[actor].ui = uentp; actor++; } } badman = rejected_number; state = US_PICKUP; if (!actor) { getdata(b_lines - 1, 0, "你的朋友還沒上站,要看看一般網友嗎(Y/N)?[Y]", genbuf, 4, LCECHO); if (genbuf[0] != 'n') { cuser.uflag &= ~FRIEND_FLAG; continue; } return; } } else if( pickup_way==5 ) /* Ptt */ { time(&freshtime); friends_number = override_number = rejected_number = actor = ch = 0; for (ch = 0;ch < luser->number;ch++) { luentp = &(luser->uinfo[ch]); if(1) /* 以後可以加條件哪類的user不顯示 */ { pklist[actor].lui = luentp; actor++; } } state = US_RESORT; } if (state >= US_RESORT) { qsort(pklist, actor, sizeof(pickup), pickup_cmp); } if (state >= US_ACTION) { showtitle((cuser.uflag & FRIEND_FLAG)? "好友列表": "休閒聊天", BoardName); prints(" 排序方式:[%s] 上站人數:%-6d我的朋友:%-4d與我為友:%-4d壞人:%-3d\n" " %s P%c代號 %-17s%-17s%-13s%-10s\n", msg_pickup_way[pickup_way], actor, friends_number, override_number, badman, #ifdef SHOWUID show_uid ? "UID" : #endif "No.", (HAS_PERM(PERM_SEECLOAK) || HAS_PERM(PERM_SYSOP)) ? 'C' : ' ', #ifdef REALINFO real_name ? "姓名" : #endif "暱稱", show_friend ? "好友描述" : "故鄉", #ifdef SHOWTTY show_tty ? "TTY " : #endif "動態", #ifdef SHOWPID show_pid ? " PID" : #endif #ifdef SHOW_IDLE_TIME "備註 發呆" #else "備註" #endif ); } else { move(3, 0); clrtobot(); } if(pid0) for (ch = 0; ch < actor; ch++) { if(pickup_way != 5 && pid0 == (pklist[ch].ui)->pid && id0 == 256 * pklist[ch].ui->userid[0] + pklist[ch].ui->userid[1]) { num = ch; } if(pickup_way == 5 && pid0 == (pklist[ch].lui)->pid && id0 == 256 * pklist[ch].lui->userid[0] + pklist[ch].lui->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; if (pickup_way != 5) { for (ch = head; ch < foot; ch++) { uentp = pklist[ch].ui; if (!uentp->pid) { state = US_PICKUP; break; } #ifdef SHOW_IDLE_TIME diff = pklist[ch].idle; if (diff > 0) sprintf(buf, "%3d'%02d", diff / 60, diff % 60); else buf[0] = '\0'; #else buf[0] = '\0'; #endif #ifdef SHOWPID if (show_pid) sprintf(buf, "%6d", uentp->pid); #endif state = (currutmp == uentp) ? 6 : pklist[ch].friend; if (PERM_HIDE(uentp)) state = PERM_HIDE(currutmp) ? 5 : 0; if (PERM_HIDE(currutmp) && state == 3) state = 6; hate = is_rejected(uentp); diff = uentp->pager & !(hate & HRM); prints("%5d %c%c%s%-13s%-17.16s%s%-17.16s%-13.13s%-4s%s\n", #ifdef SHOWUID show_uid ? uentp->uid : #endif (ch + 1), (hate & HRM)? 'X' : (uentp->pager == 4) ? 'f' : (uentp->pager == 3) ? 'W' : (uentp->pager == 2) ? '-' : pagerchar[(state & 2) | diff], (uentp->invisible ? ')' : ' '), (hate & IRH)? fcolor[4] : fcolor[state], uentp->userid, #ifdef REALINFO real_name ? uentp->realname : #endif uentp->username, /*state*/ 1 ? "" : "", show_friend ? friend_descript(uentp->userid) : ( (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 : "*" ), #ifdef SHOWTTY show_tty ? uentp->tty : #endif modestring(uentp, 0), uentp->birth ? "壽星" :"" , buf); } } else /* pickup_way == 5 跨站 mode */ { for (ch = head; ch < foot; ch++) { luentp = pklist[ch].lui; diff = luentp->idletime; if (!luentp->pid) { state = US_PICKUP; break; } if (diff > 0) sprintf(buf, "%3d'%02d", diff / 60, diff % 60); else buf[0] = '\0'; prints("%5d %-13s%-17.16s%s%-17.16s%-13.13s%-4s%s\n", (ch + 1), luentp->userid, luentp->username, 1 ? "" : "", luentp->from, luser->host[luentp->hostid].desc, luentp->birth ? "壽星" :"" , buf); } } if (state == US_PICKUP) continue; move(b_lines, 0); outs("(TAB/f)排序/好友 (t)聊天 \ (a/d/o)交友 (q)查詢 (w)扣應 \ (m)寄信 (h)線上輔助 "); 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': return; case KEY_TAB: pickup_way = (pickup_way +1) %PICKUP_WAYS; state = US_PICKUP; num = 0; break; case KEY_DOWN: case 'n': if (++num < actor) { if (num >= foot) state = US_REDRAW; break; } case '0': case KEY_HOME: num = 0; if (head) state = US_REDRAW; break; case 'N': if (HAS_PERM(PERM_BASIC)) { char buf[100]; sprintf(buf, "暱稱 [%s]:", currutmp->username); if (!getdata(1, 0, buf, currutmp->username, 17, DOECHO)) strcpy(currutmp->username, cuser.username); state = US_PICKUP; } break; case 'H': if (HAS_PERM(PERM_SYSOP)) { currutmp->userlevel ^= PERM_DENYPOST; state = US_PICKUP; } 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_PICKUP; } 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_PICKUP; } 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: 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 '/': { int tmp; if ((tmp = search_pickup(num, actor, pklist)) >= 0) num = tmp; state = US_REDRAW; } 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 SHOWTTY case 'Y': if (HAS_PERM(PERM_SYSOP)) show_tty ^= 1; state = US_PICKUP; break; #endif #ifdef SHOWPID case 'I': if (HAS_PERM(PERM_SYSOP)) show_pid ^= 1; state = US_PICKUP; break; #endif case 'b': /* broadcast */ bc_time = time(NULL); bc_tm = localtime(&bc_time); if (pickup_way != 5 && cuser.uflag & FRIEND_FLAG || HAS_PERM(PERM_SYSOP) /* Ptt 週年慶 */ || ( bc_tm -> tm_mon == 8 && bc_tm -> tm_mday >= 12 && bc_tm -> tm_mday <= 16 && bc_tm -> tm_hour == 22 && bc_tm -> tm_min <= 10 && HAS_PERM(PERM_LOGINOK) ) ) { int actor_pos = actor; char ans[4]; state = US_PICKUP; if (!getdata(0, 0, "廣播訊息:", genbuf + 1, 60, DOECHO)) break; if (getdata(0, 0, "確定廣播? [Y]", ans, 4, LCECHO) && *ans == 'n') break; genbuf[0] = HAS_PERM(PERM_SYSOP) ? 2 : 0; while (actor_pos) { uentp = pklist[--actor_pos].ui; if (uentp->pid && currpid != uentp->pid && kill(uentp->pid, 0) != -1 && (HAS_PERM(PERM_SYSOP) || (uentp->pager != 3 && (uentp->pager != 4 || is_friend(uentp) &2)))) my_write(uentp->pid, genbuf); } } break; case 's': /* 顯示好友描述 */ if (pickup_way != 5) { show_friend ^= 1; state = US_PICKUP; } break; case 'u': /* 線上修改資料 */ case 'K': /* 把壞蛋踢出去 */ if (pickup_way != 5 && !HAS_PERM(PERM_ACCOUNTS)) continue; state = US_ACTION; break; case 't': case 'w': if (!(cuser.userlevel & PERM_PAGE)) continue; state = US_ACTION; break; case 'a': case 'd': case 'o': case 'f': if (pickup_way == 5 || !HAS_PERM(PERM_LOGINOK)) /* 註冊才有 Friend */ break; if (ch == 'f') { cuser.uflag ^= FRIEND_FLAG; state = US_PICKUP; break; } state = US_ACTION; break; case 'q': case 'm': case 'r': case 'l': if (bad_user(cuser.userid) || !cuser.userlevel && ch != 'q' && ch != 'l') /* guest 只能 query */ break; if (pickup_way == 5 && ch == 'q' ) break; case 'h': state = US_ACTION; break; /* woju */ case Ctrl('R'): if (currutmp->msgs[0].last_pid) { show_last_call_in(); my_write(currutmp->msgs[0].last_pid, "水球丟回去:"); state = US_PICKUP; } break; case 'p': if (HAS_PERM(PERM_BASIC)) { t_pager(); state = US_PICKUP; } break; case KEY_ESC: if (KEY_ESC_arg == 'c') capture_screen(); else if (KEY_ESC_arg == 'n') { edit_note(); state = US_PICKUP; } break; default: /* refresh user state */ state = US_PICKUP; } } if (state != US_ACTION) { pid0 = 0; continue; } /* Ptt decide cur */ if( pickup_way != 5 ) { uentp = pklist[num].ui; pid0 = uentp->pid; id0 = 256 * uentp->userid[0] + uentp->userid[1]; } else { luentp = pklist[num].lui; pid0 = luentp->pid; id0 = 256 * luentp->userid[0] + luentp->userid[1]; } if (ch == 'w') { if (pickup_way != 5 && (uentp->pid != currpid) && (HAS_PERM(PERM_SYSOP) || ( uentp->pager != 3 && (is_friend(uentp) & 2 || uentp->pager != 4) ))) { cursor_show(num + 3 - head, 0); my_write(uentp->pid, "熱線 Call-In:"); } else if(pickup_way == 5) { buf[3]; sprintf("l%c",(char) luentp->hostid); cursor_show(num + 3 - head, 0); my_write(uentp->pid, buf); } else state = 0; } else if (ch == 'l') { /* Thor: 看 Last call in */ t_display(); state = US_PICKUP; } else { switch (ch) { case 'r': m_read(); break; 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 && (kill(uentp->pid, 0) != -1)) { move(1, 0); clrtobot(); move(2, 0); my_kick(uentp); state = US_PICKUP; } break; case 'm': stand_title("寄 信"); if(pickup_way != 5) { prints("收信人:%s", uentp->userid); my_send(uentp->userid); } else { /* mail */ } break; case 'q': strcpy(currauthor, uentp->userid); my_query(uentp->userid); break; case 'u': /* Thor: 可線上查看及修改使用者 */ { int id; userec 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 (pickup_way != 5 && uentp->pid != currpid) /* if (uentp->uid != usernum) */ { move(1, 0); clrtobot(); move(3, 0); my_talk(uentp); state = US_PICKUP; } else if(pickup_way == 5) { /* talk */ } break; } } setutmpmode(savemode); } } static int listcuent(uentp) user_info *uentp; { if ((uentp->uid != usernum) && (!uentp->invisible || HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_SEECLOAK))) AddNameList(uentp->userid); return 0; } static void creat_list() { CreateNameList(); apply_ulist(listcuent); } int t_users() { int destuid0 = currutmp->destuid; int mode0 = currutmp->mode; int stat0 = currstat; if (chkmailbox()) return; 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]; 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; { char buf[80],passbuf[PASSLEN]; 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)); } currutmp->mode = mode0; currutmp->destuid = destuid0; currstat = stat0; 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; user_info *uentp; char genbuf[4]; if (count_ulist() <= 1) { outs("目前線上只有您一人,快邀請朋友來光臨【" BOARDNAME "】吧!"); 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(cmpuids, tuid, 0)) > 1) { outs("(0) 不想 talk 了...\n"); count_logins(cmpuids, 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 = (user_info *) search_ulistn(cmpuids, tuid, unum)) my_talk(uentp); return 0; } /* ------------------------------------- */ /* 有人來串門子了,回應呼叫器 */ /* ------------------------------------- */ user_info *uip; void talkreply() { int a; struct hostent *h; char hostname[STRLEN], buf[4]; struct sockaddr_in sin; char genbuf[200]; int i; talkrequest = NA; uip = currutmp->destuip; sprintf(page_requestor, "%s (%s)", uip->userid, uip->username); currutmp->destuid = uip->uid; currstat = XMODE; /* 避免出現動畫 */ clear(); outs("\n\n\ (Y) 讓我們 talk 吧! (A) 我現在很忙,請等一會兒再 call 我\n\ (N) 我現在不想 talk (B) 對不起,我有事情不能跟你 talk\n\ (C) 請不要吵我好嗎? (D) 我要離站囉..下次再聊吧.......\n\ (E) 有事嗎?請先來信 (F) 我自己輸入理由好了...\n\n"); getuser(uip->userid); currutmp->msgs[0].last_pid = uip->pid; strcpy(currutmp->msgs[0].last_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(); sprintf(genbuf, "你想跟 %s 聊聊天嗎?請選擇(Y/N/A/B/C/D)[Y] ", page_requestor); 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)); gethostname(hostname, STRLEN); if (!(h = gethostbyname(hostname))) { 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("abcdefn", buf[0])) buf[0] = 'y'; write(a, buf, 1); if (buf[0] == 'f' || buf[0] == 'F') { if (!getdata(b_lines, 0, "不能 talk 的原因:", genbuf, 60, DOECHO,0)) strcpy(genbuf, "不告訴你咧 !! ^o^"); write(a, genbuf, 60); } if (buf[0] == 'y') do_talk(a); else close(a); clear(); } /* ------------------------------------- */ /* 網友動態簡表 */ /* ------------------------------------- */ int shortulist(uentp) user_info *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) || ((is_rejected(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) ? 6 : is_friend(uentp); if (PERM_HIDE(uentp)) state = PERM_HIDE(currutmp) ? 5 : 0; if (PERM_HIDE(currutmp) && state == 3) state = 6; sprintf(uentry, "%s%-13s%c%-10s%s ", fcolor[state], uentp->userid, uentp->invisible ? '#' : ' ', modestring(uentp, 1), state ? "" : ""); } if (++linecnt < 3) { strcat(uentry, "│"); outs(uentry); } else { outs(uentry); linecnt = 0; clrtoeol(); move(++lineno, 0); } return 0; } static void do_list(modestr) char *modestr; { int count; showtitle(modestr, BoardName); if (currstat == MONITOR) prints("每隔 %d 秒更新一次,請按[Ctrl-C]或[Ctrl-D]離開", M_INT); outc('\n'); outs(msg_shortulist); friends_number = override_number = 0; if (apply_ulist(shortulist) == -1) { outs(msg_nobody); } else { time_t thetime = time(NULL); count = shortulist(NULL); move(b_lines, 0); prints(" 上站總人數:%-7d我的朋友:%-6d" "與我為友:%-8d%-23s", count, friends_number, override_number, Cdate(&thetime)); refresh(); } } int t_list() { setutmpmode(LUSERS); do_list("使用者狀態"); igetch(); return 0; } /* ------------------------------------- */ /* 監看使用情形 */ /* ------------------------------------- */ int idle_monitor_time; static void sig_catcher() { if (currstat != MONITOR) { #ifdef DOTIMEOUT init_alarm(); #else signal(SIGALRM, SIG_IGN); #endif return; } if (signal(SIGALRM, sig_catcher) == SIG_ERR) { perror("signal"); exit(1); } #ifdef DOTIMEOUT if (!PERM_HIDE(currutmp)) idle_monitor_time += M_INT; if (idle_monitor_time > MONITOR_TIMEOUT) { clear(); fprintf(stderr, "timeout\n"); abort_bbs(); } #endif do_list("追蹤站友"); alarm(M_INT); } int t_monitor() { char c; int i; setutmpmode(MONITOR); alarm(0); signal(SIGALRM, sig_catcher); idle_monitor_time = 0; do_list("追蹤站友"); alarm(M_INT); while (YEA) { i = read(0, &c, 1); if (!i || c == Ctrl('D') || c == Ctrl('C')) break; else if (i == -1) { if (errno != EINTR) { perror("read"); exit(1); } } else idle_monitor_time = 0; } return 0; } /* int t_friends() { if (friendcount) { setutmpmode(FRIEND); pickup_user(); if (!(friends_number || override_number)) { outs("再等一下吧,也許\他們待會兒就上線了。"); return XEASY; } return 0; } else { outs("目前還沒設定好友名單"); return XEASY; } } */ void t_aloha() { int i; user_info *uentp; pid_t pid; char buf[100]; sprintf(buf + 1, "☆ %s(%s) 上站了! ", cuser.userid, cuser.username); *buf = 0; /* Thor: 特別注意, 自己上站不會通知自己... */ for (i = 0; i < USHM_SIZE; i++) { uentp = &utmpshm->uinfo[i]; if ((pid = uentp->pid) && (kill(pid, 0) != -1) && uentp->pager && (is_friend(uentp) & 2) && strcmp(uentp->userid, cuser.userid)) my_write(uentp->pid, buf); } }