2 * This module handles instant messaging between users.
4 * Copyright (c) 2012 by the citadel.org team
6 * This program is open source software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
22 #include <sys/types.h>
25 #if TIME_WITH_SYS_TIME
26 # include <sys/time.h>
30 # include <sys/time.h>
39 #include <libcitadel.h>
42 #include "citserver.h"
47 #include "ctdl_module.h"
58 struct chatmsg *first_chat_msg = NULL;
59 struct chatmsg *last_chat_msg = NULL;
63 * Periodically called for housekeeping. Expire old chat messages so they don't take up memory forever.
65 void roomchat_timer(void) {
68 begin_critical_section(S_CHATQUEUE);
70 while ((first_chat_msg != NULL) && ((time(NULL) - first_chat_msg->timestamp) > 300)) {
71 ptr = first_chat_msg->next;
72 free(first_chat_msg->sender);
73 free(first_chat_msg->msgtext);
76 if (first_chat_msg == NULL) {
81 end_critical_section(S_CHATQUEUE);
86 * Perform shutdown-related activities...
88 void roomchat_shutdown(void) {
89 /* if we ever start logging chats, we have to flush them to disk here .*/
94 * Add a message into the chat queue
96 void add_to_chat_queue(char *msg) {
99 struct chatmsg *m = malloc(sizeof(struct chatmsg));
103 m->timestamp = time(NULL);
104 m->roomnum = CC->room.QRnumber;
105 m->sender = strdup(CC->user.fullname);
106 m->msgtext = strdup(msg);
108 if ((m->sender == NULL) || (m->msgtext == NULL)) {
115 begin_critical_section(S_CHATQUEUE);
118 if (first_chat_msg == NULL) {
119 assert(last_chat_msg == NULL);
124 assert(last_chat_msg != NULL);
125 assert(last_chat_msg->next == NULL);
126 last_chat_msg->next = m;
130 end_critical_section(S_CHATQUEUE);
135 * Transmit a message into a room chat
137 void roomchat_send(char *argbuf) {
140 if ((CC->cs_flags & CS_CHAT) == 0) {
141 cprintf("%d Session is not in chat mode.\n", ERROR);
145 cprintf("%d send now\n", SEND_LISTING);
146 while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
147 add_to_chat_queue(buf);
153 * Poll room for incoming chat messages
155 void roomchat_poll(char *argbuf) {
157 struct chatmsg *found = NULL;
158 struct chatmsg *ptr = NULL;
160 newer_than = extract_int(argbuf, 1);
162 if ((CC->cs_flags & CS_CHAT) == 0) {
163 cprintf("%d Session is not in chat mode.\n", ERROR);
167 begin_critical_section(S_CHATQUEUE);
168 for (ptr = first_chat_msg; ((ptr != NULL) && (found == NULL)); ptr = ptr->next) {
169 if ((ptr->seq > newer_than) && (ptr->roomnum == CC->room.QRnumber)) {
173 end_critical_section(S_CHATQUEUE);
176 cprintf("%d no messages\n", ERROR + MESSAGE_NOT_FOUND);
180 cprintf("%d %d|%ld|%s\n", LISTING_FOLLOWS, found->seq, found->timestamp, found->sender);
181 cprintf("%s\n", found->msgtext);
188 * list users in chat in this room
190 void roomchat_rwho(char *argbuf) {
191 struct CitContext *nptr;
194 if ((CC->cs_flags & CS_CHAT) == 0) {
195 cprintf("%d Session is not in chat mode.\n", ERROR);
199 cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
201 nptr = CtdlGetContextArray(&nContexts) ; // grab a copy of the wholist
203 for (i=0; i<nContexts; i++) { // list the users
204 if ( (nptr[i].room.QRnumber == CC->room.QRnumber)
205 && (nptr[i].cs_flags & CS_CHAT)
207 cprintf("%s\n", nptr[i].user.fullname);
210 free(nptr); // free our copy
219 * Participate in real time chat in a room
221 void cmd_rcht(char *argbuf)
225 if (CtdlAccessCheck(ac_logged_in)) return;
227 extract_token(subcmd, argbuf, 0, '|', sizeof subcmd);
229 if (!strcasecmp(subcmd, "enter")) {
230 CC->cs_flags |= CS_CHAT;
231 cprintf("%d Entering chat mode.\n", CIT_OK);
233 else if (!strcasecmp(subcmd, "exit")) {
234 CC->cs_flags &= ~CS_CHAT;
235 cprintf("%d Exiting chat mode.\n", CIT_OK);
237 else if (!strcasecmp(subcmd, "send")) {
238 roomchat_send(argbuf);
240 else if (!strcasecmp(subcmd, "poll")) {
241 roomchat_poll(argbuf);
243 else if (!strcasecmp(subcmd, "rwho")) {
244 roomchat_rwho(argbuf);
247 cprintf("%d Invalid subcommand\n", ERROR + CMD_NOT_SUPPORTED);
252 CTDL_MODULE_INIT(roomchat)
256 CtdlRegisterProtoHook(cmd_rcht, "RCHT", "Participate in real time chat in a room");
257 CtdlRegisterSessionHook(roomchat_timer, EVT_TIMER, PRIO_CLEANUP + 400);
258 CtdlRegisterSessionHook(roomchat_shutdown, EVT_SHUTDOWN, PRIO_SHUTDOWN + 55);
261 /* return our module name for the log */