From c1ea6daf1e5c0a32265581410d6a45998b531440 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Thu, 8 Apr 2010 04:33:45 +0000 Subject: [PATCH] * Moved instant messaging into its own module -- serv_instmsg * Removed serv_chat and the CHAT command * Implemented serv_roomchat and the RCHT command, which implements a brand new chat protocol --- .../serv_chat.c => instmsg/serv_instmsg.c} | 394 +----------------- .../serv_chat.h => instmsg/serv_instmsg.h} | 2 - citadel/modules/roomchat/serv_roomchat.c | 243 +++++++++++ citadel/server.h | 9 - citadel/textclient/client_chat.c | 190 ++++----- 5 files changed, 336 insertions(+), 502 deletions(-) rename citadel/modules/{chat/serv_chat.c => instmsg/serv_instmsg.c} (60%) rename citadel/modules/{chat/serv_chat.h => instmsg/serv_instmsg.h} (84%) create mode 100644 citadel/modules/roomchat/serv_roomchat.c diff --git a/citadel/modules/chat/serv_chat.c b/citadel/modules/instmsg/serv_instmsg.c similarity index 60% rename from citadel/modules/chat/serv_chat.c rename to citadel/modules/instmsg/serv_instmsg.c index 5fbd1db2d..fd0fa8e33 100644 --- a/citadel/modules/chat/serv_chat.c +++ b/citadel/modules/instmsg/serv_instmsg.c @@ -1,9 +1,8 @@ /* * $Id$ - * - * This module handles all "real time" communication between users. The - * modes of communication currently supported are Chat and Instant Messages. * + * This module handles instant messaging between users. + * * Copyright (c) 1987-2010 by the citadel.org team * * This program is free software; you can redistribute it and/or modify @@ -48,7 +47,7 @@ #include #include "citadel.h" #include "server.h" -#include "serv_chat.h" +#include "serv_instmsg.h" #include "citserver.h" #include "support.h" #include "config.h" @@ -61,9 +60,6 @@ #include "ctdl_module.h" -struct ChatLine *ChatQueue = NULL; -int ChatLastMsg = 0; - struct imlog { struct imlog *next; long usernums[2]; @@ -75,16 +71,6 @@ struct imlog { struct imlog *imlist = NULL; - - - -/* - * FIXME: OMG this module is realy horrible to the rest of the system when accessing contexts. - * It pays no regard at all to how long it may have the context list locked for. - * It carries out IO whilst the context list is locked. - * I'd recomend disabling this module altogether for the moment. - */ - /* * This function handles the logging of instant messages to disk. */ @@ -163,369 +149,6 @@ void log_instant_message(struct CitContext *me, struct CitContext *them, char *m end_critical_section(S_IM_LOGS); } -/* - * This message can be set to anything you want, but it is - * checked for consistency so don't move it away from here. - */ -#define KICKEDMSG "You have been kicked out of this room." - -void allwrite(char *cmdbuf, int flag, char *username) -{ - FILE *fp; - char bcast[SIZ]; - char *un; - struct ChatLine *clptr, *clnew; - time_t now; - - if (CC->fake_username[0]) - un = CC->fake_username; - else - un = CC->user.fullname; - if (flag == 1) { - snprintf(bcast, sizeof bcast, ":|<%s %s>", un, cmdbuf); - } else if (flag == 0) { - snprintf(bcast, sizeof bcast, "%s|%s", un, cmdbuf); - } else if (flag == 2) { - snprintf(bcast, sizeof bcast, ":|<%s whispers %s>", un, cmdbuf); - } else if (flag == 3) { - snprintf(bcast, sizeof bcast, ":|%s", KICKEDMSG); - } - if ((strcasecmp(cmdbuf, "NOOP")) && (flag != 2)) { - fp = fopen(CHATLOG, "a"); - if (fp != NULL) - fprintf(fp, "%s\n", bcast); - fclose(fp); - } - clnew = (struct ChatLine *) malloc(sizeof(struct ChatLine)); - memset(clnew, 0, sizeof(struct ChatLine)); - if (clnew == NULL) { - fprintf(stderr, "citserver: cannot alloc chat line: %s\n", - strerror(errno)); - return; - } - time(&now); - clnew->next = NULL; - clnew->chat_time = now; - safestrncpy(clnew->chat_room, CC->room.QRname, - sizeof clnew->chat_room); - clnew->chat_room[sizeof clnew->chat_room - 1] = 0; - if (username) { - safestrncpy(clnew->chat_username, username, - sizeof clnew->chat_username); - clnew->chat_username[sizeof clnew->chat_username - 1] = 0; - } else - clnew->chat_username[0] = '\0'; - safestrncpy(clnew->chat_text, bcast, sizeof clnew->chat_text); - - /* Here's the critical section. - * First, add the new message to the queue... - */ - begin_critical_section(S_CHATQUEUE); - ++ChatLastMsg; - clnew->chat_seq = ChatLastMsg; - if (ChatQueue == NULL) { - ChatQueue = clnew; - } else { - for (clptr = ChatQueue; clptr->next != NULL; clptr = clptr->next);; - clptr->next = clnew; - } - - /* Then, before releasing the lock, free the expired messages */ - while ((ChatQueue != NULL) && (now - ChatQueue->chat_time >= 120L)) { - clptr = ChatQueue; - ChatQueue = ChatQueue->next; - free(clptr); - } - end_critical_section(S_CHATQUEUE); -} - - -CitContext *find_context(char **unstr) -{ - CitContext *t_cc, *found_cc = NULL; - char *name, *tptr; - - if ((!*unstr) || (!unstr)) - return (NULL); - - begin_critical_section(S_SESSION_TABLE); - for (t_cc = ContextList; ((t_cc) && (!found_cc)); t_cc = t_cc->next) { - if (t_cc->fake_username[0]) - name = t_cc->fake_username; - else - name = t_cc->curr_user; - tptr = *unstr; - if ((!strncasecmp(name, tptr, strlen(name))) && (tptr[strlen(name)] == ' ')) { - found_cc = t_cc; - *unstr = &(tptr[strlen(name) + 1]); - } - } - end_critical_section(S_SESSION_TABLE); - - return (found_cc); -} - -/* - * List users in chat. - * allflag == 0 = list users in chat - * 1 = list users in chat, followed by users not in chat - * 2 = display count only - */ - -void do_chat_listing(int allflag) -{ - struct CitContext *ccptr; - int count = 0; - int count_elsewhere = 0; - char roomname[ROOMNAMELEN]; - - if ((allflag == 0) || (allflag == 1)) - cprintf(":|\n:| Users currently in chat:\n"); - begin_critical_section(S_SESSION_TABLE); - for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { - if (ccptr->cs_flags & CS_CHAT) { - if (!strcasecmp(ccptr->room.QRname, - CC->room.QRname)) { - ++count; - } - else { - ++count_elsewhere; - } - } - - GenerateRoomDisplay(roomname, ccptr, CC); - if ((CC->user.axlevel < AxAideU) && (!IsEmptyStr(ccptr->fake_roomname))) { - strcpy(roomname, ccptr->fake_roomname); - } - - if ((ccptr->cs_flags & CS_CHAT) && ((ccptr->cs_flags & CS_STEALTH) == 0)) { - if ((allflag == 0) || (allflag == 1)) { - cprintf(":| %-25s <%s>:\n", - (ccptr->fake_username[0]) ? ccptr->fake_username : ccptr->curr_user, - roomname); - } - } - } - - if (allflag == 1) { - cprintf(":|\n:| Users not in chat:\n"); - for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { - - GenerateRoomDisplay(roomname, ccptr, CC); - if ((CC->user.axlevel < AxAideU) - && (!IsEmptyStr(ccptr->fake_roomname))) { - strcpy(roomname, ccptr->fake_roomname); - } - - if (((ccptr->cs_flags & CS_CHAT) == 0) - && ((ccptr->cs_flags & CS_STEALTH) == 0)) { - cprintf(":| %-25s <%s>:\n", - (ccptr->fake_username[0]) ? ccptr->fake_username : ccptr->curr_user, - roomname); - } - } - } - end_critical_section(S_SESSION_TABLE); - - if (allflag == 2) { - if (count > 1) { - cprintf(":|There are %d users here.\n", count); - } - else { - cprintf(":|Note: you are the only one here.\n"); - } - if (count_elsewhere > 0) { - cprintf(":|There are %d users chatting in other rooms.\n", count_elsewhere); - } - } - - cprintf(":|\n"); -} - - -void cmd_chat(char *argbuf) -{ - /* FIXME chat has been broken by the underlying buffered I/O layer */ - cprintf("%d Chat is currently disabled at this site.\n", ERROR); - return; - -#if 0 - char cmdbuf[SIZ]; - char *un; - char *strptr1; - int MyLastMsg, ThisLastMsg; - struct ChatLine *clptr; - struct CitContext *t_context; - int retval; - CitContext *CCC = CC; - - if (!(CCC->logged_in)) { - cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN); - return; - } - - CCC->cs_flags = CCC->cs_flags | CS_CHAT; - cprintf("%d Entering chat mode (type '/help' for available commands)\n", - START_CHAT_MODE); - unbuffer_output(); - - MyLastMsg = ChatLastMsg; - - if ((CCC->cs_flags & CS_STEALTH) == 0) { - allwrite("", 0, NULL); - } - strcpy(cmdbuf, ""); - - do_chat_listing(2); - - while (1) { - int ok_cmd; - int linelen; - - ok_cmd = 0; - linelen = strlen(cmdbuf); - if (linelen > 100) --linelen; /* truncate too-long lines */ - cmdbuf[linelen + 1] = 0; - - retval = client_read_to(&cmdbuf[linelen], 1, 2); - - if (retval < 0 || CCC->kill_me) { /* socket broken? */ - if ((CCC->cs_flags & CS_STEALTH) == 0) { - allwrite("", 0, NULL); - } - return; - } - - /* if we have a complete line, do send processing */ - if (!IsEmptyStr(cmdbuf)) - if (cmdbuf[strlen(cmdbuf) - 1] == 10) { - cmdbuf[strlen(cmdbuf) - 1] = 0; - time(&CCC->lastcmd); - time(&CCC->lastidle); - - if ((!strcasecmp(cmdbuf, "exit")) - || (!strcasecmp(cmdbuf, "/exit")) - || (!strcasecmp(cmdbuf, "quit")) - || (!strcasecmp(cmdbuf, "logout")) - || (!strcasecmp(cmdbuf, "logoff")) - || (!strcasecmp(cmdbuf, "/q")) - || (!strcasecmp(cmdbuf, ".q")) - || (!strcasecmp(cmdbuf, "/quit")) - ) - strcpy(cmdbuf, "000"); - - if (!strcmp(cmdbuf, "000")) { - if ((CCC->cs_flags & CS_STEALTH) == 0) { - allwrite("", 0, NULL); - } - sleep(1); - cprintf("000\n"); - CCC->cs_flags = CCC->cs_flags - CS_CHAT; - return; - } - if ((!strcasecmp(cmdbuf, "/help")) - || (!strcasecmp(cmdbuf, "help")) - || (!strcasecmp(cmdbuf, "/?")) - || (!strcasecmp(cmdbuf, "?"))) { - cprintf(":|\n"); - cprintf(":|Available commands: \n"); - cprintf(":|/help (prints this message) \n"); - cprintf(":|/who (list users currently in chat) \n"); - cprintf(":|/whobbs (list users in chat -and- elsewhere) \n"); - cprintf(":|/me ('action' line, ala irc) \n"); - cprintf(":|/msg (send private message, ala irc) \n"); - if (is_room_aide()) { - cprintf(":|/kick (kick another user out of this room) \n"); - } - cprintf(":|/quit (exit from this chat) \n"); - cprintf(":|\n"); - ok_cmd = 1; - } - if (!strcasecmp(cmdbuf, "/who")) { - do_chat_listing(0); - ok_cmd = 1; - } - if (!strcasecmp(cmdbuf, "/whobbs")) { - do_chat_listing(1); - ok_cmd = 1; - } - if (!strncasecmp(cmdbuf, "/me ", 4)) { - allwrite(&cmdbuf[4], 1, NULL); - ok_cmd = 1; - } - if (!strncasecmp(cmdbuf, "/msg ", 5)) { - ok_cmd = 1; - strptr1 = &cmdbuf[5]; - if ((t_context = find_context(&strptr1))) { - allwrite(strptr1, 2, CCC->curr_user); - if (strcasecmp(CCC->curr_user, t_context->curr_user)) - allwrite(strptr1, 2, t_context->curr_user); - } else - cprintf(":|User not found.\n"); - cprintf("\n"); - } - /* The /kick function is implemented by sending a specific - * message to the kicked-out user's context. When that message - * is processed by the read loop, that context will exit. - */ - if ( (!strncasecmp(cmdbuf, "/kick ", 6)) && (is_room_aide()) ) { - ok_cmd = 1; - strptr1 = &cmdbuf[6]; - strcat(strptr1, " "); - if ((t_context = find_context(&strptr1))) { - if (strcasecmp(CCC->curr_user, t_context->curr_user)) - allwrite(strptr1, 3, t_context->curr_user); - } else - cprintf(":|User not found.\n"); - cprintf("\n"); - } - if ((cmdbuf[0] != '/') && (strlen(cmdbuf) > 0)) { - ok_cmd = 1; - allwrite(cmdbuf, 0, NULL); - } - if ((!ok_cmd) && (cmdbuf[0]) && (cmdbuf[0] != '\n')) - cprintf(":|Command %s is not understood.\n", cmdbuf); - - strcpy(cmdbuf, ""); - - } - /* now check the queue for new incoming stuff */ - - if (CCC->fake_username[0]) - un = CCC->fake_username; - else - un = CCC->curr_user; - if (ChatLastMsg > MyLastMsg) { - ThisLastMsg = ChatLastMsg; - for (clptr = ChatQueue; clptr != NULL; clptr = clptr->next) { - if ((clptr->chat_seq > MyLastMsg) && ((!clptr->chat_username[0]) || (!strncasecmp(un, clptr->chat_username, 32)))) { - if ((!clptr->chat_room[0]) || (!strncasecmp(CCC->room.QRname, clptr->chat_room, ROOMNAMELEN))) { - /* Output new chat data */ - cprintf("%s\n", clptr->chat_text); - - /* See if we've been force-quitted (kicked etc.) */ - if (!strcmp(&clptr->chat_text[2], KICKEDMSG)) { - allwrite("", 0, NULL); - cprintf("000\n"); - CCC->cs_flags = CCC->cs_flags - CS_CHAT; - - /* Kick user out of room */ - CtdlInvtKick(CCC->user.fullname, 0); - - /* And return to the Lobby */ - CtdlUserGoto(config.c_baseroom, 0, 0, NULL, NULL); - return; - } - } - } - } - MyLastMsg = ThisLastMsg; - } - } -#endif -} - - /* * Delete any remaining instant messages @@ -935,19 +558,18 @@ void flush_conversations_to_disk(time_t if_older_than) { -void chat_timer(void) { +void instmsg_timer(void) { flush_conversations_to_disk(300); /* Anything that hasn't peeped in more than 5 minutes */ } -void chat_shutdown(void) { +void instmsg_shutdown(void) { flush_conversations_to_disk(0); /* Get it ALL onto disk NOW. */ } -CTDL_MODULE_INIT(chat) +CTDL_MODULE_INIT(instmsg) { if (!threading) { - CtdlRegisterProtoHook(cmd_chat, "CHAT", "Begin real-time chat"); CtdlRegisterProtoHook(cmd_gexp, "GEXP", "Get instant messages"); CtdlRegisterProtoHook(cmd_sexp, "SEXP", "Send an instant message"); CtdlRegisterProtoHook(cmd_dexp, "DEXP", "Disable instant messages"); @@ -955,8 +577,8 @@ CTDL_MODULE_INIT(chat) CtdlRegisterSessionHook(cmd_gexp_async, EVT_ASYNC); CtdlRegisterSessionHook(delete_instant_messages, EVT_STOP); CtdlRegisterXmsgHook(send_instant_message, XMSG_PRI_LOCAL); - CtdlRegisterSessionHook(chat_timer, EVT_TIMER); - CtdlRegisterSessionHook(chat_shutdown, EVT_SHUTDOWN); + CtdlRegisterSessionHook(instmsg_timer, EVT_TIMER); + CtdlRegisterSessionHook(instmsg_shutdown, EVT_SHUTDOWN); } /* return our Subversion id for the Log */ diff --git a/citadel/modules/chat/serv_chat.h b/citadel/modules/instmsg/serv_instmsg.h similarity index 84% rename from citadel/modules/chat/serv_chat.h rename to citadel/modules/instmsg/serv_instmsg.h index 6ceba2682..9f2bc9d8b 100644 --- a/citadel/modules/chat/serv_chat.h +++ b/citadel/modules/instmsg/serv_instmsg.h @@ -4,8 +4,6 @@ void ChatUnloadingTest(void); void allwrite (char *cmdbuf, int flag, char *username); CitContext *find_context (char **unstr); -void do_chat_listing (int allflag); -void cmd_chat (char *argbuf); void cmd_pexp (char *argbuf); /* arg unused */ void cmd_sexp (char *argbuf); void delete_instant_messages(void); diff --git a/citadel/modules/roomchat/serv_roomchat.c b/citadel/modules/roomchat/serv_roomchat.c new file mode 100644 index 000000000..c1a08c566 --- /dev/null +++ b/citadel/modules/roomchat/serv_roomchat.c @@ -0,0 +1,243 @@ +/* + * $Id$ + * + * This module handles instant messaging between users. + * + * Copyright (c) 2010 by the citadel.org team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "sysdep.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include +#include +#include +#include "citadel.h" +#include "server.h" +#include "citserver.h" +#include "support.h" +#include "config.h" +#include "msgbase.h" +#include "user_ops.h" + +#ifndef HAVE_SNPRINTF +#include "snprintf.h" +#endif + +#include "ctdl_module.h" + + +struct chatmsg { + struct chatmsg *next; + time_t timestamp; + int seq; + long roomnum; + char *sender; + char *msgtext; +}; + +struct chatmsg *first_chat_msg = NULL; +struct chatmsg *last_chat_msg = NULL; + + +/* + * Periodically called for housekeeping. Expire old chat messages so they don't take up memory forever. + */ +void roomchat_timer(void) { + struct chatmsg *ptr; + + begin_critical_section(S_CHATQUEUE); + + while ((first_chat_msg != NULL) && ((time(NULL) - first_chat_msg->timestamp) > 300)) { + ptr = first_chat_msg->next; + free(first_chat_msg->sender); + free(first_chat_msg->msgtext); + free(first_chat_msg); + first_chat_msg = ptr; + if (first_chat_msg == NULL) { + last_chat_msg = NULL; + } + } + + end_critical_section(S_CHATQUEUE); +} + + +/* + * Perform shutdown-related activities... + */ +void roomchat_shutdown(void) { + /* if we ever start logging chats, we have to flush them to disk here .*/ +} + + +/* + * Add a message into the chat queue + */ +void add_to_chat_queue(char *msg) { + static int seq = 0; + + struct chatmsg *m = malloc(sizeof(struct chatmsg)); + if (!m) return; + + m->next = NULL; + m->timestamp = time(NULL); + m->roomnum = CC->room.QRnumber; + m->sender = strdup(CC->user.fullname); + m->msgtext = strdup(msg); + + if ((m->sender == NULL) || (m->msgtext == NULL)) { + free(m->sender); + free(m->msgtext); + free(m); + return; + } + + begin_critical_section(S_CHATQUEUE); + m->seq = ++seq; + + if (first_chat_msg == NULL) { + assert(last_chat_msg == NULL); + first_chat_msg = m; + last_chat_msg = m; + } + else { + assert(last_chat_msg != NULL); + assert(last_chat_msg->next == NULL); + last_chat_msg->next = m; + last_chat_msg = m; + } + + end_critical_section(S_CHATQUEUE); +} + + +/* + * Transmit a message into a room chat + */ +void roomchat_send(char *argbuf) { + char buf[1024]; + + if ((CC->cs_flags & CS_CHAT) == 0) { + cprintf("%d Session is not in chat mode.\n", ERROR); + return; + } + + cprintf("%d send now\n", SEND_LISTING); + while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) { + add_to_chat_queue(buf); + } +} + + +/* + * Poll room for incoming chat messages + */ +void roomchat_poll(char *argbuf) { + int newer_than = 0; + struct chatmsg *found = NULL; + struct chatmsg *ptr = NULL; + + newer_than = extract_int(argbuf, 1); + + if (!CC->cs_flags & CS_CHAT) { + cprintf("%d Session is not in chat mode.\n", ERROR); + return; + } + + begin_critical_section(S_CHATQUEUE); + for (ptr = first_chat_msg; ((ptr != NULL) && (found == NULL)); ptr = ptr->next) { + if ((ptr->seq > newer_than) && (ptr->roomnum == CC->room.QRnumber)) { + found = ptr; + } + } + end_critical_section(S_CHATQUEUE); + + if (found == NULL) { + cprintf("%d no messages\n", ERROR + MESSAGE_NOT_FOUND); + return; + } + + cprintf("%d %d|%ld|%s\n", LISTING_FOLLOWS, found->seq, found->timestamp, found->sender); + cprintf("%s\n", found->msgtext); + cprintf("000\n"); +} + + +/* + * Participate in real time chat in a room + */ +void cmd_rcht(char *argbuf) +{ + char subcmd[16]; + + if (CtdlAccessCheck(ac_logged_in)) return; + + extract_token(subcmd, argbuf, 0, '|', sizeof subcmd); + + if (!strcasecmp(subcmd, "enter")) { + CC->cs_flags |= CS_CHAT; + cprintf("%d Entering chat mode.\n", CIT_OK); + } + else if (!strcasecmp(subcmd, "exit")) { + CC->cs_flags &= ~CS_CHAT; + cprintf("%d Exiting chat mode.\n", CIT_OK); + } + else if (!strcasecmp(subcmd, "send")) { + roomchat_send(argbuf); + } + else if (!strcasecmp(subcmd, "poll")) { + roomchat_poll(argbuf); + } + else { + cprintf("%d Invalid subcommand\n", ERROR + CMD_NOT_SUPPORTED); + } +} + + +CTDL_MODULE_INIT(roomchat) +{ + if (!threading) + { + CtdlRegisterProtoHook(cmd_rcht, "RCHT", "Participate in real time chat in a room"); + CtdlRegisterSessionHook(roomchat_timer, EVT_TIMER); + CtdlRegisterSessionHook(roomchat_shutdown, EVT_SHUTDOWN); + } + + /* return our Subversion id for the Log */ + return "$Id$"; +} diff --git a/citadel/server.h b/citadel/server.h index d8161faea..d5755f0a6 100644 --- a/citadel/server.h +++ b/citadel/server.h @@ -84,15 +84,6 @@ struct ExpressMessage { #define EM_GO_AWAY 2 /* Server requests client log off */ #define EM_CHAT 4 /* Server requests client enter chat */ -struct ChatLine { - struct ChatLine *next; - int chat_seq; - time_t chat_time; - char chat_text[SIZ]; - char chat_username[USERNAME_SIZE]; - char chat_room[ROOMNAMELEN]; -}; - /* * Various things we need to lock and unlock */ diff --git a/citadel/textclient/client_chat.c b/citadel/textclient/client_chat.c index c86914f02..590d8b4c9 100644 --- a/citadel/textclient/client_chat.c +++ b/citadel/textclient/client_chat.c @@ -4,21 +4,21 @@ * front end for chat mode * (the "single process" version - no more fork() anymore) * - * Copyright (c) 1987-2009 by the citadel.org team + * Copyright (c) 1987-2010 by the citadel.org team * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sysdep.h" @@ -66,36 +66,33 @@ extern char temp[]; void ctdl_getline(char *, int); + char last_paged[SIZ] = ""; void chatmode(CtdlIPC *ipc) { char wbuf[SIZ]; char buf[SIZ]; + char response[SIZ]; char c_user[SIZ]; char c_text[SIZ]; - char c_room[SIZ]; char last_user[SIZ]; int send_complete_line; - int recv_complete_line; char ch; int a, pos; - time_t last_transmit; + int seq = 0; fd_set rfds; struct timeval tv; int retval; - CtdlIPC_chat_send(ipc, "CHAT"); + CtdlIPC_chat_send(ipc, "RCHT enter"); CtdlIPC_chat_recv(ipc, buf); - if (buf[0] != '8') { + if (buf[0] != '2') { scr_printf("%s\n", &buf[4]); return; } - scr_printf("Entering chat mode " - "(type /quit to exit, /help for other cmds)\n"); - set_keepalives(KA_NO); - last_transmit = time(NULL); + scr_printf("Entering chat mode (type /quit to exit)\n"); strcpy(buf, ""); strcpy(wbuf, ""); @@ -104,24 +101,14 @@ void chatmode(CtdlIPC *ipc) sln_printf_if("\n"); sln_printf("> "); send_complete_line = 0; - recv_complete_line = 0; while (1) { sln_flush(); FD_ZERO(&rfds); FD_SET(0, &rfds); - FD_SET(CtdlIPC_getsockfd(ipc), &rfds); - tv.tv_sec = S_KEEPALIVE; + tv.tv_sec = 1; tv.tv_usec = 0; - retval = select(CtdlIPC_getsockfd(ipc) + 1, &rfds, - NULL, NULL, &tv); - - /* If there's data from the server... */ - if (FD_ISSET(CtdlIPC_getsockfd(ipc), &rfds)) { - CtdlIPC_chat_recv(ipc, buf); - recv_complete_line = 1; - goto RCL; /* ugly, but we've gotta get out! */ - } + retval = select(1, &rfds, NULL, NULL, &tv); /* If there's data from the keyboard... */ if (FD_ISSET(0, &rfds)) { @@ -141,9 +128,23 @@ void chatmode(CtdlIPC *ipc) } /* if the user hit return, send the line */ -RCL: if (send_complete_line) { - CtdlIPC_chat_send(ipc, wbuf); - last_transmit = time(NULL); + if (send_complete_line) { + + if (!strcasecmp(wbuf, "/quit")) { + CtdlIPC_chat_send(ipc, "RCHT exit"); + CtdlIPC_chat_recv(ipc, response); /* don't care about the result */ + color(BRIGHT_WHITE); + sln_printf("\rExiting chat mode\n"); + sln_flush(); + return; + } + + CtdlIPC_chat_send(ipc, "RCHT send"); + CtdlIPC_chat_recv(ipc, response); + if (response[0] == '4') { + CtdlIPC_chat_send(ipc, wbuf); + CtdlIPC_chat_send(ipc, "000"); + } strcpy(wbuf, ""); send_complete_line = 0; } @@ -156,90 +157,69 @@ RCL: if (send_complete_line) { pos = a; } if (pos == 0) { - CtdlIPC_chat_send(ipc, wbuf); - last_transmit = time(NULL); + CtdlIPC_chat_send(ipc, "RCHT send"); + CtdlIPC_chat_recv(ipc, response); + if (response[0] == '4') { + CtdlIPC_chat_send(ipc, wbuf); + CtdlIPC_chat_send(ipc, "000"); + } strcpy(wbuf, ""); send_complete_line = 0; } else { wbuf[pos] = 0; - CtdlIPC_chat_send(ipc, wbuf); - last_transmit = time(NULL); + CtdlIPC_chat_send(ipc, "RCHT send"); + CtdlIPC_chat_recv(ipc, response); + if (response[0] == '4') { + CtdlIPC_chat_send(ipc, wbuf); + CtdlIPC_chat_send(ipc, "000"); + } strcpy(wbuf, &wbuf[pos + 1]); } } - if (recv_complete_line) { - sln_printf("\r%79s\r", ""); - if (!strcmp(buf, "000")) { - color(BRIGHT_WHITE); - sln_printf("\rExiting chat mode\n"); - sln_flush(); - set_keepalives(KA_YES); - - /* Some users complained about the client and - * server losing protocol synchronization when - * exiting chat. This little dialog forces - * everything to be hunky-dory. - */ - CtdlIPC_chat_send(ipc, "ECHO __ExitingChat__"); - do { - CtdlIPC_chat_recv(ipc, buf); - } while (strcmp(buf, "200 __ExitingChat__")); - return; - } - if (num_parms(buf) >= 2) { - extract_token(c_user, buf, 0, '|', sizeof c_user); - extract_token(c_text, buf, 1, '|', sizeof c_text); - if (num_parms(buf) > 2) { - extract_token(c_room, buf, 2, '|', sizeof c_room); - scr_printf("Got room %s\n", c_room); + /* poll for incoming chat messages */ + snprintf(buf, sizeof buf, "RCHT poll|%d", seq); + CtdlIPC_chat_send(ipc, buf); + CtdlIPC_chat_recv(ipc, response); + + if (response[0] == '1') { + seq = extract_int(&response[4], 0); + extract_token(c_user, &response[4], 2, '|', sizeof c_user); + while (CtdlIPC_chat_recv(ipc, c_text), strcmp(c_text, "000")) { + sln_printf("\r%79s\r", ""); + if (!strcmp(c_user, fullname)) { + color(BRIGHT_YELLOW); + } else if (!strcmp(c_user, ":")) { + color(BRIGHT_RED); + } else { + color(BRIGHT_GREEN); } - if (strcasecmp(c_text, "NOOP")) { - if (!strcmp(c_user, fullname)) { - color(BRIGHT_YELLOW); - } else if (!strcmp(c_user, ":")) { - color(BRIGHT_RED); - } else { - color(BRIGHT_GREEN); - } - if (strcmp(c_user, last_user)) { - snprintf(buf, sizeof buf, "%s: %s", c_user, c_text); - } else { - size_t i = MIN(sizeof buf - 1, - strlen(c_user) + 2); - - memset(buf, ' ', i); - safestrncpy(&buf[i], c_text, - sizeof buf - i); - } - while (strlen(buf) < 79) - strcat(buf, " "); - if (strcmp(c_user, last_user)) { - sln_printf("\r%79s\n", ""); - strcpy(last_user, c_user); - } - scr_printf("\r%s\n", buf); - scr_flush(); + if (strcmp(c_user, last_user)) { + snprintf(buf, sizeof buf, "%s: %s", c_user, c_text); + } else { + size_t i = MIN(sizeof buf - 1, strlen(c_user) + 2); + memset(buf, ' ', i); + safestrncpy(&buf[i], c_text, sizeof buf - i); } + while (strlen(buf) < 79) { + strcat(buf, " "); + } + if (strcmp(c_user, last_user)) { + sln_printf("\r%79s\n", ""); + strcpy(last_user, c_user); + } + scr_printf("\r%s\n", buf); + scr_flush(); } - color(BRIGHT_YELLOW); - sln_printf("\r> %s", wbuf); - sln_flush(); - recv_complete_line = 0; - strcpy(buf, ""); - } - - /* If the user is sitting idle, send a half-keepalive to the - * server to prevent session timeout. - */ - if ((time(NULL) - last_transmit) >= S_KEEPALIVE) { - CtdlIPC_chat_send(ipc, "NOOP"); - last_transmit = time(NULL); } - + color(BRIGHT_YELLOW); + sln_printf("\r> %s", wbuf); + sln_flush(); + strcpy(buf, ""); } } + /* * send an instant message */ -- 2.30.2