4 * This module handles instant messaging between users.
6 * Copyright (c) 2010 by the citadel.org team
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <sys/types.h>
34 #if TIME_WITH_SYS_TIME
35 # include <sys/time.h>
39 # include <sys/time.h>
48 #include <libcitadel.h>
51 #include "citserver.h"
61 #include "ctdl_module.h"
73 struct chatmsg *first_chat_msg = NULL;
74 struct chatmsg *last_chat_msg = NULL;
78 * Periodically called for housekeeping. Expire old chat messages so they don't take up memory forever.
80 void roomchat_timer(void) {
83 begin_critical_section(S_CHATQUEUE);
85 while ((first_chat_msg != NULL) && ((time(NULL) - first_chat_msg->timestamp) > 300)) {
86 ptr = first_chat_msg->next;
87 free(first_chat_msg->sender);
88 free(first_chat_msg->msgtext);
91 if (first_chat_msg == NULL) {
96 end_critical_section(S_CHATQUEUE);
101 * Perform shutdown-related activities...
103 void roomchat_shutdown(void) {
104 /* if we ever start logging chats, we have to flush them to disk here .*/
109 * Add a message into the chat queue
111 void add_to_chat_queue(char *msg) {
114 struct chatmsg *m = malloc(sizeof(struct chatmsg));
118 m->timestamp = time(NULL);
119 m->roomnum = CC->room.QRnumber;
120 m->sender = strdup(CC->user.fullname);
121 m->msgtext = strdup(msg);
123 if ((m->sender == NULL) || (m->msgtext == NULL)) {
130 begin_critical_section(S_CHATQUEUE);
133 if (first_chat_msg == NULL) {
134 assert(last_chat_msg == NULL);
139 assert(last_chat_msg != NULL);
140 assert(last_chat_msg->next == NULL);
141 last_chat_msg->next = m;
145 end_critical_section(S_CHATQUEUE);
150 * Transmit a message into a room chat
152 void roomchat_send(char *argbuf) {
155 if ((CC->cs_flags & CS_CHAT) == 0) {
156 cprintf("%d Session is not in chat mode.\n", ERROR);
160 cprintf("%d send now\n", SEND_LISTING);
161 while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
162 add_to_chat_queue(buf);
168 * Poll room for incoming chat messages
170 void roomchat_poll(char *argbuf) {
172 struct chatmsg *found = NULL;
173 struct chatmsg *ptr = NULL;
175 newer_than = extract_int(argbuf, 1);
177 if ((CC->cs_flags & CS_CHAT) == 0) {
178 cprintf("%d Session is not in chat mode.\n", ERROR);
182 begin_critical_section(S_CHATQUEUE);
183 for (ptr = first_chat_msg; ((ptr != NULL) && (found == NULL)); ptr = ptr->next) {
184 if ((ptr->seq > newer_than) && (ptr->roomnum == CC->room.QRnumber)) {
188 end_critical_section(S_CHATQUEUE);
191 cprintf("%d no messages\n", ERROR + MESSAGE_NOT_FOUND);
195 cprintf("%d %d|%ld|%s\n", LISTING_FOLLOWS, found->seq, found->timestamp, found->sender);
196 cprintf("%s\n", found->msgtext);
203 * list users in chat in this room
205 void roomchat_rwho(char *argbuf) {
206 struct CitContext *nptr;
209 if ((CC->cs_flags & CS_CHAT) == 0) {
210 cprintf("%d Session is not in chat mode.\n", ERROR);
214 cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
216 nptr = CtdlGetContextArray(&nContexts) ; // grab a copy of the wholist
218 for (i=0; i<nContexts; i++) { // list the users
219 if ( (nptr[i].room.QRnumber == CC->room.QRnumber)
220 && (nptr[i].cs_flags & CS_CHAT)
222 cprintf("%s\n", nptr[i].user.fullname);
225 free(nptr); // free our copy
234 * Participate in real time chat in a room
236 void cmd_rcht(char *argbuf)
240 if (CtdlAccessCheck(ac_logged_in)) return;
242 extract_token(subcmd, argbuf, 0, '|', sizeof subcmd);
244 if (!strcasecmp(subcmd, "enter")) {
245 CC->cs_flags |= CS_CHAT;
246 cprintf("%d Entering chat mode.\n", CIT_OK);
248 else if (!strcasecmp(subcmd, "exit")) {
249 CC->cs_flags &= ~CS_CHAT;
250 cprintf("%d Exiting chat mode.\n", CIT_OK);
252 else if (!strcasecmp(subcmd, "send")) {
253 roomchat_send(argbuf);
255 else if (!strcasecmp(subcmd, "poll")) {
256 roomchat_poll(argbuf);
258 else if (!strcasecmp(subcmd, "rwho")) {
259 roomchat_rwho(argbuf);
262 cprintf("%d Invalid subcommand\n", ERROR + CMD_NOT_SUPPORTED);
267 CTDL_MODULE_INIT(roomchat)
271 CtdlRegisterProtoHook(cmd_rcht, "RCHT", "Participate in real time chat in a room");
272 CtdlRegisterSessionHook(roomchat_timer, EVT_TIMER);
273 CtdlRegisterSessionHook(roomchat_shutdown, EVT_SHUTDOWN);
276 /* return our Subversion id for the Log */