2 * This module handles instant messaging between users.
4 * Copyright (c) 2010 by the citadel.org team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <sys/types.h>
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
37 # include <sys/time.h>
46 #include <libcitadel.h>
49 #include "citserver.h"
59 #include "ctdl_module.h"
71 struct chatmsg *first_chat_msg = NULL;
72 struct chatmsg *last_chat_msg = NULL;
76 * Periodically called for housekeeping. Expire old chat messages so they don't take up memory forever.
78 void roomchat_timer(void) {
81 begin_critical_section(S_CHATQUEUE);
83 while ((first_chat_msg != NULL) && ((time(NULL) - first_chat_msg->timestamp) > 300)) {
84 ptr = first_chat_msg->next;
85 free(first_chat_msg->sender);
86 free(first_chat_msg->msgtext);
89 if (first_chat_msg == NULL) {
94 end_critical_section(S_CHATQUEUE);
99 * Perform shutdown-related activities...
101 void roomchat_shutdown(void) {
102 /* if we ever start logging chats, we have to flush them to disk here .*/
107 * Add a message into the chat queue
109 void add_to_chat_queue(char *msg) {
112 struct chatmsg *m = malloc(sizeof(struct chatmsg));
116 m->timestamp = time(NULL);
117 m->roomnum = CC->room.QRnumber;
118 m->sender = strdup(CC->user.fullname);
119 m->msgtext = strdup(msg);
121 if ((m->sender == NULL) || (m->msgtext == NULL)) {
128 begin_critical_section(S_CHATQUEUE);
131 if (first_chat_msg == NULL) {
132 assert(last_chat_msg == NULL);
137 assert(last_chat_msg != NULL);
138 assert(last_chat_msg->next == NULL);
139 last_chat_msg->next = m;
143 end_critical_section(S_CHATQUEUE);
148 * Transmit a message into a room chat
150 void roomchat_send(char *argbuf) {
153 if ((CC->cs_flags & CS_CHAT) == 0) {
154 cprintf("%d Session is not in chat mode.\n", ERROR);
158 cprintf("%d send now\n", SEND_LISTING);
159 while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
160 add_to_chat_queue(buf);
166 * Poll room for incoming chat messages
168 void roomchat_poll(char *argbuf) {
170 struct chatmsg *found = NULL;
171 struct chatmsg *ptr = NULL;
173 newer_than = extract_int(argbuf, 1);
175 if ((CC->cs_flags & CS_CHAT) == 0) {
176 cprintf("%d Session is not in chat mode.\n", ERROR);
180 begin_critical_section(S_CHATQUEUE);
181 for (ptr = first_chat_msg; ((ptr != NULL) && (found == NULL)); ptr = ptr->next) {
182 if ((ptr->seq > newer_than) && (ptr->roomnum == CC->room.QRnumber)) {
186 end_critical_section(S_CHATQUEUE);
189 cprintf("%d no messages\n", ERROR + MESSAGE_NOT_FOUND);
193 cprintf("%d %d|%ld|%s\n", LISTING_FOLLOWS, found->seq, found->timestamp, found->sender);
194 cprintf("%s\n", found->msgtext);
201 * list users in chat in this room
203 void roomchat_rwho(char *argbuf) {
204 struct CitContext *nptr;
207 if ((CC->cs_flags & CS_CHAT) == 0) {
208 cprintf("%d Session is not in chat mode.\n", ERROR);
212 cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
214 nptr = CtdlGetContextArray(&nContexts) ; // grab a copy of the wholist
216 for (i=0; i<nContexts; i++) { // list the users
217 if ( (nptr[i].room.QRnumber == CC->room.QRnumber)
218 && (nptr[i].cs_flags & CS_CHAT)
220 cprintf("%s\n", nptr[i].user.fullname);
223 free(nptr); // free our copy
232 * Participate in real time chat in a room
234 void cmd_rcht(char *argbuf)
238 if (CtdlAccessCheck(ac_logged_in)) return;
240 extract_token(subcmd, argbuf, 0, '|', sizeof subcmd);
242 if (!strcasecmp(subcmd, "enter")) {
243 CC->cs_flags |= CS_CHAT;
244 cprintf("%d Entering chat mode.\n", CIT_OK);
246 else if (!strcasecmp(subcmd, "exit")) {
247 CC->cs_flags &= ~CS_CHAT;
248 cprintf("%d Exiting chat mode.\n", CIT_OK);
250 else if (!strcasecmp(subcmd, "send")) {
251 roomchat_send(argbuf);
253 else if (!strcasecmp(subcmd, "poll")) {
254 roomchat_poll(argbuf);
256 else if (!strcasecmp(subcmd, "rwho")) {
257 roomchat_rwho(argbuf);
260 cprintf("%d Invalid subcommand\n", ERROR + CMD_NOT_SUPPORTED);
265 CTDL_MODULE_INIT(roomchat)
269 CtdlRegisterProtoHook(cmd_rcht, "RCHT", "Participate in real time chat in a room");
270 CtdlRegisterSessionHook(roomchat_timer, EVT_TIMER);
271 CtdlRegisterSessionHook(roomchat_shutdown, EVT_SHUTDOWN);
274 /* return our Subversion id for the Log */