精華區beta SetupBBS 關於我們 聯絡資訊
/*-------------------------------------------------------*/ /* chat.c ( NTHU CS MapleBBS Ver 2.36 ) */ /*-------------------------------------------------------*/ /* target : chat client for xchatd */ /* create : 95/03/29 */ /* update : 95/12/15 */ /*-------------------------------------------------------*/ #include "bbs.h" #ifdef lint #include <sys/uio.h> #endif #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #define MAXLASTCMD 6 char chatroom[IDLEN]; /* Chat-Room Name */ int stop_line; /* next line of bottom of message window area */ static FILE* flog; /* woju chatid prompt, for call back...needs longer */ int chatid_len = 10; extern char page_requestor[]; extern char *modestring(); extern char *Cdate(); int chatline; void printchatline(str) char *str; { move(chatline, 0); if (*str == '@') { char *id, *msg; char buf[100]; char fpath[100]; FILE* fp; user_info *uentp; int tuid; extern cmpuids(); id = str + 1; (msg = strchr(id, '@') + 1)[-1] = 0; if ((tuid = searchuser(id)) && tuid != usernum && (uentp = (user_info *) search_ulistn(cmpuids, tuid, 1))) { sprintf(buf, "★ %s 不在聊天室,發送水球★\n", id); outs(buf); strcpy(buf + 1, msg); *buf = 0; my_write(uentp->pid, buf); sprintf(buf, "%s★ %s", id, msg); strcpy(str, buf); } else { sprintf(buf, "msg fail: %s 不在站上\n", id); outs(buf); } } else if (*str == '>' && !PERM_HIDE(currutmp)) return; else if (chatline < stop_line - 1) { chatline++; } else { region_scroll_up(2, stop_line - 2); move(stop_line - 2, 0); } outs(str); outc('\n'); outs("→"); if (flog) fprintf(flog, "%s\n", str); } static void chat_clear() { for (chatline = 2; chatline < stop_line; chatline++) { move(chatline, 0); clrtoeol(); } move(b_lines, 0); clrtoeol(); move(chatline = 2, 0); outs("→"); } static void print_chatid(chatid) char *chatid; { move(b_lines - 1, 0); clrtoeol(); outs(chatid); outc(':'); } static int chat_send(fd, buf) int fd; char *buf; { int len; char genbuf[200]; sprintf(genbuf, "%s\n", buf); len = strlen(genbuf); return (send(fd, genbuf, len, 0) == len); } static int chat_recv(fd, chatid) int fd; char *chatid; { static char buf[512]; static int bufstart = 0; char genbuf[200]; int c, len; char *bptr; len = sizeof(buf) - bufstart - 1; if ((c = recv(fd, buf + bufstart, len, 0)) <= 0) return -1; c += bufstart; bptr = buf; while (c > 0) { len = strlen(bptr) + 1; if (len > c && len < (sizeof buf / 2)) break; if (*bptr == '/') { switch (bptr[1]) { case 'c': chat_clear(); break; case 'n': strncpy(chatid, bptr + 2, 8); print_chatid(chatid); clrtoeol(); break; case 'r': strncpy(chatroom, bptr + 2, IDLEN - 1); break; case 't': move(0, 0); clrtoeol(); sprintf(genbuf, "談天室 [%s]", chatroom); prints(" %-21s 話題:%-48s", genbuf, bptr + 2); } } else printchatline(bptr); c -= len; bptr += len; } if (c > 0) { strcpy(genbuf, bptr); strcpy(buf, genbuf); bufstart = len - 1; } else bufstart = 0; return 0; } static int printuserent(uentp) user_info *uentp; { static char uline[80]; static int cnt; char pline[30]; if (!uentp) { if (cnt) printchatline(uline); bzero(uline, 80); cnt = 0; return 0; } if (!HAS_PERM(PERM_SYSOP) && !HAS_PERM(PERM_SEECLOAK) && uentp->invisible) return 0; #if 0 if (kill(uentp->pid, 0) == -1) return 0; #endif sprintf(pline, "%-13s%c%-10s ", uentp->userid, uentp->invisible ? '#' : ' ', modestring(uentp, 1)); if (cnt < 2) strcat(pline, "│"); strcat(uline, pline); if (++cnt == 3) { printchatline(uline); memset(uline, 0, 80); cnt = 0; } return 0; } static void chathelp(cmd, desc) char *cmd, *desc; { char buf[STRLEN]; sprintf(buf, " %-20s- %s", cmd, desc); printchatline(buf); } static void chat_help(arg) char *arg; { if (strstr(arg, " op")) { printchatline("談天室管理員專用指令"); chathelp("[/f]lag [+-][ls]", "設定鎖定、秘密狀態"); chathelp("[/i]nvite <id>", "邀請 <id> 加入談天室"); chathelp("[/k]ick <id>", "將 <id> 踢出談天室"); chathelp("[/o]p <id>", "將 Op 的權力轉移給 <id>"); chathelp("[/t]opic <text>", "換個話題"); chathelp("[/w]all", "廣播 (站長專用)"); } else { chathelp("[//]help", "MUD-like 社交動詞"); chathelp("[/h]elp op", "談天室管理員專用指令"); chathelp("[/a]ct <msg>", "做一個動作"); chathelp("[/b]ye [msg]", "道別"); chathelp("[/c]lear", "清除螢幕"); chathelp("[/j]oin <room>", "建立或加入談天室"); chathelp("[/l]ist [room]", "列出談天室使用者"); chathelp("[/m]sg <id> <msg>", "跟 <id> 說悄悄話"); chathelp("[/n]ick <id>", "將談天代號換成 <id>"); chathelp("[/p]ager", "切換呼叫器"); chathelp("[/q]uery", "查詢網友"); chathelp("[/r]oom", "列出一般談天室"); chathelp("[/u]sers", "列出站上使用者"); chathelp("[/w]ho", "列出本談天室使用者"); chathelp("[/w]hoin <room>", "列出談天室<room> 的使用者"); } } static void chat_date() { time_t thetime; char genbuf[200]; time(&thetime); sprintf(genbuf, "◆ %s標準時間: %s", BoardName, Cdate(&thetime)); printchatline(genbuf); } static void chat_pager() { char genbuf[200]; char *msgs[] = {"關閉", "打開", "拔掉", "防水","好友"}; sprintf(genbuf, "◆ 您的呼叫器:[%s]", msgs[currutmp->pager=(currutmp->pager+1)%5]); printchatline(genbuf); } static void chat_query(arg) char *arg; { char *uid; int tuid; printchatline(""); strtok(arg, str_space); if ((uid = strtok(NULL, str_space)) && (tuid = getuser(uid))) { char buf[128], *ptr; FILE *fp; sprintf(buf, "%s(%s) 共上站 %d 次,發表過 %d 篇文章", xuser.userid, xuser.username, xuser.numlogins, xuser.numposts); printchatline(buf); sprintf(buf, "最近(%s)從[%s]上站", Cdate(&xuser.lastlogin), (xuser.lasthost[0] ? xuser.lasthost : "(不詳)")); printchatline(buf); sethomefile(buf, xuser.userid, fn_plans); if (fp = fopen(buf, "r")) { tuid = 0; while (tuid++ < MAXQUERYLINES && fgets(buf, 128, fp)) { if (ptr = strchr(buf, '\n')) ptr[0] = '\0'; printchatline(buf); } fclose(fp); } } else printchatline(err_uid); } static void chat_users() { printchatline(""); printchatline("【 " BOARDNAME "的遊客列表 】"); printchatline(msg_shortulist); if (apply_ulist(printuserent) == -1) { printchatline("空無一人"); } printuserent(NULL); } struct chat_command { char *cmdname; /* Char-room command length */ void (*cmdfunc) (); /* Pointer to function */ }; struct chat_command chat_cmdtbl[] = { {"help", chat_help}, {"clear", chat_clear}, {"date", chat_date}, {"pager", chat_pager}, {"query", chat_query}, {"users", chat_users}, {NULL, NULL} }; static int chat_cmd_match(buf, str) char *buf; char *str; { while (*str && *buf && !isspace(*buf)) { if (tolower(*buf++) != *str++) return 0; } return 1; } static int chat_cmd(buf, fd) char *buf; int fd; { int i; if (*buf++ != '/') return 0; for (i = 0; chat_cmdtbl[i].cmdname; i++) { if (chat_cmd_match(buf, chat_cmdtbl[i].cmdname)) { chat_cmdtbl[i].cmdfunc(buf); return 1; } } return 0; } char* select_address() { int c; FILE* fp; char nametab[25][90]; char iptab[25][18] , buf[80]; move(1,0); clrtobot(); outs("\n 【找個地方抬抬槓吧!】 ◎ 【以下為本站登記有案的茶樓】 \n"); if (fp = fopen("etc/teashop", "r")) { for (c=0;fscanf(fp,"%s%s",iptab[c],nametab[c])!=EOF;c++) { sprintf(buf,"\n (%d) %-30s [%s]",c+1,nametab[c],iptab[c]); outs(buf); } getdata(20 , 10, "★ 請選擇,[Enter]離開:", buf, 3, LCECHO); buf[0]-='1'; if(buf[1]) buf[0]=(buf[0]+1)*10+(buf[1]-'1'); strcpy(trans_buffer,iptab[buf[0]]); if( buf[0] >= 0 && buf[0] < c) { return trans_buffer; } else { return ""; } } else { outs("本站沒有登記任何合格茶樓"); pressanykey(); return ""; } } int t_chat() { char inbuf[80], chatid[20], lastcmd[MAXLASTCMD][80], *ptr, inbuf0[80]; struct sockaddr_in sin; struct hostent *h; int cfd, cmdpos, ch; int currchar, currchar0; int newmail; extern int dumb_term; int page_pending = NA; int chatting = YEA; char fpath[80]; FILE* fp; char genbuf[200]; int phone_mode = 0; char* pstr; extern char* phone_char(); strcpy(inbuf,select_address()); if(inbuf[0]==0) { return -1; } outs(" 驅車前往 請梢候........ "); if (!(h = gethostbyname(inbuf))) { perror("gethostbyname"); return -1; } memset(&sin, 0, sizeof sin); sin.sin_family = PF_INET; /* sin.sin_family = h->h_addrtype; */ memcpy(&sin.sin_addr, h->h_addr, h->h_length); sin.sin_port = CHATPORT; cfd = socket(sin.sin_family, SOCK_STREAM, 0); if (connect(cfd, (struct sockaddr *) & sin, sizeof sin)) { close(cfd); switch (ch = fork()) { case -1: /* fork error */ break; case 0: /* child */ execl("bin/xchatd", "xchatd", NULL); exit(1); default: /* parent ch = child's pid */ /* The chat daemon forks so we can wait on it here. */ waitpid(ch, NULL, 0); } cfd = socket(sin.sin_family, SOCK_STREAM, 0); if ((connect(cfd, (struct sockaddr *) & sin, sizeof sin))) { outs("\n 哇! 沒人在那邊耶...要有那地方的人先去開門啦!..."); pressanykey(); return -1; } } while (1) { getdata(b_lines - 1, 0, "請輸入聊天代號:", inbuf, 9, DOECHO, NULL); sprintf(chatid, "%s", (inbuf[0] ? inbuf : cuser.userid)); chatid[8] = '\0'; sprintf(inbuf, "/! %d %d %s %s", usernum, currutmp->userlevel, cuser.userid, chatid); chat_send(cfd, inbuf); if (recv(cfd, inbuf, 3, 0) != 3) { return 0; } if (!strcmp(inbuf, CHAT_LOGIN_OK)) break; else if (!strcmp(inbuf, CHAT_LOGIN_EXISTS)) ptr = "這個代號已經有人用了"; else if (!strcmp(inbuf, CHAT_LOGIN_INVALID)) ptr = "這個代號是錯誤的"; move(b_lines - 2, 0); outs(ptr); clrtoeol(); bell(); } add_io(cfd, 0); newmail = currchar = 0; cmdpos = -1; memset(lastcmd, 0, MAXLASTCMD * 80); setutmpmode(CHATING); currutmp->in_chat = YEA; strcpy(currutmp->chatid, chatid); clear(); chatline = 2; strcpy(inbuf, chatid); stop_line = t_lines - 3; move(stop_line, 0); outs(msg_seperator); move(1, 0); outs(msg_seperator); print_chatid(chatid); memset(inbuf, 0, 80); /* woju */ sethomepath(fpath, cuser.userid); strcpy(fpath, tempnam(fpath, "chat_")); flog = fopen(fpath, "w"); while (chatting) { move(b_lines - 1, currchar + chatid_len); ch = igetkey(); switch (ch) { case KEY_DOWN: cmdpos += MAXLASTCMD - 2; case KEY_UP: cmdpos++; cmdpos %= MAXLASTCMD; strcpy(inbuf, lastcmd[cmdpos]); move(b_lines - 1, chatid_len); clrtoeol(); outs(inbuf); currchar = strlen(inbuf); continue; case KEY_LEFT: if (currchar) --currchar; continue; case KEY_RIGHT: if (inbuf[currchar]) ++currchar; continue; } if (!newmail && chkmail(0)) { newmail = 1; printchatline("◆ 噹!郵差又來了..."); } if (ch == I_OTHERDATA) /* incoming */ { if (chat_recv(cfd, chatid) == -1) { chatting = chat_send(cfd, "/b"); break; } continue; } if (phone_mode && (pstr = phone_char(ch)) || isprint2(ch)) { if (currchar + (phone_char && pstr) < 68) { if (inbuf[currchar]) { /* insert */ int i; for (i = currchar; inbuf[i] && i + (phone_mode && pstr) < 68; i++) ; inbuf[i + 1 + (phone_mode && pstr)] = '\0'; for (; i > currchar; i--) inbuf[i + (phone_mode && pstr)] = inbuf[i - 1]; } else { /* append */ inbuf[currchar + 1 + (phone_mode && pstr)] = '\0'; } if (phone_mode && pstr) { inbuf[currchar] = pstr[0]; inbuf[currchar + 1] = pstr[1]; } else inbuf[currchar] = ch; move(b_lines - 1, currchar + chatid_len); outs(&inbuf[currchar++]); currchar += phone_mode && pstr; } continue; } if (ch == '\n' || ch == '\r') { if (*inbuf) { chatting = chat_cmd(inbuf, cfd); if (chatting == 0) chatting = chat_send(cfd, inbuf); if (!strncmp(inbuf, "/b", 2)) break; for (cmdpos = MAXLASTCMD - 1; cmdpos; cmdpos--) strcpy(lastcmd[cmdpos], lastcmd[cmdpos - 1]); strcpy(lastcmd[0], inbuf); inbuf[0] = '\0'; currchar = 0; cmdpos = -1; } print_chatid(chatid); move(b_lines - 1, chatid_len); continue; } if (ch == KEY_ESC && KEY_ESC_arg == 'p') { phone_mode ^= 1; continue; } if (ch == KEY_ESC && KEY_ESC_arg == 'n') { extern screenline* big_picture; screenline* screen0 = calloc(t_lines, sizeof(screenline)); memcpy(screen0, big_picture, t_lines * sizeof(screenline)); add_io(0, 0); edit_note(); memcpy(big_picture, screen0, t_lines * sizeof(screenline)); free(screen0); redoscr(); add_io(cfd, 0); continue; } if (ch == KEY_ESC && KEY_ESC_arg == 'c') { capture_screen(); continue; } if (ch == Ctrl('H') || ch == '\177') { if (currchar) { currchar--; inbuf[69] = '\0'; memcpy(&inbuf[currchar], &inbuf[currchar + 1], 69 - currchar); move(b_lines - 1, currchar + chatid_len); clrtoeol(); outs(&inbuf[currchar]); } continue; } if (ch == Ctrl('Z') || ch == Ctrl('Y')) { inbuf[0] = '\0'; currchar = 0; print_chatid(chatid); move(b_lines - 1, chatid_len); continue; } if (ch == Ctrl('C')) { chat_send(cfd, "/b"); break; } /* woju */ if (ch == Ctrl('D')) { if (currchar < strlen(inbuf)) { inbuf[69] = '\0'; memcpy(&inbuf[currchar], &inbuf[currchar + 1], 69 - currchar); move(b_lines - 1, currchar + chatid_len); clrtoeol(); outs(&inbuf[currchar]); } continue; } if (ch == Ctrl('K')) { inbuf[currchar] = 0; move(b_lines - 1, currchar + chatid_len); clrtoeol(); continue; } if (ch == Ctrl('A')) { currchar = 0; continue; } if (ch == Ctrl('E')) { currchar = strlen(inbuf); continue; } if (ch == Ctrl('U')) { extern screenline* big_picture; screenline* screen0 = calloc(t_lines, sizeof(screenline)); memcpy(screen0, big_picture, t_lines * sizeof(screenline)); add_io(0, 0); t_users(); memcpy(big_picture, screen0, t_lines * sizeof(screenline)); free(screen0); redoscr(); add_io(cfd, 0); continue; } if (ch == Ctrl('I')) { extern screenline* big_picture; screenline* screen0 = calloc(t_lines, sizeof(screenline)); memcpy(screen0, big_picture, t_lines * sizeof(screenline)); add_io(0, 0); t_idle(); memcpy(big_picture, screen0, t_lines * sizeof(screenline)); free(screen0); redoscr(); add_io(cfd, 0); continue; } if (ch == Ctrl('R') && currutmp->msgs[0].last_pid) { extern screenline* big_picture; screenline* screen0 = calloc(t_lines, sizeof(screenline)); memcpy(screen0, big_picture, t_lines * sizeof(screenline)); add_io(0, 0); show_last_call_in(); my_write(currutmp->msgs[0].last_pid, "水球丟回去:"); memcpy(big_picture, screen0, t_lines * sizeof(screenline)); free(screen0); redoscr(); add_io(cfd, 0); continue; } if (ch == Ctrl('Q')) { print_chatid(chatid); move(b_lines - 1, chatid_len); outs(inbuf); continue; } } close(cfd); add_io(0, 0); currutmp->in_chat = currutmp->chatid[0] = 0; if (flog) { char ans[4]; 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, "[備.忘.錄]"); strcpy(mymail.title, "會議記錄"); sethomedir(title, cuser.userid); append_record(title, &mymail, sizeof(mymail)); Rename(fpath, genbuf); } else unlink(fpath); } return 0; }