summaryrefslogtreecommitdiffstats
path: root/console/chat.c
diff options
context:
space:
mode:
Diffstat (limited to 'console/chat.c')
-rw-r--r--console/chat.c597
1 files changed, 597 insertions, 0 deletions
diff --git a/console/chat.c b/console/chat.c
new file mode 100644
index 00000000..6623fbc2
--- /dev/null
+++ b/console/chat.c
@@ -0,0 +1,597 @@
+/* $Id$ */
+#include "bbs.h"
+
+#ifndef DBCSAWARE
+#define dbcs_off (1)
+#endif
+
+#define STOP_LINE (t_lines-3)
+static int chatline;
+static FILE *flog;
+static void
+printchatline(const char *str)
+{
+ move(chatline, 0);
+ 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(char*unused)
+{
+ 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(const char *chatid)
+{
+ move(b_lines - 1, 0);
+ clrtoeol();
+ outs(chatid);
+ outc(':');
+}
+
+static int
+chat_send(int fd, const char *buf)
+{
+ int len;
+ char genbuf[200];
+
+ len = snprintf(genbuf, sizeof(genbuf), "%s\n", buf);
+ return (send(fd, genbuf, len, 0) == len);
+}
+
+struct ChatBuf {
+ char buf[128];
+ int bufstart;
+};
+
+static int
+chat_recv(struct ChatBuf *cb, int fd, char *chatroom, char *chatid, size_t chatid_size)
+{
+ int c, len;
+ char *bptr;
+
+ len = sizeof(cb->buf) - cb->bufstart - 1;
+ if ((c = recv(fd, cb->buf + cb->bufstart, len, 0)) <= 0)
+ return -1;
+ c += cb->bufstart;
+
+ bptr = cb->buf;
+ while (c > 0) {
+ len = strlen(bptr) + 1;
+ if (len > c && (unsigned)len < (sizeof(cb->buf)/ 2) )
+ break;
+
+ if (*bptr == '/') {
+ switch (bptr[1]) {
+ case 'c':
+ chat_clear(NULL);
+ break;
+ case 'n':
+ strlcpy(chatid, bptr + 2, chatid_size);
+ print_chatid(chatid);
+ clrtoeol();
+ break;
+ case 'r':
+ strlcpy(chatroom, bptr + 2, IDLEN);
+ break;
+ case 't':
+ move(0, 0);
+ clrtoeol();
+ prints(ANSI_COLOR(1;37;46) " 談天室 [%-12s] " ANSI_COLOR(45) " 話題:%-48s" ANSI_RESET,
+ chatroom, bptr + 2);
+ }
+ } else
+ printchatline(bptr);
+
+ c -= len;
+ bptr += len;
+ }
+
+ if (c > 0) {
+ memmove(cb->buf, bptr, sizeof(cb->buf)-(bptr-cb->buf));
+ cb->bufstart = len - 1;
+ } else
+ cb->bufstart = 0;
+ return 0;
+}
+
+static void
+chathelp(const char *cmd, const char *desc)
+{
+ char buf[STRLEN];
+
+ snprintf(buf, sizeof(buf), " %-20s- %s", cmd, desc);
+ printchatline(buf);
+}
+
+static void
+chat_help(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", "chicken 鬥雞用指令");
+ chathelp(" /help op", "談天室管理員專用指令");
+ chathelp("[//]help", "MUD-like 社交動詞");
+ 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 <id>", "查詢網友");
+ chathelp("[/r]oom ", "列出一般談天室");
+ chathelp("[/w]ho", "列出本談天室使用者");
+ chathelp(" /whoin <room>", "列出談天室<room> 的使用者");
+ chathelp(" /ignore <userid>", "忽略指定使用者的訊息");
+ chathelp(" /unignore <userid>", "停止忽略指定使用者的訊息");
+ }
+}
+
+static void
+chat_date(char *unused)
+{
+ char genbuf[200];
+
+ snprintf(genbuf, sizeof(genbuf),
+ "◆ " BBSNAME "標準時間: %s", Cdate(&now));
+ printchatline(genbuf);
+}
+
+static void
+chat_pager(char *unused)
+{
+ char genbuf[200];
+
+ char *msgs[PAGER_MODES] = {
+ /* Ref: please match PAGER* in modes.h */
+ "關閉", "打開", "拔掉", "防水", "好友"
+ };
+
+ snprintf(genbuf, sizeof(genbuf), "◆ 您的呼叫器:[%s]",
+ msgs[currutmp->pager = (currutmp->pager + 1) % PAGER_MODES]);
+ printchatline(genbuf);
+}
+
+static void
+chat_query(char *arg)
+{
+ char *uid;
+ int tuid;
+ userec_t xuser;
+ char *strtok_pos;
+
+ printchatline("");
+ strtok_r(arg, str_space, &strtok_pos);
+ if ((uid = strtok_r(NULL, str_space, &strtok_pos)) && (tuid = getuser(uid, &xuser))) {
+ char buf[128], *ptr;
+ FILE *fp;
+
+ snprintf(buf, sizeof(buf), "%s(%s) 共上站 %d 次,發表過 %d 篇文章",
+ xuser.userid, xuser.nickname,
+ xuser.numlogins, xuser.numposts);
+ printchatline(buf);
+
+ snprintf(buf, sizeof(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++ < MAX_QUERYLINES && fgets(buf, 128, fp)) {
+ if ((ptr = strchr(buf, '\n')))
+ ptr[0] = '\0';
+ printchatline(buf);
+ }
+ fclose(fp);
+ }
+ } else
+ printchatline(err_uid);
+}
+
+typedef struct chat_command_t {
+ char *cmdname; /* Chatroom command length */
+ void (*cmdfunc) (char *); /* Pointer to function */
+} chat_command_t;
+
+static const chat_command_t chat_cmdtbl[] = {
+ {"help", chat_help},
+ {"clear", chat_clear},
+ {"date", chat_date},
+ {"pager", chat_pager},
+ {"query", chat_query},
+ {NULL, NULL}
+};
+
+static int
+chat_cmd_match(const char *buf, const char *str)
+{
+ while (*str && *buf && !isspace((int)*buf))
+ if (tolower(*buf++) != *str++)
+ return 0;
+ return 1;
+}
+
+static int
+chat_cmd(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;
+}
+
+#define MAXLASTCMD 6
+static int chatid_len = 10;
+static time4_t lastEnter = 0;
+
+int
+t_chat(void)
+{
+ char chatroom[IDLEN];/* Chat-Room Name */
+ char inbuf[80], chatid[20], lastcmd[MAXLASTCMD][80], *ptr = "";
+ struct sockaddr_in sin;
+ int cfd, cmdpos, ch;
+ int currchar;
+ int chatting = YEA;
+ char fpath[80];
+ struct ChatBuf chatbuf;
+
+ if(HasUserPerm(PERM_VIOLATELAW))
+ {
+ vmsg("請先繳罰單才能使用聊天室!");
+ return -1;
+ }
+
+ syncnow();
+
+#ifdef CHAT_GAPMINS
+ if ((now - lastEnter)/60 < CHAT_GAPMINS)
+ {
+ vmsg("您才剛離開聊天室,裡面正在整理中。請稍後再試。");
+ return 0;
+ }
+#endif
+
+#ifdef CHAT_REGDAYS
+ if ((now - cuser.firstlogin)/86400 < CHAT_REGDAYS)
+ {
+ int i = CHAT_REGDAYS - (now-cuser.firstlogin)/86400 +1;
+ vmsgf("您還不夠資深喔 (再等 %d 天吧)", i);
+ return 0;
+ }
+#endif
+
+ memset(&chatbuf, 0, sizeof(chatbuf));
+ outs(" 驅車前往 請梢候........ ");
+
+ memset(&sin, 0, sizeof sin);
+#ifdef __FreeBSD__
+ sin.sin_len = sizeof(sin);
+#endif
+ sin.sin_family = PF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ sin.sin_port = htons(NEW_CHATPORT);
+ cfd = socket(sin.sin_family, SOCK_STREAM, 0);
+ if (connect(cfd, (struct sockaddr *) & sin, sizeof sin) != 0) {
+ outs("\n "
+ "哇! 沒人在那邊耶...要有那地方的人先去開門啦!...");
+ system("bin/xchatd");
+ pressanykey();
+ close(cfd);
+ return -1;
+ }
+
+ while (1) {
+ getdata(b_lines - 1, 0, "請輸入聊天代號:", chatid, 9, DOECHO);
+ if(!chatid[0])
+ strlcpy(chatid, cuser.userid, sizeof(chatid));
+ chatid[8] = '\0';
+ /*
+ * 新格式: /! UserID ChatID Password
+ */
+ snprintf(inbuf, sizeof(inbuf), "/! %s %s %s",
+ cuser.userid, chatid, cuser.passwd);
+ chat_send(cfd, inbuf);
+ if (recv(cfd, inbuf, 3, 0) != 3) {
+ close(cfd);
+ vmsg("系統錯誤。");
+ 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 = "這個代號是錯誤的";
+ else if (!strcmp(inbuf, CHAT_LOGIN_BOGUS))
+ ptr = "請勿派遣分身進入聊天室 !!";
+
+ move(b_lines - 2, 0);
+ outs(ptr);
+ clrtoeol();
+ bell();
+ }
+ syncnow();
+ lastEnter = now;
+
+ add_io(cfd, 0);
+
+ currchar = 0;
+ cmdpos = -1;
+ memset(lastcmd, 0, sizeof(lastcmd));
+
+ setutmpmode(CHATING);
+ currutmp->in_chat = YEA;
+ strlcpy(currutmp->chatid, chatid, sizeof(currutmp->chatid));
+
+ clear();
+ chatline = 2;
+
+ move(STOP_LINE, 0);
+ outs(msg_seperator);
+ move(STOP_LINE, 56);
+ outs(" /h 查詢指令 /b 離開 ");
+ move(1, 0);
+ outs(msg_seperator);
+ print_chatid(chatid);
+ memset(inbuf, 0, sizeof(inbuf));
+
+ setuserfile(fpath, "chat_XXXXXX");
+ flog = fdopen(mkstemp(fpath), "w");
+
+ while (chatting) {
+ move(b_lines - 1, currchar + chatid_len);
+ ch = igetch();
+
+ switch (ch) {
+ case KEY_DOWN:
+ cmdpos += MAXLASTCMD - 2;
+ case KEY_UP:
+ cmdpos++;
+ cmdpos %= MAXLASTCMD;
+ strlcpy(inbuf, lastcmd[cmdpos], sizeof(inbuf));
+ move(b_lines - 1, chatid_len);
+ clrtoeol();
+ outs(inbuf);
+ currchar = strlen(inbuf);
+ continue;
+ case KEY_LEFT:
+ if (currchar)
+ {
+ --currchar;
+#ifdef DBCSAWARE
+ if(currchar > 0 &&
+ ISDBCSAWARE() &&
+ getDBCSstatus((unsigned char*)inbuf, currchar) == DBCS_TRAILING)
+ currchar --;
+#endif
+ }
+ continue;
+ case KEY_RIGHT:
+ if (inbuf[currchar])
+ {
+ ++currchar;
+#ifdef DBCSAWARE
+ if(inbuf[currchar] &&
+ ISDBCSAWARE() &&
+ getDBCSstatus((unsigned char*)inbuf, currchar) == DBCS_TRAILING)
+ currchar++;
+#endif
+ }
+ continue;
+ case KEY_UNKNOWN:
+ continue;
+ }
+
+ if (ISNEWMAIL(currutmp)) {
+ printchatline("◆ 噹!郵差又來了...");
+ }
+ if (ch == I_OTHERDATA) {/* incoming */
+ if (chat_recv(&chatbuf, cfd, chatroom, chatid, 9) == -1) {
+ chatting = chat_send(cfd, "/b");
+ break;
+ }
+ } else if (isprint2(ch)) {
+ if (currchar < 68) {
+ if (inbuf[currchar]) { /* insert */
+ int i;
+
+ for (i = currchar; inbuf[i] && i < 68; i++);
+ inbuf[i + 1] = '\0';
+ for (; i > currchar; i--)
+ inbuf[i] = inbuf[i - 1];
+ } else /* append */
+ inbuf[currchar + 1] = '\0';
+ inbuf[currchar] = ch;
+ move(b_lines - 1, currchar + chatid_len);
+ outs(&inbuf[currchar++]);
+ }
+ } else if (ch == '\n' || ch == '\r') {
+ if (*inbuf) {
+
+#ifdef EXP_ANTIFLOOD
+ // prevent flooding */
+ static time4_t lasttime = 0;
+ static int flood = 0;
+
+ /* // debug anti flodding
+ move(b_lines-3, 0); clrtoeol();
+ prints("lasttime=%d, now=%d, flood=%d\n",
+ lasttime, now, flood);
+ refresh();
+ */
+ syncnow();
+ if (now - lasttime < 3 )
+ {
+ // 3 秒內洗半面是不行的 ((25-5)/2)
+ if( ++flood > 10 ){
+ // flush all input!
+ drop_input();
+ while (wait_input(1, 0))
+ {
+ if (num_in_buf())
+ drop_input();
+ else
+ tty_read((unsigned char*)inbuf, sizeof(inbuf));
+ }
+ drop_input();
+ vmsg("請勿大量剪貼或造成洗板面的效果。");
+ // log?
+ sleep(2);
+ continue;
+ }
+ } else {
+ lasttime = now;
+ flood = 0;
+ }
+#endif // anti-flood
+
+ 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--)
+ strlcpy(lastcmd[cmdpos],
+ lastcmd[cmdpos - 1], sizeof(lastcmd[cmdpos]));
+ strlcpy(lastcmd[0], inbuf, sizeof(lastcmd[0]));
+
+ inbuf[0] = '\0';
+ currchar = 0;
+ cmdpos = -1;
+ }
+ print_chatid(chatid);
+ move(b_lines - 1, chatid_len);
+ } else if (ch == Ctrl('H') || ch == '\177') {
+ if (currchar) {
+#ifdef DBCSAWARE
+ int dbcs_off = 1;
+ if (ISDBCSAWARE() &&
+ getDBCSstatus((unsigned char*)inbuf, currchar-1) == DBCS_TRAILING)
+ dbcs_off = 2;
+#endif
+ currchar -= dbcs_off;
+ inbuf[69] = '\0';
+ memcpy(&inbuf[currchar], &inbuf[currchar + dbcs_off],
+ 69 - currchar);
+ move(b_lines - 1, currchar + chatid_len);
+ clrtoeol();
+ outs(&inbuf[currchar]);
+ }
+ } else if (ch == Ctrl('Z') || ch == Ctrl('Y')) {
+ inbuf[0] = '\0';
+ currchar = 0;
+ print_chatid(chatid);
+ move(b_lines - 1, chatid_len);
+ } else if (ch == Ctrl('C')) {
+ chat_send(cfd, "/b");
+ break;
+ } else if (ch == Ctrl('D')) {
+ if ((size_t)currchar < strlen(inbuf)) {
+#ifdef DBCSAWARE
+ int dbcs_off = 1;
+ if (ISDBCSAWARE() && inbuf[currchar+1] &&
+ getDBCSstatus((unsigned char*)inbuf, currchar+1) == DBCS_TRAILING)
+ dbcs_off = 2;
+#endif
+ inbuf[69] = '\0';
+ memcpy(&inbuf[currchar], &inbuf[currchar + dbcs_off],
+ 69 - currchar);
+ move(b_lines - 1, currchar + chatid_len);
+ clrtoeol();
+ outs(&inbuf[currchar]);
+ }
+ } else if (ch == Ctrl('K')) {
+ inbuf[currchar] = 0;
+ move(b_lines - 1, currchar + chatid_len);
+ clrtoeol();
+ } else if (ch == Ctrl('A')) {
+ currchar = 0;
+ } else if (ch == Ctrl('E')) {
+ currchar = strlen(inbuf);
+ } else if (ch == Ctrl('I')) {
+ screen_backup_t old_screen;
+
+ scr_dump(&old_screen);
+ add_io(0, 0);
+ t_idle();
+ scr_restore(&old_screen);
+ add_io(cfd, 0);
+ } else 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, sizeof(ans), LCECHO);
+ if (*ans == 'm') {
+ fileheader_t mymail;
+ char title[128];
+ char genbuf[200];
+
+ sethomepath(genbuf, cuser.userid);
+ stampfile(genbuf, &mymail);
+ mymail.filemode = FILE_READ ;
+ strlcpy(mymail.owner, "[備.忘.錄]", sizeof(mymail.owner));
+ strlcpy(mymail.title, "會議" ANSI_COLOR(1;33) "記錄" ANSI_RESET, sizeof(mymail.title));
+ sethomedir(title, cuser.userid);
+ append_record(title, &mymail, sizeof(mymail));
+ Rename(fpath, genbuf);
+ } else
+ unlink(fpath);
+ }
+ return 0;
+}